Files
MeBox/internal/service/image_resize_budget_test.go
T
2026-09-20 15:16:40 +08:00

114 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"bytes"
"errors"
"image"
"image/color"
"image/jpeg"
"testing"
)
// encodeTestJPEG 生成一张便于压缩的测试用 JPEG(比 PNG 更适合构造大尺寸样本)。
func encodeTestJPEG(t *testing.T, w, h int) []byte {
t.Helper()
img := image.NewRGBA(image.Rect(0, 0, w, h))
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
img.Set(x, y, color.RGBA{R: uint8(x % 32 * 8), G: uint8(y % 32 * 8), B: 150, A: 255})
}
}
var buf bytes.Buffer
if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 70}); err != nil {
t.Fatalf("encode test jpeg: %v", err)
}
return buf.Bytes()
}
// TestResizeImageDataRejectsOverPixelBudget 锁定解码像素预算:超过上限的
// 原图必须放弃缩放(回退原图直出),而不是在小内存主机上尝试解码。
func TestResizeImageDataRejectsOverPixelBudget(t *testing.T) {
// 12_000_000 像素预算之上:3000×5000 = 1500 万。
data := encodeTestJPEG(t, 3000, 5000)
if _, _, _, err := resizeImageData(data, imageResizeOptions{MaxWidth: 400}); !errors.Is(err, errImageResizeTooLarge) {
t.Fatalf("expected errImageResizeTooLarge, got %v", err)
}
}
// TestResizeImageDataAcceptsRealisticPoster 常见高清海报(2892×4096,约
// 1180 万像素)必须仍在预算之内,否则真实海报会退化成直出多兆字节原图。
func TestResizeImageDataAcceptsRealisticPoster(t *testing.T) {
data := encodeTestJPEG(t, 2892, 4096)
out, ctype, unchanged, err := resizeImageData(data, imageResizeOptions{MaxWidth: 480, MaxHeight: 600})
if err != nil {
t.Fatalf("resizeImageData failed: %v", err)
}
if unchanged {
t.Fatal("expected a resized result, got the original bytes")
}
if ctype != "image/jpeg" {
t.Fatalf("content type = %q, want image/jpeg", ctype)
}
cfg, _, err := image.DecodeConfig(bytes.NewReader(out))
if err != nil {
t.Fatalf("decode resized output: %v", err)
}
if cfg.Width != 424 || cfg.Height != 600 {
t.Fatalf("resized to %dx%d, want 424x600", cfg.Width, cfg.Height)
}
}
// TestUseCheapScaleInterpolator 大比例缩小走低成本插值,轻微缩小仍保持高质量。
func TestUseCheapScaleInterpolator(t *testing.T) {
cases := []struct {
name string
dstW, dstH, srcW, srcH int
want bool
}{
{"poster to card", 480, 600, 2892, 4096, true},
{"hero to strip", 480, 320, 1920, 1080, true},
{"exactly half is cheap", 960, 540, 1920, 1080, true},
{"slight shrink", 900, 540, 1000, 600, false},
{"upscale", 1200, 800, 600, 400, false},
{"zero source", 100, 100, 0, 0, false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := useCheapScaleInterpolator(tc.dstW, tc.dstH, tc.srcW, tc.srcH); got != tc.want {
t.Fatalf("useCheapScaleInterpolator(%d,%d,%d,%d) = %v, want %v",
tc.dstW, tc.dstH, tc.srcW, tc.srcH, got, tc.want)
}
})
}
}
// TestIsOpaqueImageDetectsAlpha 透明度检测:全不透明才允许转 JPEG。
func TestIsOpaqueImageDetectsAlpha(t *testing.T) {
opaque := image.NewRGBA(image.Rect(0, 0, 4, 4))
for y := 0; y < 4; y++ {
for x := 0; x < 4; x++ {
opaque.Set(x, y, color.RGBA{R: 10, G: 20, B: 30, A: 255})
}
}
if !isOpaqueImage(opaque) {
t.Fatal("expected fully opaque image to be reported opaque")
}
withAlpha := image.NewRGBA(image.Rect(0, 0, 4, 4))
for y := 0; y < 4; y++ {
for x := 0; x < 4; x++ {
withAlpha.Set(x, y, color.RGBA{R: 10, G: 20, B: 30, A: 255})
}
}
withAlpha.Set(2, 2, color.RGBA{R: 10, G: 20, B: 30, A: 128})
if isOpaqueImage(withAlpha) {
t.Fatal("expected image with a translucent pixel to be reported non-opaque")
}
if isOpaqueImage(nil) {
t.Fatal("expected nil image to be reported non-opaque")
}
}