mirror of
https://github.com/tmux/tmux.git
synced 2026-09-01 19:33:36 +00:00
image: preserve fractional cell extents
This commit is contained in:
@@ -76,6 +76,8 @@ struct kitty_state {
|
||||
u_int height;
|
||||
u_int source_x;
|
||||
u_int source_y;
|
||||
u_int x_offset;
|
||||
u_int y_offset;
|
||||
u_int source_width;
|
||||
u_int source_height;
|
||||
u_int columns;
|
||||
@@ -526,6 +528,8 @@ kitty_control(struct kitty_state *ks, const u_char *buf, size_t len)
|
||||
case 'S':
|
||||
case 'C':
|
||||
case 'U':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
if (kitty_number((const char *)value, valuelen,
|
||||
&number) != 0)
|
||||
return (-1);
|
||||
@@ -546,6 +550,8 @@ kitty_control(struct kitty_state *ks, const u_char *buf, size_t len)
|
||||
case 'S': ks->data_size = number; break;
|
||||
case 'C': ks->no_cursor = (number != 0); break;
|
||||
case 'U': ks->virtual = (number != 0); break;
|
||||
case 'X': ks->x_offset = number; break;
|
||||
case 'Y': ks->y_offset = number; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -855,7 +861,7 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
|
||||
uint64_t numerator, denominator, value;
|
||||
u_int x, y, width, height, sx, sy, canvas_width;
|
||||
u_int canvas_height, cell_width, cell_height, source_width;
|
||||
u_int source_height;
|
||||
u_int source_height, display_width, display_height;
|
||||
struct image *im;
|
||||
|
||||
x = ks->source_x;
|
||||
@@ -869,11 +875,17 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
|
||||
height = ks->source_height;
|
||||
if (height == 0 || height > source_height - y)
|
||||
height = source_height - y;
|
||||
if (ks->x_offset > UINT_MAX - width ||
|
||||
ks->y_offset > UINT_MAX - height)
|
||||
return (NULL);
|
||||
display_width = width + ks->x_offset;
|
||||
display_height = height + ks->y_offset;
|
||||
|
||||
cell_width = (xpixel == 0 ? 8 : xpixel);
|
||||
cell_height = (ypixel == 0 ? 16 : ypixel);
|
||||
if (ks->columns == 0 && ks->rows == 0) {
|
||||
image_size_in_cells(width, height, cell_width, cell_height,
|
||||
image_size_in_cells(display_width, display_height, cell_width,
|
||||
cell_height,
|
||||
&sx, &sy);
|
||||
value = (uint64_t)sx * cell_width;
|
||||
if (value > UINT_MAX)
|
||||
@@ -886,46 +898,46 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
|
||||
} else if (ks->columns != 0 && ks->rows != 0) {
|
||||
sx = ks->columns;
|
||||
sy = ks->rows;
|
||||
canvas_width = width;
|
||||
canvas_height = height;
|
||||
canvas_width = display_width;
|
||||
canvas_height = display_height;
|
||||
} else if (ks->columns != 0) {
|
||||
sx = ks->columns;
|
||||
numerator = (uint64_t)height * sx * cell_width;
|
||||
denominator = (uint64_t)width * cell_height;
|
||||
numerator = (uint64_t)display_height * sx * cell_width;
|
||||
denominator = (uint64_t)display_width * cell_height;
|
||||
value = (numerator + denominator - 1) / denominator;
|
||||
if (value == 0 || value > UINT_MAX)
|
||||
return (NULL);
|
||||
sy = value;
|
||||
canvas_width = width;
|
||||
numerator = (uint64_t)sy * cell_height * width;
|
||||
canvas_width = display_width;
|
||||
numerator = (uint64_t)sy * cell_height * display_width;
|
||||
denominator = (uint64_t)sx * cell_width;
|
||||
value = (numerator + denominator - 1) / denominator;
|
||||
if (value < height)
|
||||
value = height;
|
||||
if (value < display_height)
|
||||
value = display_height;
|
||||
if (value > UINT_MAX)
|
||||
return (NULL);
|
||||
canvas_height = value;
|
||||
} else {
|
||||
sy = ks->rows;
|
||||
numerator = (uint64_t)width * sy * cell_height;
|
||||
denominator = (uint64_t)height * cell_width;
|
||||
numerator = (uint64_t)display_width * sy * cell_height;
|
||||
denominator = (uint64_t)display_height * cell_width;
|
||||
value = (numerator + denominator - 1) / denominator;
|
||||
if (value == 0 || value > UINT_MAX)
|
||||
return (NULL);
|
||||
sx = value;
|
||||
canvas_height = height;
|
||||
numerator = (uint64_t)sx * cell_width * height;
|
||||
canvas_height = display_height;
|
||||
numerator = (uint64_t)sx * cell_width * display_height;
|
||||
denominator = (uint64_t)sy * cell_height;
|
||||
value = (numerator + denominator - 1) / denominator;
|
||||
if (value < width)
|
||||
value = width;
|
||||
if (value < display_width)
|
||||
value = display_width;
|
||||
if (value > UINT_MAX)
|
||||
return (NULL);
|
||||
canvas_width = value;
|
||||
}
|
||||
|
||||
im = image_create_view(source, x, y, width, height, canvas_width,
|
||||
canvas_height, sx, sy);
|
||||
canvas_height, sx, sy, ks->x_offset, ks->y_offset);
|
||||
if (im != NULL && ks->no_cursor)
|
||||
image_set_no_cursor(im);
|
||||
return (im);
|
||||
|
||||
@@ -603,7 +603,7 @@ sixel_scale(struct sixel_image *si, u_int cell_w, u_int cell_h, u_int ox,
|
||||
{
|
||||
struct sixel_image *new;
|
||||
u_int cx, cy, pox, poy, psx, psy, tsx, tsy, px, py;
|
||||
uint64_t x0, x1, y0, y1;
|
||||
uint64_t x0, x1, y0, y1, tx0, tx1, ty0, ty1;
|
||||
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;
|
||||
|
||||
33
image.c
33
image.c
@@ -971,13 +971,15 @@ image_create(u_int width, u_int height, u_int canvas_width,
|
||||
return (im);
|
||||
}
|
||||
|
||||
/* Create an immutable rectangular view without copying its source pixels. */
|
||||
/* Create a cell-aligned view of an existing image. */
|
||||
/* Create a cell-aligned view of an existing image with an optional offset. */
|
||||
struct image *
|
||||
image_create_view(struct image *source, u_int x, u_int y, u_int width,
|
||||
u_int height, u_int canvas_width, u_int canvas_height, u_int sx, u_int sy)
|
||||
u_int height, u_int canvas_width, u_int canvas_height, u_int sx, u_int sy,
|
||||
u_int x_offset, u_int y_offset)
|
||||
{
|
||||
struct image *im;
|
||||
u_char *pixels;
|
||||
u_int padded_width, padded_height, yy;
|
||||
|
||||
if (source == NULL || x >= source->width || y >= source->height ||
|
||||
width == 0 || width > source->width - x || height == 0 ||
|
||||
@@ -988,9 +990,28 @@ image_create_view(struct image *source, u_int x, u_int y, u_int width,
|
||||
sx > USHRT_MAX || sy > USHRT_MAX)
|
||||
return (NULL);
|
||||
|
||||
im = image_create1(width, height, canvas_width, canvas_height, sx, sy,
|
||||
source->stride, source->pixels + (size_t)y * source->stride +
|
||||
(size_t)x * 4);
|
||||
if (x_offset == 0 && y_offset == 0) {
|
||||
im = image_create1(width, height, canvas_width, canvas_height,
|
||||
sx, sy, source->stride, source->pixels +
|
||||
(size_t)y * source->stride + (size_t)x * 4);
|
||||
} else {
|
||||
if (x_offset > UINT_MAX - width ||
|
||||
y_offset > UINT_MAX - height)
|
||||
return (NULL);
|
||||
padded_width = width + x_offset;
|
||||
padded_height = height + y_offset;
|
||||
if ((uint64_t)padded_width * padded_height * 4 > SIZE_MAX)
|
||||
return (NULL);
|
||||
pixels = xcalloc((size_t)padded_width * padded_height, 4);
|
||||
for (yy = 0; yy < height; yy++) {
|
||||
memcpy(pixels + (size_t)(yy + y_offset) * padded_width * 4 +
|
||||
(size_t)x_offset * 4,
|
||||
source->pixels + (size_t)(y + yy) * source->stride +
|
||||
(size_t)x * 4, (size_t)width * 4);
|
||||
}
|
||||
im = image_create1(padded_width, padded_height, canvas_width,
|
||||
canvas_height, sx, sy, (size_t)padded_width * 4, pixels);
|
||||
}
|
||||
if (im == NULL)
|
||||
return (NULL);
|
||||
im->parent_id = source->id;
|
||||
|
||||
@@ -79,14 +79,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
|
||||
|
||||
# A selection redraw uses the single-cell path. It must leave ASCII image
|
||||
# cells visible (graphical clients skip these cells to avoid erasing pixels).
|
||||
$TMUX2 copy-mode || exit 1
|
||||
|
||||
2
tmux.h
2
tmux.h
@@ -4237,7 +4237,7 @@ char *regsub(const char *, const char *, const char *, int);
|
||||
struct image *image_create(u_int, u_int, u_int, u_int, u_int, u_int,
|
||||
u_char *);
|
||||
struct image *image_create_view(struct image *, u_int, u_int, u_int,
|
||||
u_int, u_int, u_int, u_int, u_int);
|
||||
u_int, u_int, u_int, u_int, u_int, u_int, u_int);
|
||||
struct image *image_find(u_int);
|
||||
u_int image_get_id(const struct image *);
|
||||
void image_get_size(const struct image *, u_int *, u_int *);
|
||||
|
||||
Reference in New Issue
Block a user