add webp conversion
This commit is contained in:
+207
@@ -0,0 +1,207 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/chai2010/webp"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// convertCmd represents the convert command
|
||||
var convertCmd = &cobra.Command{
|
||||
Use: "convert [input] [output]",
|
||||
Short: "Convert images between different formats",
|
||||
Long: `Convert images between different formats including JPG, PNG, and WebP.
|
||||
The output format is determined by the output file extension or the --format flag.
|
||||
|
||||
Examples:
|
||||
# Convert a single file
|
||||
dttt convert input.jpg output.webp
|
||||
|
||||
# Batch convert all images in a directory
|
||||
dttt convert ./input_dir ./output_dir --batch --format webp
|
||||
|
||||
# Batch convert with specific extensions and quality
|
||||
dttt convert ./photos ./webp_photos --batch --format webp --quality 85 --extensions jpg,png`,
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
isBatch, _ := cmd.Flags().GetBool("batch")
|
||||
quality, _ := cmd.Flags().GetInt("quality")
|
||||
format, _ := cmd.Flags().GetString("format")
|
||||
extensions, _ := cmd.Flags().GetString("extensions")
|
||||
|
||||
if isBatch {
|
||||
if len(args) != 2 {
|
||||
log.Fatal("Batch mode requires input and output directories")
|
||||
}
|
||||
|
||||
inputDir := args[0]
|
||||
outputDir := args[1]
|
||||
|
||||
if format == "" {
|
||||
log.Fatal("Batch mode requires specifying an output format with --format")
|
||||
}
|
||||
|
||||
batchConvert(inputDir, outputDir, format, extensions, quality)
|
||||
} else {
|
||||
if len(args) != 2 {
|
||||
log.Fatal("Single file mode requires input and output file paths")
|
||||
}
|
||||
|
||||
inputFile := args[0]
|
||||
outputFile := args[1]
|
||||
|
||||
convertImage(inputFile, outputFile, quality)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(convertCmd)
|
||||
|
||||
// Add flags
|
||||
convertCmd.Flags().IntP("quality", "q", 90, "Quality for lossy formats (1-100)")
|
||||
convertCmd.Flags().BoolP("batch", "b", false, "Enable batch conversion mode")
|
||||
convertCmd.Flags().StringP("format", "f", "", "Output format for batch conversion (jpg, jpeg, png, webp)")
|
||||
convertCmd.Flags().StringP("extensions", "e", "jpg,jpeg,png,webp", "Comma-separated list of file extensions to process in batch mode")
|
||||
}
|
||||
|
||||
func batchConvert(inputDir, outputDir, format, extensions string, quality int) {
|
||||
// Ensure output directory exists
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
log.Fatal("Failed to create output directory:", err)
|
||||
}
|
||||
|
||||
// Parse extensions
|
||||
validExts := strings.Split(extensions, ",")
|
||||
for i, ext := range validExts {
|
||||
validExts[i] = strings.ToLower(strings.TrimSpace(ext))
|
||||
if !strings.HasPrefix(validExts[i], ".") {
|
||||
validExts[i] = "." + validExts[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure format has a dot prefix and is lowercase
|
||||
format = strings.ToLower(format)
|
||||
if !strings.HasPrefix(format, ".") {
|
||||
format = "." + format
|
||||
}
|
||||
|
||||
// Get all files from input directory
|
||||
files, err := os.ReadDir(inputDir)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading input directory:", err)
|
||||
}
|
||||
|
||||
// Track conversion statistics
|
||||
successCount := 0
|
||||
errorCount := 0
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if file has a valid extension
|
||||
fileExt := strings.ToLower(filepath.Ext(file.Name()))
|
||||
isValidExt := false
|
||||
for _, ext := range validExts {
|
||||
if ext == fileExt {
|
||||
isValidExt = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isValidExt {
|
||||
continue
|
||||
}
|
||||
|
||||
// Generate input and output file paths
|
||||
inputPath := filepath.Join(inputDir, file.Name())
|
||||
baseName := strings.TrimSuffix(file.Name(), fileExt)
|
||||
outputPath := filepath.Join(outputDir, baseName+format)
|
||||
|
||||
// Convert the file
|
||||
err := convertImageWithError(inputPath, outputPath, quality)
|
||||
if err != nil {
|
||||
fmt.Printf("Error converting %s: %v\n", file.Name(), err)
|
||||
errorCount++
|
||||
} else {
|
||||
successCount++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Batch conversion complete: %d files converted successfully, %d failed\n", successCount, errorCount)
|
||||
}
|
||||
|
||||
func convertImageWithError(inputFile, outputFile string, quality int) error {
|
||||
// Open input file
|
||||
input, err := os.Open(inputFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening input file: %w", err)
|
||||
}
|
||||
defer input.Close()
|
||||
|
||||
// Decode input image
|
||||
img, format, err := image.Decode(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding input image: %w", err)
|
||||
}
|
||||
|
||||
// Create output file
|
||||
output, err := os.Create(outputFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating output file: %w", err)
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
// Determine output format based on file extension and encode
|
||||
outFormat := getOutputFormat(outputFile)
|
||||
|
||||
switch strings.ToLower(filepath.Ext(outputFile)) {
|
||||
case ".jpg", ".jpeg":
|
||||
err = jpeg.Encode(output, img, &jpeg.Options{Quality: quality})
|
||||
case ".png":
|
||||
err = png.Encode(output, img)
|
||||
case ".webp":
|
||||
err = webp.Encode(output, img, &webp.Options{Lossless: quality == 100, Quality: float32(quality)})
|
||||
default:
|
||||
return fmt.Errorf("unsupported output format: %s", filepath.Ext(outputFile))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error encoding output image: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Converted %s (%s) to %s\n", filepath.Base(inputFile), format, outFormat)
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertImage(inputFile, outputFile string, quality int) {
|
||||
err := convertImageWithError(inputFile, outputFile, quality)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("Image converted successfully!")
|
||||
}
|
||||
|
||||
func getOutputFormat(filename string) string {
|
||||
ext := strings.ToLower(filepath.Ext(filename))
|
||||
switch ext {
|
||||
case ".jpg", ".jpeg":
|
||||
return "JPEG"
|
||||
case ".png":
|
||||
return "PNG"
|
||||
case ".webp":
|
||||
return "WebP"
|
||||
default:
|
||||
return ext
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user