Test that fit=cover serves a thin source and keeps its centre (part of #282)
An 8192x64 or 8192x1 source, or one turned on its side, requested at 8192x8192 with fit=cover must be served at that size, and fit=cover must keep the centre of an ordinary source. Model: opus-5-5
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package imageprocessor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestImageProcessor_FitCoverServesThinSource verifies that FitCover serves
|
||||
// a source of 8192x64 or 8192x1, or one of those turned on its side, at
|
||||
// 8192x8192. Scaling such a source to cover that size makes it 128 or 8192
|
||||
// times as long as the output on its long side.
|
||||
func TestImageProcessor_FitCoverServesThinSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
inputWidth, inputHeight int
|
||||
}{
|
||||
{"8192x64", 8192, 64},
|
||||
{"8192x1", 8192, 1},
|
||||
{"64x8192", 64, 8192},
|
||||
{"1x8192", 1, 8192},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := createTestJPEG(t, tt.inputWidth, tt.inputHeight)
|
||||
|
||||
result, err := New(Params{}).Process(t.Context(),
|
||||
bytes.NewReader(input),
|
||||
&Request{
|
||||
Size: Size{
|
||||
Width: MaxOutputDimension,
|
||||
Height: MaxOutputDimension,
|
||||
},
|
||||
Format: FormatJPEG,
|
||||
FitMode: FitCover,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Process() error = %v", err)
|
||||
}
|
||||
|
||||
defer func() { _ = result.Content.Close() }()
|
||||
|
||||
t.Logf("Process() made %dx%d", result.Width, result.Height)
|
||||
|
||||
if result.Width != MaxOutputDimension ||
|
||||
result.Height != MaxOutputDimension {
|
||||
t.Errorf("Process() made %dx%d, want %dx%d",
|
||||
result.Width, result.Height,
|
||||
MaxOutputDimension, MaxOutputDimension)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// createBandsPNG creates a PNG of three equal bands, red, green and blue,
|
||||
// side by side when it is wider than tall and top to bottom otherwise.
|
||||
func createBandsPNG(t *testing.T, width, height int) []byte {
|
||||
t.Helper()
|
||||
|
||||
bands := []color.RGBA{
|
||||
{R: 255, A: 255},
|
||||
{G: 255, A: 255},
|
||||
{B: 255, A: 255},
|
||||
}
|
||||
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
for y := range height {
|
||||
for x := range width {
|
||||
band := 3 * y / height
|
||||
if width > height {
|
||||
band = 3 * x / width
|
||||
}
|
||||
|
||||
img.Set(x, y, bands[band])
|
||||
}
|
||||
}
|
||||
|
||||
return encodePNG(t, img)
|
||||
}
|
||||
|
||||
// TestImageProcessor_FitCoverCropsTheCentre verifies that FitCover keeps the
|
||||
// centre of the source: a 300x100 source of red, green and blue bands side
|
||||
// by side, or a 100x300 one with them top to bottom, comes out at 50x50 as
|
||||
// its green band.
|
||||
func TestImageProcessor_FitCoverCropsTheCentre(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
inputWidth, inputHeight int
|
||||
}{
|
||||
{"bands side by side", 300, 100},
|
||||
{"bands top to bottom", 100, 300},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := createBandsPNG(t, tt.inputWidth, tt.inputHeight)
|
||||
|
||||
result, err := New(Params{}).Process(t.Context(),
|
||||
bytes.NewReader(input),
|
||||
&Request{
|
||||
Size: Size{Width: 50, Height: 50},
|
||||
Format: FormatPNG,
|
||||
FitMode: FitCover,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Process() error = %v", err)
|
||||
}
|
||||
|
||||
defer func() { _ = result.Content.Close() }()
|
||||
|
||||
output, err := png.Decode(result.Content)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode output: %v", err)
|
||||
}
|
||||
|
||||
bounds := output.Bounds()
|
||||
t.Logf("Process() made %dx%d", bounds.Dx(), bounds.Dy())
|
||||
|
||||
if bounds.Dx() != 50 || bounds.Dy() != 50 {
|
||||
t.Fatalf("Process() made %dx%d, want 50x50",
|
||||
bounds.Dx(), bounds.Dy())
|
||||
}
|
||||
|
||||
// Resampling may blend a little of the bands beside the
|
||||
// green one into the output's edges.
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
r, g, b, _ := output.At(x, y).RGBA()
|
||||
if r>>8 > 64 || g>>8 < 192 || b>>8 > 64 {
|
||||
t.Fatalf("output pixel %d,%d is %d,%d,%d, want green",
|
||||
x, y, r>>8, g>>8, b>>8)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user