mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Optimize sixel_print. Previously, the algorithm scanned each pixel several
times; once to find out which colors are active, and then once for every single active color to actually construct the output string. Now it constructs the compressed sixel patterns in the first pass (now x * 12 iters), so we can reduce the second pass (the really expensive part, at active colors * x * 6 iters) to just appending these to the output buffer. From nincsnevem662 at gmail dot com in GitHub issue 4184.
This commit is contained in:
parent
cb00e869ea
commit
8ff65230e1
131
image-sixel.c
131
image-sixel.c
@ -52,6 +52,19 @@ struct sixel_image {
|
|||||||
struct sixel_line *lines;
|
struct sixel_line *lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sixel_chunk {
|
||||||
|
u_int next_x;
|
||||||
|
u_int next_y;
|
||||||
|
|
||||||
|
u_int count;
|
||||||
|
char pattern;
|
||||||
|
char next_pattern;
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
size_t used;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
|
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
|
||||||
{
|
{
|
||||||
@ -496,13 +509,65 @@ sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sixel_print_compress_colors(struct sixel_image *si, struct sixel_chunk *chunks,
|
||||||
|
u_int y, u_int *active, u_int *nactive)
|
||||||
|
{
|
||||||
|
u_int i, x, c, dx, colors[6];
|
||||||
|
struct sixel_chunk *chunk = NULL;
|
||||||
|
struct sixel_line *sl;
|
||||||
|
|
||||||
|
for (x = 0; x < si->x; x++) {
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
colors[i] = 0;
|
||||||
|
if (y + i < si->y) {
|
||||||
|
sl = &si->lines[y + i];
|
||||||
|
if (x < sl->x && sl->data[x] != 0) {
|
||||||
|
colors[i] = sl->data[x];
|
||||||
|
c = sl->data[x] - 1;
|
||||||
|
chunks[c].next_pattern |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
if (colors[i] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
c = colors[i] - 1;
|
||||||
|
chunk = &chunks[c];
|
||||||
|
if (chunk->next_x == x + 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (chunk->next_y < y + 1) {
|
||||||
|
chunk->next_y = y + 1;
|
||||||
|
active[(*nactive)++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = x - chunk->next_x;
|
||||||
|
if (chunk->pattern != chunk->next_pattern || dx != 0) {
|
||||||
|
sixel_print_repeat(&chunk->data, &chunk->len,
|
||||||
|
&chunk->used, chunk->count,
|
||||||
|
chunk->pattern + 0x3f);
|
||||||
|
sixel_print_repeat(&chunk->data, &chunk->len,
|
||||||
|
&chunk->used, dx, '?');
|
||||||
|
chunk->pattern = chunk->next_pattern;
|
||||||
|
chunk->count = 0;
|
||||||
|
}
|
||||||
|
chunk->count++;
|
||||||
|
chunk->next_pattern = 0;
|
||||||
|
chunk->next_x = x + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
||||||
{
|
{
|
||||||
char *buf, tmp[64], *contains, data, last = 0;
|
char *buf, tmp[64];
|
||||||
size_t len, used = 0, tmplen;
|
size_t len, used = 0, tmplen;
|
||||||
u_int *colours, ncolours, i, c, x, y, count;
|
u_int *colours, ncolours, i, c, y, *active, nactive;
|
||||||
struct sixel_line *sl;
|
struct sixel_chunk *chunks, *chunk;
|
||||||
|
|
||||||
if (map != NULL) {
|
if (map != NULL) {
|
||||||
colours = map->colours;
|
colours = map->colours;
|
||||||
@ -514,7 +579,6 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|||||||
|
|
||||||
if (ncolours == 0)
|
if (ncolours == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
contains = xcalloc(1, ncolours);
|
|
||||||
|
|
||||||
len = 8192;
|
len = 8192;
|
||||||
buf = xmalloc(len);
|
buf = xmalloc(len);
|
||||||
@ -528,59 +592,42 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunks = xcalloc(ncolours, sizeof *chunks);
|
||||||
|
active = xcalloc(ncolours, sizeof *active);
|
||||||
|
|
||||||
for (i = 0; i < ncolours; i++) {
|
for (i = 0; i < ncolours; i++) {
|
||||||
c = colours[i];
|
c = colours[i];
|
||||||
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
|
||||||
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
|
||||||
|
chunk = &chunks[i];
|
||||||
|
chunk->len = 8;
|
||||||
|
chunk->data = xmalloc(chunk->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < si->y; y += 6) {
|
for (y = 0; y < si->y; y += 6) {
|
||||||
memset(contains, 0, ncolours);
|
nactive = 0;
|
||||||
for (x = 0; x < si->x; x++) {
|
sixel_print_compress_colors(si, chunks, y, active, &nactive);
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (y + i >= si->y)
|
|
||||||
break;
|
|
||||||
sl = &si->lines[y + i];
|
|
||||||
if (x < sl->x && sl->data[x] != 0)
|
|
||||||
contains[sl->data[x] - 1] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (c = 0; c < ncolours; c++) {
|
for (i = 0; i < nactive; i++) {
|
||||||
if (!contains[c])
|
c = active[i];
|
||||||
continue;
|
chunk = &chunks[c];
|
||||||
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
|
||||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||||
|
sixel_print_add(&buf, &len, &used, chunk->data,
|
||||||
count = 0;
|
chunk->used);
|
||||||
for (x = 0; x < si->x; x++) {
|
sixel_print_repeat(&buf, &len, &used, chunk->count,
|
||||||
data = 0;
|
chunk->pattern + 0x3f);
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (y + i >= si->y)
|
|
||||||
break;
|
|
||||||
sl = &si->lines[y + i];
|
|
||||||
if (x < sl->x && sl->data[x] == c + 1)
|
|
||||||
data |= (1 << i);
|
|
||||||
}
|
|
||||||
data += 0x3f;
|
|
||||||
if (data != last) {
|
|
||||||
sixel_print_repeat(&buf, &len, &used,
|
|
||||||
count, last);
|
|
||||||
last = data;
|
|
||||||
count = 1;
|
|
||||||
} else
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
sixel_print_repeat(&buf, &len, &used, count, data);
|
|
||||||
sixel_print_add(&buf, &len, &used, "$", 1);
|
sixel_print_add(&buf, &len, &used, "$", 1);
|
||||||
|
chunk->used = chunk->next_x = chunk->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[used - 1] == '$')
|
if (buf[used - 1] == '$')
|
||||||
used--;
|
used--;
|
||||||
sixel_print_add(&buf, &len, &used, "-", 1);
|
sixel_print_add(&buf, &len, &used, "-", 1);
|
||||||
}
|
}
|
||||||
if (buf[used - 1] == '$' || buf[used - 1] == '-')
|
if (buf[used - 1] == '-')
|
||||||
used--;
|
used--;
|
||||||
|
|
||||||
sixel_print_add(&buf, &len, &used, "\033\\", 2);
|
sixel_print_add(&buf, &len, &used, "\033\\", 2);
|
||||||
@ -589,7 +636,11 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|||||||
if (size != NULL)
|
if (size != NULL)
|
||||||
*size = used;
|
*size = used;
|
||||||
|
|
||||||
free(contains);
|
for (i = 0; i < ncolours; i++)
|
||||||
|
free(chunks[i].data);
|
||||||
|
free(active);
|
||||||
|
free(chunks);
|
||||||
|
|
||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user