Real-image posters: scale to the box's pixel size
Ghostty shows an image smaller than its placement at its own size, so library posters (Radarr's poster-500 is 333x500, not 500x750) came out smaller than the 426x640 remote ones. Images are now scaled (bilinear) to exactly cols*cellWidth x rows*cellHeight pixels before upload, and library titles use the original poster for real images. The disk cache stores posters as decoded (JPEG) instead of the possibly large originals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+27
-2
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
xdraw "golang.org/x/image/draw"
|
||||
"image"
|
||||
"image/png"
|
||||
"strings"
|
||||
@@ -43,6 +44,11 @@ type kittyGraphics struct {
|
||||
|
||||
holdUntil time.Time // no real images until then (the window is being resized)
|
||||
debug func(string) // reports what is uploaded, if set
|
||||
// cellPixels returns the size of a cell in pixels (0 if unknown): images are
|
||||
// scaled to exactly fill their cells, because terminals do not all enlarge
|
||||
// an image that is smaller than its placement (Ghostty shows it at its own
|
||||
// size, so a small poster came out smaller than the others).
|
||||
cellPixels func() (w, h int)
|
||||
}
|
||||
|
||||
// settleDelay is how long the window size must stay the same before real
|
||||
@@ -92,9 +98,15 @@ func (k *kittyGraphics) show(img *image.RGBA, rect image.Rectangle, cols, rows i
|
||||
if id, ok := k.ids[key]; ok {
|
||||
return id, nil
|
||||
}
|
||||
var src image.Image = img.SubImage(rect)
|
||||
if k.cellPixels != nil {
|
||||
if cw, ch := k.cellPixels(); cw > 0 && ch > 0 {
|
||||
src = scaleImage(src, cols*cw, rows*ch)
|
||||
}
|
||||
}
|
||||
var data bytes.Buffer
|
||||
enc := png.Encoder{CompressionLevel: png.BestSpeed}
|
||||
if err := enc.Encode(&data, img.SubImage(rect)); err != nil {
|
||||
if err := enc.Encode(&data, src); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
encoded := base64.StdEncoding.EncodeToString(data.Bytes())
|
||||
@@ -130,7 +142,8 @@ func (k *kittyGraphics) show(img *image.RGBA, rect image.Rectangle, cols, rows i
|
||||
k.ids[key] = id
|
||||
k.latest[img] = key
|
||||
if k.debug != nil {
|
||||
k.debug(fmt.Sprintf("graphics: id %d, poster %dx%d px cropped to %v, placed over %dx%d cells", id, img.Bounds().Dx(), img.Bounds().Dy(), rect, cols, rows))
|
||||
k.debug(fmt.Sprintf("graphics: id %d, poster %dx%d px cropped to %v, sent as %dx%d px, placed over %dx%d cells",
|
||||
id, img.Bounds().Dx(), img.Bounds().Dy(), rect, src.Bounds().Dx(), src.Bounds().Dy(), cols, rows))
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
@@ -175,3 +188,15 @@ func kittyTerminal(env func(string) string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// scaleImage resizes src to w×h pixels, smoothly (bilinear) both up and down.
|
||||
// Sizes beyond 4000 pixels are not made (a misreported cell size).
|
||||
func scaleImage(src image.Image, w, h int) image.Image {
|
||||
b := src.Bounds()
|
||||
if w <= 0 || h <= 0 || w > 4000 || h > 4000 || (w == b.Dx() && h == b.Dy()) {
|
||||
return src
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
xdraw.BiLinear.Scale(dst, dst.Bounds(), src, b, xdraw.Src, nil)
|
||||
return dst
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user