81 lines
2.0 KiB
Go
81 lines
2.0 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"image/png"
|
|
"strings"
|
|
|
|
"golang.org/x/image/tiff"
|
|
_ "golang.org/x/image/webp" // decode-only; we re-encode webp as png
|
|
)
|
|
|
|
// RotateImage rotates src clockwise by angle (must be 0/90/180/270).
|
|
func RotateImage(src image.Image, angle int) image.Image {
|
|
angle = ((angle % 360) + 360) % 360
|
|
if angle == 0 {
|
|
return src
|
|
}
|
|
b := src.Bounds()
|
|
w, h := b.Dx(), b.Dy()
|
|
switch angle {
|
|
case 180:
|
|
dst := image.NewRGBA(image.Rect(0, 0, w, h))
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
dst.Set(w-1-x, h-1-y, src.At(b.Min.X+x, b.Min.Y+y))
|
|
}
|
|
}
|
|
return dst
|
|
case 90:
|
|
dst := image.NewRGBA(image.Rect(0, 0, h, w))
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
dst.Set(h-1-y, x, src.At(b.Min.X+x, b.Min.Y+y))
|
|
}
|
|
}
|
|
return dst
|
|
case 270:
|
|
dst := image.NewRGBA(image.Rect(0, 0, h, w))
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
dst.Set(y, w-1-x, src.At(b.Min.X+x, b.Min.Y+y))
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
return src
|
|
}
|
|
|
|
// EncodeImage re-encodes img using format hint from the original filename / detected format.
|
|
// Falls back to PNG when format is not directly writable.
|
|
func EncodeImage(img image.Image, format string) ([]byte, string, error) {
|
|
var buf bytes.Buffer
|
|
switch strings.ToLower(format) {
|
|
case "jpeg", "jpg":
|
|
if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 92}); err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buf.Bytes(), "jpg", nil
|
|
case "tiff", "tif":
|
|
if err := tiff.Encode(&buf, img, &tiff.Options{Compression: tiff.Deflate}); err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buf.Bytes(), "tiff", nil
|
|
case "png", "":
|
|
if err := png.Encode(&buf, img); err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buf.Bytes(), "png", nil
|
|
case "webp":
|
|
// Re-encode to PNG (no webp encoder in stdlib/x/image).
|
|
if err := png.Encode(&buf, img); err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buf.Bytes(), "png", nil
|
|
}
|
|
return nil, "", fmt.Errorf("unsupported format: %s", format)
|
|
}
|