Make image types opaque

This commit is contained in:
Michael Grant
2026-08-06 12:38:11 +01:00
parent d9ff36408c
commit 7c6f5d838f
5 changed files with 317 additions and 157 deletions

View File

@@ -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);

View File

@@ -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);

190
image.c
View File

@@ -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)

View File

@@ -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

77
tmux.h
View File

@@ -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 *);