From 7bd1ba9cad3c900289768ce2d099f2de145f64e2 Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Mon, 10 Aug 2026 15:12:47 +0100 Subject: [PATCH] sixel: preserve fractional raster extents --- image-sixel.c | 25 ++++++++++++++++++++++--- regress/image-support.sh | 10 ++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/image-sixel.c b/image-sixel.c index 324f46b65..f687a51d8 100644 --- a/image-sixel.c +++ b/image-sixel.c @@ -602,7 +602,7 @@ sixel_scale(struct sixel_image *si, u_int cell_w, u_int cell_h, u_int ox, u_int oy, u_int sx, u_int sy, int colours) { struct sixel_image *new; - uint64_t x0, x1, y0, y1; + uint64_t x0, x1, y0, y1, tx0, tx1, ty0, ty1; u_int cx, cy, pox, poy, psx, psy, tsx, tsy, px, py; u_int x, y, i; @@ -640,8 +640,27 @@ sixel_scale(struct sixel_image *si, u_int cell_w, u_int cell_h, u_int ox, psx = x1 - x0; psy = y1 - y0; - tsx = sx * cell_w; - tsy = sy * cell_h; + /* + * Preserve any partial final source cell. The grid still covers whole + * cells, but the SIXEL raster must end at the corresponding pixel offset + * rather than stretching to the cell boundary. + */ + tx1 = ((uint64_t)si->sx * cell_w + si->cell_w - 1) / si->cell_w; + ty1 = ((uint64_t)si->sy * cell_h + si->cell_h - 1) / si->cell_h; + if (tx1 > UINT_MAX || ty1 > UINT_MAX) + return (NULL); + tx0 = (uint64_t)ox * cell_w; + ty0 = (uint64_t)oy * cell_h; + if (tx0 >= tx1 || ty0 >= ty1) + return (NULL); + if ((uint64_t)(ox + sx) * cell_w < tx1) + tx1 = (uint64_t)(ox + sx) * cell_w; + if ((uint64_t)(oy + sy) * cell_h < ty1) + ty1 = (uint64_t)(oy + sy) * cell_h; + tsx = tx1 - tx0; + tsy = ty1 - ty0; + if (tsx == 0 || tsy == 0) + return (NULL); new = xcalloc (1, sizeof *si); new->cell_w = cell_w; diff --git a/regress/image-support.sh b/regress/image-support.sh index 41e60e191..c15ec30bb 100755 --- a/regress/image-support.sh +++ b/regress/image-support.sh @@ -50,14 +50,24 @@ $TMUX2 new-session -d -x 10 -y 4 " printf '\033Pq\"1;1;26;26#0;2;100;100;100#0!26~-!26~-!26~-!26~-!26B\033\\' sleep 10" || exit 1 $TMUX2 set -g status off || exit 1 +$TMUX2 set -as terminal-features ',*:sixel' || exit 1 $TMUX new-session -d -x 10 -y 4 || exit 1 $TMUX set -g status off || exit 1 +$TMUX pipe-pane -O "cat >$TMP" || exit 1 $TMUX send-keys -l "$TMUX2 attach-session" || exit 1 $TMUX send-keys Enter || exit 1 sleep 1 $TMUX capture-pane -pS0 -E0 >$TMP || exit 1 grep -q '^#=' $TMP || exit 1 +# Re-emitting the image preserves the 26-pixel raster rather than expanding +# it to the two complete 16-pixel grid cells occupied by the image. +$TMUX pipe-pane || exit 1 +$TMUX pipe-pane -O "cat >$TMP" || exit 1 +$TMUX2 refresh-client -R || exit 1 +sleep 1 +grep -a '"1;1;26;26' $TMP >/dev/null || exit 1 + # Selection redraws must leave text image cells visible. $TMUX2 copy-mode || exit 1 $TMUX2 send-keys -X history-top || exit 1