From a35871110fe8f9becc6a4cf6c928b912fb055a52 Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Thu, 6 Aug 2026 12:24:10 +0100 Subject: [PATCH] Make image types opaque --- image-kitty.c | 124 ++++++++++++++++++++++-------------------- image-sixel.c | 119 ++++++++++++++++++++++++---------------- image.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++- input.c | 4 +- screen-write.c | 2 +- tmux.h | 76 ++++++-------------------- 6 files changed, 303 insertions(+), 165 deletions(-) diff --git a/image-kitty.c b/image-kitty.c index 045645cb9..35374486f 100644 --- a/image-kitty.c +++ b/image-kitty.c @@ -219,14 +219,15 @@ kitty_place(struct tty *tty, struct image *im, u_int id) { char control[192]; u_int x, y, columns, rows, px, py, pwidth, pheight; - u_int placement = 1; + u_int placement = 1, sx, sy; - for (y = 0; y < im->sy; y += nitems(kitty_diacritics)) { - rows = im->sy - y; + image_get_cell_dimensions(im, &sx, &sy); + for (y = 0; y < sy; y += nitems(kitty_diacritics)) { + rows = sy - y; if (rows > nitems(kitty_diacritics)) rows = nitems(kitty_diacritics); - for (x = 0; x < im->sx; x += nitems(kitty_diacritics)) { - columns = im->sx - x; + for (x = 0; x < sx; x += nitems(kitty_diacritics)) { + columns = sx - x; if (columns > nitems(kitty_diacritics)) columns = nitems(kitty_diacritics); image_get_pixel_rectangle(im, x, y, columns, rows, &px, @@ -247,12 +248,14 @@ kitty_upload(struct tty *tty, struct image *im) struct kitty_image_cache *cache; char control[128], encoded[4097]; u_char raw[3072]; - size_t offset, size, copied, row, column, available; + const u_char *pixels; + size_t offset, size, copied, row, column, available, stride; + size_t image_size; int encodedlen; - u_int id; + u_int id, width, height; for (cache = ko->images; cache != NULL; cache = cache->next) { - if (cache->server_id != im->id) + if (cache->server_id != image_get_id(im)) continue; if (cache->xpixel == tty->xpixel && cache->ypixel == tty->ypixel) @@ -269,22 +272,24 @@ kitty_upload(struct tty *tty, struct image *im) do { id = ++ko->next_id & 0xffffff; } while (id == 0); - cache->server_id = im->id; + cache->server_id = image_get_id(im); cache->kitty_id = id; cache->xpixel = tty->xpixel; cache->ypixel = tty->ypixel; - for (offset = 0; offset < im->size; offset += size) { - size = im->size - offset; + pixels = image_get_pixels(im, &stride, &image_size); + image_get_dimensions(im, &width, &height); + for (offset = 0; offset < image_size; offset += size) { + size = image_size - offset; if (size > sizeof raw) size = sizeof raw; for (copied = 0; copied < size; copied += available) { - row = (offset + copied) / ((size_t)im->width * 4); - column = (offset + copied) % ((size_t)im->width * 4); - available = (size_t)im->width * 4 - column; + row = (offset + copied) / ((size_t)width * 4); + column = (offset + copied) % ((size_t)width * 4); + available = (size_t)width * 4 - column; if (available > size - copied) available = size - copied; - memcpy(raw + copied, im->pixels + row * im->stride + + memcpy(raw + copied, pixels + row * stride + column, available); } encodedlen = b64_ntop(raw, size, encoded, @@ -294,11 +299,10 @@ kitty_upload(struct tty *tty, struct image *im) if (offset == 0) { xsnprintf(control, sizeof control, "\033_Ga=t,f=32,s=%u,v=%u,i=%u,q=2,m=%d;", - im->width, im->height, id, - offset + size < im->size); + width, height, id, offset + size < image_size); } else { xsnprintf(control, sizeof control, "\033_Gm=%d;", - offset + size < im->size); + offset + size < image_size); } tty_puts(tty, control); tty_putn(tty, encoded, encodedlen, 0); @@ -311,9 +315,10 @@ kitty_upload(struct tty *tty, struct image *im) static u_int kitty_placement(struct image *im, u_int x, u_int y) { - u_int across; + u_int across, sx; - across = (im->sx + nitems(kitty_diacritics) - 1) / + image_get_cell_dimensions(im, &sx, NULL); + across = (sx + nitems(kitty_diacritics) - 1) / nitems(kitty_diacritics); return ((y / nitems(kitty_diacritics)) * across + x / nitems(kitty_diacritics) + 1); @@ -355,30 +360,32 @@ kitty_draw_rectangle(struct tty *tty, const struct image_rectangle *rectangle, { struct grid_cell draw_gc; struct kitty_image_cache *cache; - struct image *im = rectangle->image; - u_int x, y, run, available; + struct image *im; + u_int x, y, run, available, source_x, source_y; + u_int width, height, destination_x, destination_y; + im = image_rectangle_get_image(rectangle); kitty_images_collect(tty); cache = kitty_upload(tty, im); if (cache == NULL) return; - memcpy(&draw_gc, &rectangle->cell, sizeof draw_gc); + memcpy(&draw_gc, image_rectangle_get_cell(rectangle), sizeof draw_gc); + image_rectangle_get_coordinates(rectangle, &source_x, &source_y, &width, + &height, &destination_x, &destination_y); draw_gc.flags &= ~(GRID_FLAG_IMAGE|GRID_FLAG_SELECTED); utf8_set(&draw_gc.data, ' '); - for (y = 0; y < rectangle->height; y++) { - for (x = 0; x < rectangle->width; x += run) { + for (y = 0; y < height; y++) { + for (x = 0; x < width; x += run) { available = nitems(kitty_diacritics) - - (rectangle->source_x + x) % + (source_x + x) % nitems(kitty_diacritics); - run = rectangle->width - x; + run = width - x; if (run > available) run = available; - tty_cursor(tty, rectangle->destination_x + x, - rectangle->destination_y + y); + tty_cursor(tty, destination_x + x, destination_y + y); tty_attributes(tty, &draw_gc, style_ctx); - kitty_placeholder(tty, cache, im, - rectangle->source_x + x, - rectangle->source_y + y, run); + kitty_placeholder(tty, cache, im, source_x + x, + source_y + y, run); tty_reset(tty); } } @@ -569,8 +576,8 @@ kitty_source_set(struct kitty_context *kc, u_int id, struct image *im) } image_free(source->server_id); } - image_ref(im->id); - source->server_id = im->id; + image_ref(image_get_id(im)); + source->server_id = image_get_id(im); return (old_id); } @@ -599,8 +606,8 @@ kitty_placement_set(struct kitty_context *kc, u_int image_id, source->placements = placement; } old_id = placement->server_id; - image_ref(im->id); - placement->server_id = im->id; + image_ref(image_get_id(im)); + placement->server_id = image_get_id(im); if (old_id != 0) image_free(old_id); return (old_id); @@ -623,7 +630,7 @@ kitty_placement_remove(struct kitty_context *kc, u_int image_id, continue; im = image_find(placement->server_id); if (im != NULL) - image_ref(im->id); + image_ref(image_get_id(im)); *pp = placement->next; image_free(placement->server_id); free(placement); @@ -642,8 +649,8 @@ kitty_virtual_set(struct kitty_context *kc, u_int id, struct image *im) return; if (source->virtual_id != 0) image_free(source->virtual_id); - image_ref(im->id); - source->virtual_id = im->id; + image_ref(image_get_id(im)); + source->virtual_id = image_get_id(im); } static struct image * @@ -657,7 +664,7 @@ kitty_source_remove(struct kitty_context *kc, u_int id) continue; im = image_find(source->server_id); if (im != NULL) - image_ref(im->id); + image_ref(image_get_id(im)); *pp = source->next; kitty_placements_free(source); if (source->virtual_id != 0) @@ -680,7 +687,7 @@ kitty_source_get(struct kitty_context *kc, u_int id) return (NULL); im = image_find(source->server_id); if (im != NULL) - image_ref(im->id); + image_ref(image_get_id(im)); return (im); } @@ -748,19 +755,21 @@ 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; + u_int canvas_height, cell_width, cell_height, source_width; + u_int source_height; struct image *im; x = ks->source_x; y = ks->source_y; - if (x >= source->width || y >= source->height) + image_get_dimensions(source, &source_width, &source_height); + if (x >= source_width || y >= source_height) return (NULL); width = ks->source_width; - if (width == 0 || width > source->width - x) - width = source->width - x; + if (width == 0 || width > source_width - x) + width = source_width - x; height = ks->source_height; - if (height == 0 || height > source->height - y) - height = source->height - y; + if (height == 0 || height > source_height - y) + height = source_height - y; cell_width = (xpixel == 0 ? 8 : xpixel); cell_height = (ypixel == 0 ? 16 : ypixel); @@ -819,7 +828,7 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel, im = image_create_view(source, x, y, width, height, canvas_width, canvas_height, sx, sy); if (im != NULL && ks->no_cursor) - im->flags |= IMAGE_FLAG_NO_CURSOR; + image_set_no_cursor(im); return (im); } @@ -891,17 +900,17 @@ kitty_parse_image(void **state, const u_char *buf, size_t len, u_int xpixel, im = NULL; } else if (ks->virtual) { im = kitty_place_image(source, ks, xpixel, ypixel); - image_free(source->id); + image_free(image_get_id(source)); if (im != NULL) { kitty_virtual_set(kc, ks->image_id, im); - image_free(im->id); + image_free(image_get_id(im)); im = NULL; *action = 'u'; *status = KITTY_PARSE_OK; } } else { im = kitty_place_image(source, ks, xpixel, ypixel); - image_free(source->id); + image_free(image_get_id(source)); if (im != NULL) { *replace_id = kitty_placement_set(kc, ks->image_id, ks->placement_id, im); @@ -1014,14 +1023,14 @@ kitty_parse_image(void **state, const u_char *buf, size_t len, u_int xpixel, *status = KITTY_PARSE_ERROR; else { kitty_virtual_set(kc, ks->image_id, im); - image_free(im->id); + image_free(image_get_id(im)); im = NULL; *action = 'u'; } } else { im = NULL; } - image_free(source->id); + image_free(image_get_id(source)); } kitty_state_free(ks); return (im); @@ -1094,7 +1103,7 @@ kitty_placeholder_to_cell(void *state, struct grid_cell *gc, struct image *im; uint32_t value; size_t offset = 0; - u_int values[3], nvalues = 0, id, x, y; + u_int values[3], nvalues = 0, id, x, y, sx, sy; struct utf8_data data; int fg, bg, us; @@ -1127,22 +1136,23 @@ kitty_placeholder_to_cell(void *state, struct grid_cell *gc, source->server_id); if (im == NULL) return (0); + image_get_cell_dimensions(im, &sx, &sy); if (nvalues >= 1) y = values[0]; else if (left != NULL && left->flags & GRID_FLAG_IMAGE && - left->image_id == im->id) + left->image_id == image_get_id(im)) y = left->image_y; else return (0); if (nvalues >= 2) x = values[1]; else if (left != NULL && left->flags & GRID_FLAG_IMAGE && - left->image_id == im->id && left->image_x != UINT_MAX) + left->image_id == image_get_id(im) && left->image_x != UINT_MAX) x = left->image_x + 1; else return (0); - if (x >= im->sx || y >= im->sy) + if (x >= sx || y >= sy) return (0); utf8_copy(&data, &gc->data); diff --git a/image-sixel.c b/image-sixel.c index dc1c4e93a..362acc444 100644 --- a/image-sixel.c +++ b/image-sixel.c @@ -88,6 +88,40 @@ struct sixel_output { uint64_t age; }; +struct sixel_histogram { + u_int count; + uint64_t red; + uint64_t green; + uint64_t blue; +}; + +struct sixel_box { + u_int red_min; + u_int red_max; + u_int green_min; + u_int green_max; + u_int blue_min; + u_int blue_max; + u_int count; +}; + +struct sixel_rgb { + u_char red; + u_char green; + u_char blue; +}; + +struct sixel_source { + const u_char *pixels; + size_t stride; + u_int width; + u_int height; + u_int canvas_width; + u_int canvas_height; + u_int sx; + u_int sy; +}; + static int sixel_parse_expand_lines(struct sixel_image *si, u_int y) { @@ -516,7 +550,7 @@ sixel_to_image(struct sixel_image *si) if (im == NULL) free(pixels); else - im->sixel = si; + image_set_sixel(im, si); return (im); } #endif @@ -763,26 +797,6 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size) return (buf); } -struct sixel_histogram { - u_int count; - uint64_t red; - uint64_t green; - uint64_t blue; -}; - -struct sixel_box { - u_int red_min, red_max; - u_int green_min, green_max; - u_int blue_min, blue_max; - u_int count; -}; - -struct sixel_rgb { - u_char red; - u_char green; - u_char blue; -}; - /* Split a 5-bit RGB histogram into an adaptive palette using median cut. */ static void sixel_box_update(struct sixel_box *box, struct sixel_histogram *histogram) @@ -992,7 +1006,8 @@ sixel_clamp_colour(int colour) } static const u_char * -sixel_from_image_pixel(struct image *im, u_int sourcex0, u_int sourcey0, +sixel_from_image_pixel(const struct sixel_source *source, u_int sourcex0, + u_int sourcey0, u_int sourcewidth, u_int sourceheight, u_int sx, u_int sy, u_int x, u_int y) { @@ -1000,11 +1015,11 @@ sixel_from_image_pixel(struct image *im, u_int sourcex0, u_int sourcey0, sourcex = sourcex0 + (uint64_t)x * sourcewidth / sx; sourcey = sourcey0 + (uint64_t)y * sourceheight / sy; - if (sourcex >= im->width) - sourcex = im->width - 1; - if (sourcey >= im->height) - sourcey = im->height - 1; - return (im->pixels + sourcey * im->stride + sourcex * 4); + if (sourcex >= source->width) + sourcex = source->width - 1; + if (sourcey >= source->height) + sourcey = source->height - 1; + return (source->pixels + sourcey * source->stride + sourcex * 4); } static struct sixel_image * @@ -1014,6 +1029,7 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, struct sixel_image *si; struct sixel_histogram *histogram, *entry; struct sixel_rgb palette[SIXEL_PALETTE_SIZE]; + struct sixel_source source; const u_char *pixel; uint16_t *cache; int *current, *next, *tmp; @@ -1024,14 +1040,19 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, uint64_t destination_width, destination_height; uint64_t content_width, content_height, x0, x1, y0, y1; - destination_width = (uint64_t)im->sx * xpixel; - destination_height = (uint64_t)im->sy * ypixel; + source.pixels = image_get_pixels(im, &source.stride, NULL); + image_get_dimensions(im, &source.width, &source.height); + image_get_canvas_dimensions(im, &source.canvas_width, + &source.canvas_height); + image_get_cell_dimensions(im, &source.sx, &source.sy); + destination_width = (uint64_t)source.sx * xpixel; + destination_height = (uint64_t)source.sy * ypixel; if (destination_width > UINT_MAX || destination_height > UINT_MAX) return (NULL); - content_width = ((uint64_t)im->width * destination_width + - im->canvas_width - 1) / im->canvas_width; - content_height = ((uint64_t)im->height * destination_height + - im->canvas_height - 1) / im->canvas_height; + content_width = ((uint64_t)source.width * destination_width + + source.canvas_width - 1) / source.canvas_width; + content_height = ((uint64_t)source.height * destination_height + + source.canvas_height - 1) / source.canvas_height; x0 = (uint64_t)ox * xpixel; y0 = (uint64_t)oy * ypixel; x1 = ((uint64_t)ox + cells_x) * xpixel; @@ -1055,7 +1076,7 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, histogram = xcalloc(SIXEL_HISTOGRAM_SIZE, sizeof *histogram); for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { - pixel = sixel_from_image_pixel(im, sourcex0, sourcey0, + pixel = sixel_from_image_pixel(&source, sourcex0, sourcey0, sourcewidth, sourceheight, sx, sy, x, y); if (pixel[3] < 128) continue; @@ -1095,7 +1116,7 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, next = xcalloc(((size_t)sx + 2) * 3, sizeof *next); for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { - pixel = sixel_from_image_pixel(im, sourcex0, sourcey0, + pixel = sixel_from_image_pixel(&source, sourcex0, sourcey0, sourcewidth, sourceheight, sx, sy, x, y); if (pixel[3] < 128) continue; @@ -1223,11 +1244,15 @@ sixel_geometry_changed(struct tty *tty) static struct sixel_image * sixel_render_image(struct image *im, u_int xpixel, u_int ypixel) { + struct sixel_image *original; + u_int sx, sy; + + image_get_cell_dimensions(im, &sx, &sy); /* Preserve SIXEL's original palette and indexed pixels when possible. */ - if (im->sixel != NULL) - return (sixel_scale(im->sixel, xpixel, ypixel, 0, 0, - im->sx, im->sy, 1)); - return (sixel_from_image(im, 0, 0, im->sx, im->sy, xpixel, ypixel)); + original = image_get_sixel(im); + if (original != NULL) + return (sixel_scale(original, xpixel, ypixel, 0, 0, sx, sy, 1)); + return (sixel_from_image(im, 0, 0, sx, sy, xpixel, ypixel)); } static struct sixel_image * @@ -1240,7 +1265,8 @@ sixel_get_image(struct tty *tty, struct image *im) sixel_collect_images(so); for (cache = so->images; cache != NULL; cache = cache->next) { - if (cache->server_id != im->id || cache->xpixel != tty->xpixel || + if (cache->server_id != image_get_id(im) || + cache->xpixel != tty->xpixel || cache->ypixel != tty->ypixel) continue; cache->age = ++so->age; @@ -1267,7 +1293,7 @@ sixel_get_image(struct tty *tty, struct image *im) sixel_remove_cache(so, oldest); } cache = xcalloc(1, sizeof *cache); - cache->server_id = im->id; + cache->server_id = image_get_id(im); cache->xpixel = tty->xpixel; cache->ypixel = tty->ypixel; cache->size = size; @@ -1301,13 +1327,16 @@ sixel_draw_rectangle(struct tty *tty, const struct image_rectangle *rectangle, struct sixel_image *si, *crop; char *data; size_t size; + u_int source_x, source_y, width, height; + u_int destination_x, destination_y; - si = sixel_get_image(tty, rectangle->image); + si = sixel_get_image(tty, image_rectangle_get_image(rectangle)); if (si == NULL) return; + image_rectangle_get_coordinates(rectangle, &source_x, &source_y, &width, + &height, &destination_x, &destination_y); crop = sixel_scale(si, tty->xpixel, tty->ypixel, - rectangle->source_x, rectangle->source_y, rectangle->width, - rectangle->height, 1); + source_x, source_y, width, height, 1); if (!sixel_image_is_cached(tty, si)) sixel_free(si); if (crop == NULL) @@ -1318,7 +1347,7 @@ sixel_draw_rectangle(struct tty *tty, const struct image_rectangle *rectangle, return; tty_region_off(tty); tty_margin_off(tty); - tty_cursor(tty, rectangle->destination_x, rectangle->destination_y); + tty_cursor(tty, destination_x, destination_y); tty->flags |= TTY_NOBLOCK; tty_putn(tty, data, size, 0); tty_invalidate(tty); diff --git a/image.c b/image.c index 5f41f7677..e9ca93dad 100644 --- a/image.c +++ b/image.c @@ -27,6 +27,60 @@ #include "tmux.h" +/* A protocol-neutral average of part of an image cell. RGB is premultiplied. */ +struct image_sample { + u_char red; + u_char green; + u_char blue; + u_char alpha; + u_char brightness; +}; + +/* Half blocks, quadrants and sextants all divide evenly into a 2 by 6 grid. */ +#define IMAGE_SAMPLE_COLUMNS 2 +#define IMAGE_SAMPLE_ROWS 6 +#define IMAGE_FLAG_NO_CURSOR 0x1 +struct image_cell { + struct image_sample whole; + struct image_sample samples[IMAGE_SAMPLE_ROWS][IMAGE_SAMPLE_COLUMNS]; +}; + +/* Immutable protocol-neutral image placement. */ +struct image { + u_int id; + u_int references; + u_int flags; + u_int parent_id; + u_int source_id; + u_int width; + u_int height; + u_int canvas_width; + u_int canvas_height; + u_int sx; + u_int sy; + size_t stride; + size_t size; + u_char *pixels; + /* Original indexed SIXEL data, if this image arrived as SIXEL. */ + struct sixel_image *sixel; + struct image_cell *cells; + + RB_ENTRY(image) entry; +}; +RB_HEAD(images, image); + +/* A cell-aligned part of an image to draw at a terminal position. */ +struct image_rectangle { + struct image *image; + struct grid_cell cell; + u_int source_x; + u_int source_y; + u_int width; + u_int height; + u_int destination_x; + u_int destination_y; +}; + static struct images images = RB_INITIALIZER(&images); static u_int image_next_id; @@ -210,6 +264,93 @@ image_find(u_int id) return (RB_FIND(images, &images, &find)); } +u_int +image_get_id(const struct image *im) +{ + return (im->id); +} + +void +image_get_dimensions(const struct image *im, u_int *width, u_int *height) +{ + if (width != NULL) + *width = im->width; + if (height != NULL) + *height = im->height; +} + +void +image_get_canvas_dimensions(const struct image *im, u_int *width, + u_int *height) +{ + if (width != NULL) + *width = im->canvas_width; + if (height != NULL) + *height = im->canvas_height; +} + +void +image_get_cell_dimensions(const struct image *im, u_int *sx, u_int *sy) +{ + if (sx != NULL) + *sx = im->sx; + if (sy != NULL) + *sy = im->sy; +} + +const u_char * +image_get_pixels(const struct image *im, size_t *stride, size_t *size) +{ + if (stride != NULL) + *stride = im->stride; + if (size != NULL) + *size = im->size; + return (im->pixels); +} + +void +image_set_no_cursor(struct image *im) +{ + im->flags |= IMAGE_FLAG_NO_CURSOR; +} + +struct sixel_image * +image_get_sixel(const struct image *im) +{ + return (im->sixel); +} + +void +image_set_sixel(struct image *im, struct sixel_image *si) +{ + im->sixel = si; +} + +struct image * +image_rectangle_get_image(const struct image_rectangle *rectangle) +{ + return (rectangle->image); +} + +const struct grid_cell * +image_rectangle_get_cell(const struct image_rectangle *rectangle) +{ + return (&rectangle->cell); +} + +void +image_rectangle_get_coordinates(const struct image_rectangle *rectangle, + u_int *source_x, u_int *source_y, u_int *width, u_int *height, + u_int *destination_x, u_int *destination_y) +{ + *source_x = rectangle->source_x; + *source_y = rectangle->source_y; + *width = rectangle->width; + *height = rectangle->height; + *destination_x = rectangle->destination_x; + *destination_y = rectangle->destination_y; +} + static struct image * image_create1(u_int width, u_int height, u_int canvas_width, u_int canvas_height, u_int sx, u_int sy, size_t stride, u_char *pixels) @@ -318,7 +459,7 @@ image_free(u_int id) free(im); } -const struct image_cell * +static const struct image_cell * image_get_cell(struct image *im, u_int x, u_int y) { if (im == NULL || x >= im->sx || y >= im->sy) diff --git a/input.c b/input.c index 1937dc8c5..58780d3c4 100644 --- a/input.c +++ b/input.c @@ -2844,10 +2844,10 @@ input_handle_kitty(struct input_ctx *ictx, const u_char *buf, size_t len) image_clear(sctx, replace_id); if (im != NULL) { if (action == 'd') - image_clear(sctx, im->id); + image_clear(sctx, image_get_id(im)); else image_write(sctx, im, ictx->cell.cell.bg); - image_free(im->id); + image_free(image_get_id(im)); if (quiet == 0 && image_id != 0) input_reply(ictx, 0, "\033_Gi=%u;OK\033\\", image_id); } else if (action == 'd' && image_id == 0) diff --git a/screen-write.c b/screen-write.c index 931e1847a..71a52255e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -3054,7 +3054,7 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si, return; } image_write(ctx, im, bg); - image_free(im->id); + image_free(image_get_id(im)); } #endif diff --git a/tmux.h b/tmux.h index 6724838a0..5d9336f90 100644 --- a/tmux.h +++ b/tmux.h @@ -1038,60 +1038,6 @@ struct style { }; #ifdef ENABLE_IMAGES -/* A protocol-neutral average of part of an image cell. RGB is premultiplied. */ -struct image_sample { - u_char red; - u_char green; - u_char blue; - u_char alpha; - u_char brightness; -}; - -/* Half blocks, quadrants and sextants all divide evenly into a 2 by 6 grid. */ -#define IMAGE_SAMPLE_COLUMNS 2 -#define IMAGE_SAMPLE_ROWS 6 -#define IMAGE_FLAG_NO_CURSOR 0x1 -struct image_cell { - struct image_sample whole; - struct image_sample samples[IMAGE_SAMPLE_ROWS][IMAGE_SAMPLE_COLUMNS]; -}; - -/* Immutable protocol-neutral image placement. */ -struct image { - u_int id; - u_int references; - u_int flags; - u_int parent_id; - u_int source_id; - u_int width; - u_int height; - u_int canvas_width; - u_int canvas_height; - u_int sx; - u_int sy; - size_t stride; - size_t size; - u_char *pixels; - /* Original indexed SIXEL data, if this image arrived as SIXEL. */ - struct sixel_image *sixel; - struct image_cell *cells; /* lazily generated text samples */ - - RB_ENTRY(image) entry; -}; -RB_HEAD(images, image); - -/* A cell-aligned part of an image to draw at a terminal position. */ -struct image_rectangle { - struct image *image; - struct grid_cell cell; - u_int source_x; - u_int source_y; - u_int width; - u_int height; - u_int destination_x; - u_int destination_y; -}; - #define IMAGE_SIZE_LIMIT (64 * 1024 * 1024) #endif @@ -4274,6 +4220,14 @@ struct image *image_create(u_int, u_int, u_int, u_int, u_int, u_int, struct image *image_create_view(struct image *, 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_dimensions(const struct image *, u_int *, u_int *); +void image_get_canvas_dimensions(const struct image *, u_int *, u_int *); +void image_get_cell_dimensions(const struct image *, u_int *, u_int *); +const u_char *image_get_pixels(const struct image *, size_t *, size_t *); +void image_set_no_cursor(struct image *); +struct sixel_image *image_get_sixel(const struct image *); +void image_set_sixel(struct image *, struct sixel_image *); void image_ref(u_int); void image_free(u_int); void image_set_cell(struct grid_cell *, struct image *, u_int, @@ -4297,10 +4251,14 @@ void image_tty_geometry_changed(struct tty *); void image_tty_free(struct tty *, int); void image_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, u_int, u_int, const struct tty_style_ctx *); -const struct image_cell *image_get_cell(struct image *, u_int, u_int); void image_get_fallback_cell(struct tty *, struct image *, u_int, u_int, const struct grid_cell *, struct grid_cell *, const struct tty_style_ctx *); +struct image *image_rectangle_get_image(const struct image_rectangle *); +const struct grid_cell *image_rectangle_get_cell( + const struct image_rectangle *); +void image_rectangle_get_coordinates(const struct image_rectangle *, + u_int *, u_int *, u_int *, u_int *, u_int *, u_int *); void image_clear(struct screen_write_ctx *, u_int); #define KITTY_PARSE_ERROR -1 #define KITTY_PARSE_OK 0 @@ -4315,15 +4273,15 @@ void kitty_draw_rectangle(struct tty *, const struct image_rectangle *, const struct tty_style_ctx *); void kitty_free_output(struct tty *, int); void kitty_geometry_changed(struct tty *); -void sixel_draw_rectangle(struct tty *, - const struct image_rectangle *, const struct tty_style_ctx *); -void sixel_free_output(struct tty *, int); -void sixel_geometry_changed(struct tty *); #endif #ifdef ENABLE_SIXEL /* image-sixel.c */ #define SIXEL_COLOUR_REGISTERS 1024 +void sixel_draw_rectangle(struct tty *, + const struct image_rectangle *, const struct tty_style_ctx *); +void sixel_free_output(struct tty *, int); +void sixel_geometry_changed(struct tty *); struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int); void sixel_free(struct sixel_image *); void sixel_log(struct sixel_image *);