46 lines
1.1 KiB
Go
46 lines
1.1 KiB
Go
package vision
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
|
|
"golang.org/x/image/draw"
|
|
)
|
|
|
|
// EncodeJPEG 把图像等比缩放到长边不超过 maxEdge 后编码为 JPEG。
|
|
// 视觉模型对分辨率不敏感,但对 token 很敏感,这一步是成本控制的关键。
|
|
func EncodeJPEG(img image.Image, maxEdge, quality int) ([]byte, error) {
|
|
if img == nil {
|
|
return nil, fmt.Errorf("待编码图像为空")
|
|
}
|
|
if maxEdge <= 0 {
|
|
maxEdge = 1280
|
|
}
|
|
if quality <= 0 || quality > 100 {
|
|
quality = 75
|
|
}
|
|
|
|
b := img.Bounds()
|
|
w, h := b.Dx(), b.Dy()
|
|
if w <= 0 || h <= 0 {
|
|
return nil, fmt.Errorf("图像尺寸无效: %dx%d", w, h)
|
|
}
|
|
|
|
target := img
|
|
if longest := max(w, h); longest > maxEdge {
|
|
scale := float64(maxEdge) / float64(longest)
|
|
nw, nh := max(int(float64(w)*scale+0.5), 1), max(int(float64(h)*scale+0.5), 1)
|
|
dst := image.NewRGBA(image.Rect(0, 0, nw, nh))
|
|
draw.CatmullRom.Scale(dst, dst.Bounds(), img, b, draw.Src, nil)
|
|
target = dst
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := jpeg.Encode(&buf, target, &jpeg.Options{Quality: quality}); err != nil {
|
|
return nil, fmt.Errorf("JPEG 编码失败: %w", err)
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|