diff --git a/henshin/wand.go b/henshin/wand.go index 7667b95..30740dc 100644 --- a/henshin/wand.go +++ b/henshin/wand.go @@ -156,7 +156,7 @@ func (w *Wand) Resize(iw, ih int, strategy ResizeStrategy) { w.im = newIm } -func (w *Wand) ResizeMaxArea(area int, strategy ResizeStrategy) { +func (w *Wand) ResizeArea(area int, strategy ResizeStrategy) { iw, ih := areaFit(w.Width(), w.Height(), area) w.Resize(iw, ih, strategy) } diff --git a/main.go b/main.go index a92bfd2..0e38065 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "sync" "github.com/pborman/getopt/v2" @@ -143,31 +144,94 @@ func processFilterArgs(wand *henshin.Wand, fa *FilterArgs) { } if fa.Resize != "" { - if fa.Resize[0] == '@' { + resizeOpt := fa.Resize + shrinkLarger := resizeOpt[len(resizeOpt)-1] == '>' + enlargeSmaller := resizeOpt[len(resizeOpt)-1] == '<' + if (shrinkLarger || enlargeSmaller) && len(resizeOpt) > 1 { + resizeOpt = resizeOpt[:len(resizeOpt)-1] + } + + percentScaling := strings.ContainsRune(resizeOpt, '%') + if percentScaling { + resizeOpt = strings.ReplaceAll(resizeOpt, "%", "") + // Special case + if strings.ContainsRune("0123456789", rune(resizeOpt[0])) && !strings.ContainsRune(resizeOpt, 'x') { + // Ensure things like `-resize 50%` work + resizeOpt = resizeOpt + "x" + } + } + + if resizeOpt[0] == '@' { var area int - n, err := fmt.Sscanf(fa.Resize, "@%d", &area) + n, err := fmt.Sscanf(resizeOpt, "@%d", &area) if n == 1 && err == nil { - wand.ResizeMaxArea(int(area), henshin.BiLinearStrategy) + currentArea := wand.Width() * wand.Height() + if currentArea < area && shrinkLarger { + goto SKIP + } else if currentArea > area && enlargeSmaller { + goto SKIP + } + + wand.ResizeArea(int(area), henshin.BiLinearStrategy) } - } else if fa.Resize[0] == 'x' { + } else if resizeOpt[0] == 'x' { var h int - n, err := fmt.Sscanf(fa.Resize, "x%d", &h) + n, err := fmt.Sscanf(resizeOpt, "x%d", &h) + if n == 1 && err == nil { + if percentScaling && h != 0 { + h = int((float64(h) / 100) * float64(wand.Height())) + } + + if wand.Height() < h && shrinkLarger { + goto SKIP + } else if wand.Height() > h && enlargeSmaller { + goto SKIP + } + wand.Resize(-1, h, henshin.BiLinearStrategy) } - } else if fa.Resize[len(fa.Resize)-1] == 'x' { + } else if resizeOpt[len(resizeOpt)-1] == 'x' { var w int - n, err := fmt.Sscanf(fa.Resize, "%dx", &w) + n, err := fmt.Sscanf(resizeOpt, "%dx", &w) + if n == 1 && err == nil { + if percentScaling && w != 0 { + w = int((float64(w) / 100) * float64(wand.Width())) + } + + if wand.Width() < w && shrinkLarger { + goto SKIP + } else if wand.Width() > w && enlargeSmaller { + goto SKIP + } + wand.Resize(w, -1, henshin.BiLinearStrategy) } } else { var w, h int - n, err := fmt.Sscanf(fa.Resize, "%dx%d", &w, &h) + n, err := fmt.Sscanf(resizeOpt, "%dx%d", &w, &h) if n == 2 && err == nil { + if percentScaling && w != 0 { + w = int((float64(w) / 100) * float64(wand.Width())) + } + if percentScaling && h != 0 { + h = int((float64(h) / 100) * float64(wand.Height())) + } + + area := w * h + currentArea := wand.Width() * wand.Height() + if currentArea < area && shrinkLarger { + goto SKIP + } else if currentArea > area && enlargeSmaller { + goto SKIP + } + wand.Resize(w, h, henshin.BiLinearStrategy) } } + + SKIP: } if fa.CompressionLevel != -1 {