From 7c6f5d838f648987cc33f157633effed453af5a7 Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Thu, 6 Aug 2026 12:38:11 +0100 Subject: [PATCH] Make image types opaque --- image-fallback.c | 86 +++++++++------------ image-sixel.c | 119 ++++++++++++++++++----------- image.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++- screen-write.c | 2 +- tmux.h | 77 ++++++------------- 5 files changed, 317 insertions(+), 157 deletions(-) diff --git a/image-fallback.c b/image-fallback.c index 25b3eac04..840b4217d 100644 --- a/image-fallback.c +++ b/image-fallback.c @@ -48,7 +48,7 @@ struct image_rgb { u_char b; }; -struct image_glyph_data { +struct image_fallback_data { u_char *shade5; u_char *shade8; }; @@ -235,28 +235,30 @@ image_glyph_block_key(enum image_glyph_detail detail, u_int mask) static u_char * image_glyph_make_shades(struct image *im, u_int levels) { - struct image_glyph_data *data = im->fallback_data; - const struct image_cell *cell; + struct image_fallback_data *data; int *values, value, represented, error; size_t cells, index; u_int x, y, scan, level, minimum = 255, maximum = 0; + u_int sx, sy; int reverse; u_char *result; + data = image_get_fallback_data(im); if (data == NULL) { - data = im->fallback_data = xcalloc(1, sizeof *data); + data = xcalloc(1, sizeof *data); + image_set_fallback_data(im, data); } result = (levels == 5 ? data->shade5 : data->shade8); if (result != NULL) return (result); - cells = (size_t)im->sx * im->sy; + image_get_cell_dimensions(im, &sx, &sy); + cells = (size_t)sx * sy; values = xcalloc(cells, sizeof *values); result = xcalloc(cells, 1); - for (y = 0; y < im->sy; y++) { - for (x = 0; x < im->sx; x++) { - index = (size_t)y * im->sx + x; - cell = image_get_cell(im, x, y); - value = cell->whole.brightness; + for (y = 0; y < sy; y++) { + for (x = 0; x < sx; x++) { + index = (size_t)y * sx + x; + value = image_get_brightness(im, x, y); if ((u_int)value < minimum) minimum = value; if ((u_int)value > maximum) @@ -269,11 +271,11 @@ image_glyph_make_shades(struct image *im, u_int levels) values[index] = (values[index] - minimum) * 255 / (maximum - minimum); } - for (y = 0; y < im->sy; y++) { + for (y = 0; y < sy; y++) { reverse = (y & 1); - for (scan = 0; scan < im->sx; scan++) { - x = (reverse ? im->sx - scan - 1 : scan); - index = (size_t)y * im->sx + x; + for (scan = 0; scan < sx; scan++) { + x = (reverse ? sx - scan - 1 : scan); + index = (size_t)y * sx + x; value = values[index]; if (value < 0) value = 0; @@ -283,21 +285,21 @@ image_glyph_make_shades(struct image *im, u_int levels) result[index] = level; represented = level * 255 / (levels - 1); error = value - represented; - if (!reverse && x + 1 < im->sx) + if (!reverse && x + 1 < sx) values[index + 1] += error * 7 / 16; if (reverse && x != 0) values[index - 1] += error * 7 / 16; - if (y + 1 == im->sy) + if (y + 1 == sy) continue; if (!reverse && x != 0) - values[index + im->sx - 1] += error * 3 / 16; - if (reverse && x + 1 < im->sx) - values[index + im->sx + 1] += error * 3 / 16; - values[index + im->sx] += error * 5 / 16; - if (!reverse && x + 1 < im->sx) - values[index + im->sx + 1] += error / 16; + values[index + sx - 1] += error * 3 / 16; + if (reverse && x + 1 < sx) + values[index + sx + 1] += error * 3 / 16; + values[index + sx] += error * 5 / 16; + if (!reverse && x + 1 < sx) + values[index + sx + 1] += error / 16; if (reverse && x != 0) - values[index + im->sx - 1] += error / 16; + values[index + sx - 1] += error / 16; } } free(values); @@ -346,10 +348,8 @@ image_glyph_block(struct tty *tty, struct image *im, u_int x, u_int y, enum image_glyph_detail detail, enum image_glyph_palette palette, struct grid_cell *out) { - const struct image_cell *cell = image_get_cell(im, x, y); struct image_rgb samples[6], centres[2], quantized[2]; - u_int columns, rows, sx, sy, ix, iy, i, n, mask; - u_int x0, x1, y0, y1, red, green, blue, count; + u_int columns, rows, sx, sy, i, n, mask; int colours[2]; u_char key; @@ -359,22 +359,8 @@ image_glyph_block(struct tty *tty, struct image *im, u_int x, u_int y, i = 0; for (sy = 0; sy < rows; sy++) { for (sx = 0; sx < columns; sx++) { - x0 = sx * IMAGE_SAMPLE_COLUMNS / columns; - x1 = (sx + 1) * IMAGE_SAMPLE_COLUMNS / columns; - y0 = sy * IMAGE_SAMPLE_ROWS / rows; - y1 = (sy + 1) * IMAGE_SAMPLE_ROWS / rows; - red = green = blue = count = 0; - for (iy = y0; iy < y1; iy++) { - for (ix = x0; ix < x1; ix++) { - red += cell->samples[iy][ix].red; - green += cell->samples[iy][ix].green; - blue += cell->samples[iy][ix].blue; - count++; - } - } - samples[i].r = red / count; - samples[i].g = green / count; - samples[i].b = blue / count; + image_get_cell_average(im, x, y, sx, sy, columns, rows, + &samples[i].r, &samples[i].g, &samples[i].b); i++; } } @@ -411,30 +397,25 @@ image_get_fallback_cell(struct tty *tty, struct image *im, u_int x, u_int y, TTY_ACS_IMAGE_SHADE_MEDIUM, TTY_ACS_IMAGE_SHADE_MEDIUM, TTY_ACS_IMAGE_SHADE_DARK, TTY_ACS_IMAGE_BLOCK, TTY_ACS_IMAGE_BLOCK }; - const struct image_cell *cell; enum image_glyph_palette palette; enum image_glyph_detail detail; u_char *levels, key; - u_int level = 0; + u_int level = 0, sx; memcpy(out, gc, sizeof *out); out->flags &= ~GRID_FLAG_IMAGE; - cell = image_get_cell(im, x, y); - if (cell == NULL) { - utf8_set(&out->data, ' '); - return; - } palette = image_glyph_get_palette(tty); detail = image_glyph_get_detail(tty, palette); if (detail == IMAGE_GLYPH_ASCII) { - level = cell->whole.brightness * (sizeof ascii - 2) / 255; + level = image_get_brightness(im, x, y) * (sizeof ascii - 2) / 255; utf8_set(&out->data, ascii[level]); return; } if (detail == IMAGE_GLYPH_SHADE5 || detail == IMAGE_GLYPH_SHADE8) { levels = image_glyph_make_shades(im, detail == IMAGE_GLYPH_SHADE5 ? 5 : 8); - level = levels[(size_t)y * im->sx + x]; + image_get_cell_dimensions(im, &sx, NULL); + level = levels[(size_t)y * sx + x]; key = (detail == IMAGE_GLYPH_SHADE5 ? shades[level] : bold_shades[level]); if (key == 0) @@ -455,8 +436,9 @@ image_get_fallback_cell(struct tty *tty, struct image *im, u_int x, u_int y, void image_free_fallback(struct image *im) { - struct image_glyph_data *data = im->fallback_data; + struct image_fallback_data *data; + data = image_get_fallback_data(im); if (data == NULL) return; free(data->shade5); diff --git a/image-sixel.c b/image-sixel.c index dc1c4e93a..5d872e1e8 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 * @@ -1012,6 +1027,7 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, u_int cells_y, u_int xpixel, u_int ypixel) { struct sixel_image *si; + struct sixel_source source; struct sixel_histogram *histogram, *entry; struct sixel_rgb palette[SIXEL_PALETTE_SIZE]; const u_char *pixel; @@ -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 53ac62d64..c197d7fdd 100644 --- a/image.c +++ b/image.c @@ -25,6 +25,57 @@ #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 +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 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 */ + struct image_fallback_data *fallback_data; + + 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; @@ -202,6 +253,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); +} + +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_fallback_data * +image_get_fallback_data(const struct image *im) +{ + return (im->fallback_data); +} + +void +image_set_fallback_data(struct image *im, struct image_fallback_data *data) +{ + im->fallback_data = data; +} + +struct image * +image_rectangle_get_image(const struct image_rectangle *rectangle) +{ + return (rectangle->image); +} + +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; +} + struct image * 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) @@ -273,7 +411,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) @@ -283,6 +421,53 @@ image_get_cell(struct image *im, u_int x, u_int y) return (&im->cells[(size_t)y * im->sx + x]); } +u_char +image_get_brightness(struct image *im, u_int x, u_int y) +{ + const struct image_cell *cell; + + cell = image_get_cell(im, x, y); + if (cell == NULL) + return (0); + return (cell->whole.brightness); +} + +void +image_get_cell_average(struct image *im, u_int x, u_int y, u_int part_x, + u_int part_y, u_int parts_x, u_int parts_y, u_char *red, u_char *green, + u_char *blue) +{ + const struct image_cell *cell; + u_int ix, iy, x0, x1, y0, y1, count; + u_int value_red, value_green, value_blue; + + *red = *green = *blue = 0; + if (parts_x == 0 || parts_y == 0 || part_x >= parts_x || + part_y >= parts_y) + return; + cell = image_get_cell(im, x, y); + if (cell == NULL) + return; + x0 = part_x * IMAGE_SAMPLE_COLUMNS / parts_x; + x1 = (part_x + 1) * IMAGE_SAMPLE_COLUMNS / parts_x; + y0 = part_y * IMAGE_SAMPLE_ROWS / parts_y; + y1 = (part_y + 1) * IMAGE_SAMPLE_ROWS / parts_y; + value_red = value_green = value_blue = count = 0; + for (iy = y0; iy < y1; iy++) { + for (ix = x0; ix < x1; ix++) { + value_red += cell->samples[iy][ix].red; + value_green += cell->samples[iy][ix].green; + value_blue += cell->samples[iy][ix].blue; + count++; + } + } + if (count == 0) + return; + *red = value_red / count; + *green = value_green / count; + *blue = value_blue / count; +} + void image_set_cell(struct grid_cell *gc, struct image *im, u_int x, u_int y) { @@ -452,10 +637,9 @@ image_write(struct screen_write_ctx *ctx, struct image *im, u_int bg) u_int cx = s->cx, cy = s->cy; u_int x, y, sx, sy, lines; - sx = im->sx; + image_get_cell_dimensions(im, &sx, &sy); if (sx > screen_size_x(s) - cx) sx = screen_size_x(s) - cx; - sy = im->sy; if (sy > screen_size_y(s) - 1) sy = screen_size_y(s) - 1; if (sx == 0 || sy == 0) diff --git a/screen-write.c b/screen-write.c index c11bf94ad..17d3a4752 100644 --- a/screen-write.c +++ b/screen-write.c @@ -3034,7 +3034,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 45bdf9b5e..5d15d0c0d 100644 --- a/tmux.h +++ b/tmux.h @@ -78,6 +78,7 @@ struct session; #ifdef ENABLE_IMAGES struct image; struct image_backend; +struct image_fallback_data; struct image_rectangle; #endif #ifdef ENABLE_SIXEL @@ -1060,57 +1061,6 @@ struct style { #define TTY_ACS_IMAGE_SEXTANT_FIRST 0x92 #define TTY_ACS_IMAGE_SEXTANT_LAST 0xcd -/* 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 -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 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 */ - void *fallback_data; - - 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 @@ -4291,6 +4241,19 @@ 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_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 *); +struct sixel_image *image_get_sixel(const struct image *); +void image_set_sixel(struct image *, struct sixel_image *); +u_char image_get_brightness(struct image *, u_int, u_int); +void image_get_cell_average(struct image *, u_int, u_int, u_int, u_int, + u_int, u_int, u_char *, u_char *, u_char *); +struct image_fallback_data *image_get_fallback_data(const struct image *); +void image_set_fallback_data(struct image *, + struct image_fallback_data *); void image_ref(u_int); void image_free(u_int); void image_set_cell(struct grid_cell *, struct image *, u_int, @@ -4311,20 +4274,22 @@ 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 *); void image_free_fallback(struct image *); -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 image *image_rectangle_get_image(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 *); #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 *);