Preserve SIXEL pixel dimensions

Retain the padded canonical pixel canvas separately from the image content. Scale only the populated portion of partial edge cells so an image keeps its exact raster size on the originating terminal while retaining its cell footprint.
This commit is contained in:
Michael Grant
2026-08-03 12:14:49 +01:00
parent 08f0c0485b
commit 832d2beb2d
4 changed files with 66 additions and 27 deletions

45
image.c
View File

@@ -108,14 +108,19 @@ image_sample(struct image *im, uint64_t sample_x, uint64_t sample_y,
uint64_t brightness = 0, count = 0;
u_int x, y, x0, x1, y0, y1;
x0 = sample_x * im->width / sample_columns;
x1 = (sample_x + 1) * im->width / sample_columns;
y0 = sample_y * im->height / sample_rows;
y1 = (sample_y + 1) * im->height / sample_rows;
x0 = sample_x * im->canvas_width / sample_columns;
x1 = ((sample_x + 1) * im->canvas_width + sample_columns - 1) /
sample_columns;
y0 = sample_y * im->canvas_height / sample_rows;
y1 = ((sample_y + 1) * im->canvas_height + sample_rows - 1) /
sample_rows;
if (x1 <= x0)
x1 = x0 + 1;
if (y1 <= y0)
y1 = y0 + 1;
count = (uint64_t)(x1 - x0) * (y1 - y0);
if (x0 >= im->width || y0 >= im->height)
return;
if (x1 > im->width)
x1 = im->width;
if (y1 > im->height)
@@ -131,7 +136,6 @@ image_sample(struct image *im, uint64_t sample_x, uint64_t sample_y,
brightness += ((2126ULL * pixel[0] +
7152ULL * pixel[1] + 722ULL * pixel[2]) / 10000) *
pixel[3] / 255;
count++;
}
}
if (count == 0)
@@ -182,11 +186,13 @@ image_find(u_int id)
}
struct image *
image_create(u_int width, u_int height, u_int sx, u_int sy, u_char *pixels)
image_create(u_int width, u_int height, u_int canvas_width,
u_int canvas_height, u_int sx, u_int sy, u_char *pixels)
{
struct image *im;
if (width == 0 || height == 0 || sx == 0 || sy == 0 || pixels == NULL)
if (width == 0 || height == 0 || canvas_width < width ||
canvas_height < height || sx == 0 || sy == 0 || pixels == NULL)
return (NULL);
if ((uint64_t)width * height * 4 > SIZE_MAX)
return (NULL);
@@ -203,6 +209,8 @@ image_create(u_int width, u_int height, u_int sx, u_int sy, u_char *pixels)
im->references = 1;
im->width = width;
im->height = height;
im->canvas_width = canvas_width;
im->canvas_height = canvas_height;
im->sx = sx;
im->sy = sy;
im->stride = (size_t)width * 4;
@@ -210,8 +218,9 @@ image_create(u_int width, u_int height, u_int sx, u_int sy, u_char *pixels)
im->pixels = pixels;
RB_INSERT(images, &images, im);
log_debug("%s: image %u is %ux%u pixels, %ux%u cells", __func__,
im->id, width, height, sx, sy);
log_debug("%s: image %u is %ux%u pixels on %ux%u canvas, "
"%ux%u cells", __func__, im->id, width, height, canvas_width,
canvas_height, sx, sy);
return (im);
}
@@ -281,14 +290,16 @@ image_get_pixel_rectangle(const struct image *im, u_int x, u_int y,
if (height > im->sy - y)
height = im->sy - y;
*px = (uint64_t)x * im->width / im->sx;
*py = (uint64_t)y * im->height / im->sy;
x1 = (uint64_t)(x + width) * im->width / im->sx;
y1 = (uint64_t)(y + height) * im->height / im->sy;
if (*px >= im->width)
*px = im->width - 1;
if (*py >= im->height)
*py = im->height - 1;
*px = (uint64_t)x * im->canvas_width / im->sx;
*py = (uint64_t)y * im->canvas_height / im->sy;
x1 = ((uint64_t)(x + width) * im->canvas_width + im->sx - 1) /
im->sx;
y1 = ((uint64_t)(y + height) * im->canvas_height + im->sy - 1) /
im->sy;
if (*px >= im->width || *py >= im->height) {
*px = *py = 0;
return;
}
if (x1 <= *px)
x1 = *px + 1;
if (y1 <= *py)