Files
image-transcoder/main.go
2024-08-29 11:51:27 +02:00

141 lines
3.4 KiB
Go

package main
import (
"flag"
"fmt"
"image-transcoder/codec"
"io"
"log"
"os"
"path/filepath"
"strings"
"sync"
)
var codecs = map[string]codec.Coder{
".jpg": codec.JPGCoder{},
".jpeg": codec.JPGCoder{},
".png": codec.PNGCoder{},
".webp": codec.WebpCoder{},
}
var Error *log.Logger
var Warning *log.Logger
func init() {
log.SetFlags(log.Lmicroseconds | log.Lshortfile)
logger := io.MultiWriter(os.Stdout)
log.SetOutput(logger)
Error = log.New(io.MultiWriter(os.Stderr, os.Stdout),
fmt.Sprintf("%sERROR:%s ", "\033[0;101m", "\033[0m"),
log.Lmicroseconds|log.Lshortfile)
Warning = log.New(io.MultiWriter(os.Stdout),
fmt.Sprintf("%sWarning:%s ", "\033[0;93m", "\033[0m"),
log.Lmicroseconds|log.Lshortfile)
}
func main() {
quality := flag.Int("quality", 80, "Quality of the image")
to := flag.String("to", ".jpg", "Extension to transcode to")
nosafe := flag.Bool("nosafe", false, "Prevents backup of the original before encoding")
rm := flag.Bool("rm", false, "Removes the original after transcoding")
flag.Parse()
if _, ok := codecs[*to]; !ok {
Error.Println("Invalid extension")
return
}
log.Printf("Using quality: %d", *quality)
log.Printf("Transcoding to: %s", *to)
log.Printf("Nosafe mode: %v", *nosafe)
log.Printf("Remove mode: %v", *rm)
var wg sync.WaitGroup
for _, file := range flag.Args() {
wg.Add(1)
go func(file string) {
defer wg.Done()
file = filepath.ToSlash(file)
file = filepath.Clean(file)
ext := filepath.Ext(file)
coder, ok := codecs[ext]
if !ok {
Error.Printf("No encoder found for file: %s", file)
return
}
filedir := filepath.Dir(file)
filename := filepath.Base(file)
if !*nosafe {
bckp := filename + ".bak"
bckp = filepath.Join(filedir, bckp)
err := os.Link(file, bckp)
if err != nil {
Error.Printf("Failed to backup file: %v", err)
return
}
}
filehandle, err := os.Open(file)
if err != nil {
Error.Printf("Failed to open file: %v", err)
return
}
stat, err := filehandle.Stat()
if err != nil {
Error.Printf("Failed to get file stats: %v", err)
return
}
originalSize := stat.Size()
log.Printf("Decoding %s", file)
image, err := coder.Decode(filehandle)
if err != nil {
Error.Printf("Failed to decode file: %v", err)
return
}
filehandle.Close()
newfile := strings.Replace(filename, ext, *to, 1)
newfile = filepath.Join(filedir, newfile)
log.Printf("Encoding %s to %s", file, newfile)
buf, err := coder.Encode(image, *quality)
if err != nil {
Error.Printf("Failed to encode image: %v", err)
return
}
filehandle, err = os.Create(newfile)
if err != nil {
Error.Printf("Failed to create file %s: %v", newfile, err)
return
}
n, err := filehandle.Write(buf.Bytes())
if n != len(buf.Bytes()) || err != nil {
Error.Printf("Failed to write file %s: %v", newfile, err)
return
}
log.Printf("Wrote %dKB; Old size: %dKB; Compression: %.2f", n/1024, originalSize/1024, float32(n)/float32(originalSize))
if *rm {
if file == newfile {
log.Printf("Won't remove newfile %s", file)
return
}
log.Printf("Removing %s", file)
err = os.Remove(file)
if err != nil {
Error.Printf("Failed to remove file %v: %v", file, err)
return
}
}
}(file)
}
wg.Wait()
}