Real-image posters: match the box to the poster's shape and crop the remainder
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"image"
|
||||
"image/png"
|
||||
"math"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -49,7 +50,7 @@ func TestKittyUploadChunksAndEncodes(t *testing.T) {
|
||||
k := newKittyGraphics(rec.write)
|
||||
img := noisy(200, 300) // incompressible: far more than one 4096-byte chunk of base64
|
||||
|
||||
id, err := k.imageID(img)
|
||||
id, err := k.imageID(img, img.Bounds())
|
||||
if err != nil || id != 1 {
|
||||
t.Fatalf("id=%d err=%v", id, err)
|
||||
}
|
||||
@@ -94,10 +95,10 @@ func TestKittyUploadChunksAndEncodes(t *testing.T) {
|
||||
|
||||
// The same image is not uploaded twice; another one gets the next id.
|
||||
n := len(rec.cmds)
|
||||
if again, _ := k.imageID(img); again != id || len(rec.cmds) != n {
|
||||
if again, _ := k.imageID(img, img.Bounds()); again != id || len(rec.cmds) != n {
|
||||
t.Error("an uploaded image must be reused")
|
||||
}
|
||||
if other, _ := k.imageID(noisy(4, 4)); other != 2 {
|
||||
if other, _ := k.imageID(noisy(4, 4), image.Rect(0, 0, 4, 4)); other != 2 {
|
||||
t.Errorf("second image id = %d", other)
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,8 @@ func TestKittyPlacement(t *testing.T) {
|
||||
}
|
||||
|
||||
rec.cmds = nil
|
||||
id, _ := k.imageID(noisy(2, 2))
|
||||
small := noisy(2, 2)
|
||||
id, _ := k.imageID(small, small.Bounds())
|
||||
k.deleteAll()
|
||||
if last := rec.cmds[len(rec.cmds)-1]; last != "\x1b_Ga=d,d=I,i="+itoa(int(id))+",q=2\x1b\\" {
|
||||
t.Errorf("deleteAll sent %q", last)
|
||||
@@ -237,7 +239,39 @@ func TestCoverViewGraphicsDrawsPlaceholders(t *testing.T) {
|
||||
// A cell aspect of 2.5 (taller cells) changes the footprint of the same box.
|
||||
c.cellAspect = func() float64 { return 2.5 }
|
||||
c.Draw(screen)
|
||||
if len(rec.cmds) != 4 || !strings.Contains(rec.cmds[3], "c=16,r=10") {
|
||||
t.Errorf("after the cell aspect changed: %q", rec.cmds[2:])
|
||||
// The box is now 17×10 cells, a different shape: a new crop is uploaded, the
|
||||
// old upload is removed, and the image is placed afresh.
|
||||
var placements []string
|
||||
for _, cmd := range rec.cmds[2:] {
|
||||
placements = append(placements, cmd[:min(len(cmd), 30)])
|
||||
}
|
||||
last := rec.cmds[len(rec.cmds)-1]
|
||||
if !strings.Contains(last, "c=17,r=10") || !strings.Contains(strings.Join(rec.cmds[2:], ""), "a=d,d=I,i=1") {
|
||||
t.Errorf("after the cell aspect changed: %q", placements)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCropToBox(t *testing.T) {
|
||||
b := image.Rect(0, 0, 167, 250) // a 2:3 poster
|
||||
// A box slightly narrower than the poster: the sides are trimmed.
|
||||
got := cropToBox(b, 17, 13, 2.1) // box shape 17/(13*2.1) = 0.6227 < 0.668
|
||||
if got.Dy() != 250 || got.Dx() >= 167 || got.Min.X != (167-got.Dx())/2 {
|
||||
t.Errorf("narrow box: %v", got)
|
||||
}
|
||||
if shape := float64(got.Dx()) / float64(got.Dy()); math.Abs(shape-17.0/(13*2.1)) > 0.005 {
|
||||
t.Errorf("cropped shape %.4f, want %.4f", shape, 17.0/(13*2.1))
|
||||
}
|
||||
// A box slightly wider: top and bottom are trimmed.
|
||||
got = cropToBox(b, 18, 12, 2.1) // 18/(12*2.1) = 0.714 > 0.668
|
||||
if got.Dx() != 167 || got.Dy() >= 250 || got.Min.Y != (250-got.Dy())/2 {
|
||||
t.Errorf("wide box: %v", got)
|
||||
}
|
||||
// A box of exactly the poster's shape changes nothing.
|
||||
if got := cropToBox(image.Rect(0, 0, 40, 60), 20, 15, 2); got != image.Rect(0, 0, 40, 60) {
|
||||
t.Errorf("exact box: %v", got)
|
||||
}
|
||||
// Offsets of sub-images are respected.
|
||||
if got := cropToBox(image.Rect(10, 20, 50, 80), 18, 10, 2); got.Min.X != 10 || got.Max.X != 50 || got.Min.Y < 20 || got.Max.Y > 80 || got.Dy() >= 60 {
|
||||
t.Errorf("offset image: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user