mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +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:
		
							
								
								
									
										131
									
								
								image-sixel.c
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								image-sixel.c
									
									
									
									
									
								
							@@ -52,6 +52,19 @@ struct sixel_image {
 | 
			
		||||
	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
 | 
			
		||||
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 *
 | 
			
		||||
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;
 | 
			
		||||
	u_int			*colours, ncolours, i, c, x, y, count;
 | 
			
		||||
	struct sixel_line	*sl;
 | 
			
		||||
	u_int			*colours, ncolours, i, c, y, *active, nactive;
 | 
			
		||||
	struct sixel_chunk	*chunks, *chunk;
 | 
			
		||||
 | 
			
		||||
	if (map != NULL) {
 | 
			
		||||
		colours = map->colours;
 | 
			
		||||
@@ -514,7 +579,6 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
 | 
			
		||||
 | 
			
		||||
	if (ncolours == 0)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	contains = xcalloc(1, ncolours);
 | 
			
		||||
 | 
			
		||||
	len = 8192;
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chunks = xcalloc(ncolours, sizeof *chunks);
 | 
			
		||||
	active = xcalloc(ncolours, sizeof *active);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ncolours; i++) {
 | 
			
		||||
		c = colours[i];
 | 
			
		||||
		tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
 | 
			
		||||
		    i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
 | 
			
		||||
		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) {
 | 
			
		||||
		memset(contains, 0, ncolours);
 | 
			
		||||
		for (x = 0; x < si->x; x++) {
 | 
			
		||||
			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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		nactive = 0;
 | 
			
		||||
		sixel_print_compress_colors(si, chunks, y, active, &nactive);
 | 
			
		||||
 | 
			
		||||
		for (c = 0; c < ncolours; c++) {
 | 
			
		||||
			if (!contains[c])
 | 
			
		||||
				continue;
 | 
			
		||||
		for (i = 0; i < nactive; i++) {
 | 
			
		||||
			c = active[i];
 | 
			
		||||
			chunk = &chunks[c];
 | 
			
		||||
			tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
 | 
			
		||||
			sixel_print_add(&buf, &len, &used, tmp, tmplen);
 | 
			
		||||
 | 
			
		||||
			count = 0;
 | 
			
		||||
			for (x = 0; x < si->x; x++) {
 | 
			
		||||
				data = 0;
 | 
			
		||||
				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, chunk->data,
 | 
			
		||||
			    chunk->used);
 | 
			
		||||
			sixel_print_repeat(&buf, &len, &used, chunk->count,
 | 
			
		||||
			    chunk->pattern + 0x3f);
 | 
			
		||||
			sixel_print_add(&buf, &len, &used, "$", 1);
 | 
			
		||||
			chunk->used = chunk->next_x = chunk->count = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (buf[used - 1] == '$')
 | 
			
		||||
			used--;
 | 
			
		||||
		sixel_print_add(&buf, &len, &used, "-", 1);
 | 
			
		||||
	}
 | 
			
		||||
	if (buf[used - 1] == '$' || buf[used - 1] == '-')
 | 
			
		||||
	if (buf[used - 1] == '-')
 | 
			
		||||
		used--;
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		*size = used;
 | 
			
		||||
 | 
			
		||||
	free(contains);
 | 
			
		||||
	for (i = 0; i < ncolours; i++)
 | 
			
		||||
		free(chunks[i].data);
 | 
			
		||||
	free(active);
 | 
			
		||||
	free(chunks);
 | 
			
		||||
 | 
			
		||||
	return (buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user