aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2026-06-11 21:37:07 -0700
committerRose Hogenson <rosehogenson@posteo.net>2026-06-11 21:37:07 -0700
commit32847faf25a59a63c8530e71b26df81c625b756c (patch)
treed0f03f305cd03fb74fce5afeee2e208bb8beed21
parent3a2fa3f5839ab28c64ba3eef65697130efd5e593 (diff)
downloadimgutil-32847faf25a59a63c8530e71b26df81c625b756c.tar.zst
Implement resizing
-rw-r--r--convert.go54
1 files changed, 50 insertions, 4 deletions
diff --git a/convert.go b/convert.go
index ea7403c..432d0fc 100644
--- a/convert.go
+++ b/convert.go
@@ -12,10 +12,18 @@ import (
"strings"
"golang.org/x/image/bmp"
+ "golang.org/x/image/draw"
"golang.org/x/image/tiff"
_ "golang.org/x/image/webp"
)
+var (
+ x = flag.Int("x", 0, "new image width")
+ y = flag.Int("y", 0, "new image height")
+ stretch = flag.Bool("stretch", false, "if resizing, whether to stretch the image rather than cropping (the default)")
+ format = flag.String("format", "", "output image format, default is to use the file extension")
+)
+
func load(filename string) (image.Image, error) {
file := os.Stdin
if filename != "-" {
@@ -35,6 +43,37 @@ func load(filename string) (image.Image, error) {
return img, nil
}
+func divRound(n, d int) int {
+ return (n + d/2) / d
+}
+
+func resize(img image.Image) image.Image {
+ x, y := *x, *y
+ if x == 0 {
+ x = divRound(y*img.Bounds().Dx(), img.Bounds().Dy())
+ }
+ if y == 0 {
+ y = divRound(x*img.Bounds().Dy(), img.Bounds().Dx())
+ }
+ output := image.NewRGBA64(image.Rect(0, 0, x, y))
+ srcRect := img.Bounds()
+ if !*stretch {
+ if img.Bounds().Dx()*y >= img.Bounds().Dy()*x {
+ scaledX := divRound(img.Bounds().Dy()*x, y)
+ xOffset := (img.Bounds().Dx() - scaledX) / 2
+ srcRect.Min.X += xOffset
+ srcRect.Max.X = srcRect.Min.X + scaledX
+ } else {
+ scaledY := divRound(img.Bounds().Dx()*y, x)
+ yOffset := (img.Bounds().Dy() - scaledY) / 2
+ srcRect.Min.Y += yOffset
+ srcRect.Max.Y = srcRect.Min.Y + scaledY
+ }
+ }
+ draw.CatmullRom.Scale(output, output.Bounds(), img, srcRect, draw.Src, nil)
+ return output
+}
+
func run() error {
args := flag.Args()
if len(args) != 2 {
@@ -42,11 +81,14 @@ func run() error {
}
inputFileName, outputFileName := args[0], args[1]
- n := strings.LastIndex(outputFileName, ".")
- if n < 0 {
- return errors.New("unknown output file extension")
+ ext := *format
+ if ext == "" {
+ n := strings.LastIndex(outputFileName, ".")
+ if n < 0 {
+ return errors.New("unknown output file extension")
+ }
+ ext = outputFileName[n+1:]
}
- ext := outputFileName[n+1:]
switch ext {
case "gif", "jpeg", "jpg", "png", "bmp", "tiff":
default:
@@ -58,6 +100,10 @@ func run() error {
return err
}
+ if *x != 0 || *y != 0 {
+ input = resize(input)
+ }
+
outputFile, err := os.Create(outputFileName)
if err != nil {
return err