mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-20 03:25:47 +00:00
sixel: combine ctable/dtable extraction passes, cuts 80% of runtime #1380
This commit is contained in:
parent
43b3724f07
commit
e3ede498b6
134
src/lib/sixel.c
134
src/lib/sixel.c
@ -8,81 +8,101 @@ break_sixel_comps(unsigned char comps[static 3], uint32_t rgba, unsigned char ma
|
||||
//fprintf(stderr, "%u %u %u\n", comps[0], comps[1], comps[2]);
|
||||
}
|
||||
|
||||
// FIXME you can have more (or fewer) than 256 registers...detect?
|
||||
#define MAXCOLORS 256
|
||||
|
||||
// first pass: extract up to 256 sixelspace colors over arbitrarily many sixels
|
||||
// sixelspace is 0..100 corresponding to 0..255, lame =[
|
||||
// FIXME you can have more (or fewer) than 256 registers...detect?
|
||||
typedef struct colortable {
|
||||
int colors;
|
||||
int sixelcount;
|
||||
unsigned char table[3 * 256];
|
||||
unsigned char table[5 * MAXCOLORS]; // components + dtable index
|
||||
} colortable;
|
||||
|
||||
// second pass: construct data for extracted colors over the sixels
|
||||
typedef struct sixeltable {
|
||||
const colortable* ctab;
|
||||
colortable* ctab;
|
||||
unsigned char* data; // |colors|x|sixelcount|-byte arrays
|
||||
} sixeltable;
|
||||
|
||||
// returns the index at which the provided color can be found, possibly
|
||||
// inserting it into the table. returns -1 if the color is not in the
|
||||
// table and the table is full.
|
||||
static inline int
|
||||
ctable_to_dtable(const unsigned char* ctable){
|
||||
return ctable[3] * 256 + ctable[4];
|
||||
}
|
||||
|
||||
static inline void
|
||||
dtable_to_ctable(int dtable, unsigned char* ctable){
|
||||
ctable[3] = dtable / 256;
|
||||
ctable[4] = dtable % 256;
|
||||
}
|
||||
|
||||
// returns the index at which the provided color can be found *in the
|
||||
// dtable*, possibly inserting it into the ctable. returns -1 if the
|
||||
// color is not in the table and the table is full.
|
||||
// FIXME switch to binary search, duh
|
||||
// FIXME replace all these 3s with sizeof(comps)
|
||||
// FIXME replace all these 3s and 5s
|
||||
static int
|
||||
find_color(colortable* ctab, unsigned char comps[static 3]){
|
||||
int i;
|
||||
for(i = 0 ; i < ctab->colors ; ++i){
|
||||
int cmp = memcmp(ctab->table + i * 3, comps, 3);
|
||||
int cmp = memcmp(ctab->table + i * 5, comps, 3);
|
||||
if(cmp == 0){
|
||||
return i;
|
||||
return ctable_to_dtable(ctab->table + i * 5);
|
||||
}else if(cmp > 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ctab->colors == sizeof(ctab->table) / 3){
|
||||
if(ctab->colors == MAXCOLORS){
|
||||
return -1;
|
||||
}
|
||||
if(i < ctab->colors){
|
||||
memmove(ctab->table + (i + 1) * 3, ctab->table + i * 3, (ctab->colors - i) * 3);
|
||||
memmove(ctab->table + (i + 1) * 5, ctab->table + i * 5, (ctab->colors - i) * 5);
|
||||
}
|
||||
memcpy(ctab->table + i * 3, comps, 3);
|
||||
memcpy(ctab->table + i * 5, comps, 3);
|
||||
dtable_to_ctable(ctab->colors, ctab->table + i * 5);
|
||||
++ctab->colors;
|
||||
return i;
|
||||
return ctab->colors - 1;
|
||||
//return ctable_to_dtable(ctab->table + i * 5);
|
||||
}
|
||||
|
||||
// rather inelegant preprocess of the entire image. colors are converted to the
|
||||
// 100x100x100 sixel colorspace, and built into a table. if there are more than
|
||||
// 256 converted colors, we (currently) reject it FIXME. ideally we'd do the
|
||||
// image piecemeal, allowing us to get complete color fidelity; barring that,
|
||||
// we'd have something sensibly quantize us down first FIXME. we ought do
|
||||
// MAXCOLORS converted colors, we (currently) reject it FIXME. ideally we'd do
|
||||
// the image piecemeal, allowing us to get complete color fidelity; barring
|
||||
// that, we'd have something sensibly quantize us down first FIXME. we ought do
|
||||
// everything in a single pass FIXME.
|
||||
// what do we do if every pixel is transparent (0 colors)? FIXME
|
||||
static int
|
||||
extract_ctable_inner(const uint32_t* data, int linesize, int begy, int begx,
|
||||
int leny, int lenx, colortable* ctab, unsigned char mask){
|
||||
int leny, int lenx, sixeltable* stab, unsigned char mask){
|
||||
int pos = 0;
|
||||
for(int visy = begy ; visy < (begy + leny) ; visy += 6){
|
||||
for(int visx = begx ; visx < (begx + lenx) ; visx += 1){
|
||||
for(int sy = visy ; sy < (begy + leny) && sy < visy + 6 ; ++sy){
|
||||
const uint32_t* rgb = (const uint32_t*)(data + (linesize / 4 * sy) + (visx));
|
||||
const uint32_t* rgb = (const uint32_t*)(data + (linesize / 4 * sy) + visx);
|
||||
if(rgba_trans_p(ncpixel_a(*rgb))){
|
||||
continue;
|
||||
}
|
||||
unsigned char comps[3];
|
||||
break_sixel_comps(comps, *rgb, mask);
|
||||
if(find_color(ctab, comps) < 0){
|
||||
int c = find_color(stab->ctab, comps);
|
||||
if(c < 0){
|
||||
//fprintf(stderr, "FAILED FINDING COLOR AUGH 0x%02x\n", mask);
|
||||
return -1;
|
||||
}
|
||||
stab->data[c * stab->ctab->sixelcount + pos] |= (1u << (sy - visy));
|
||||
//fprintf(stderr, "color %d pos %d: 0x%x\n", c, pos, stab->data[c * stab->ctab->sixelcount + pos]);
|
||||
}
|
||||
++ctab->sixelcount;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
initialize_ctable(colortable* ctab){
|
||||
ctab->colors = 0;
|
||||
ctab->sixelcount = 0;
|
||||
initialize_stable(sixeltable* stab){
|
||||
stab->ctab->colors = 0;
|
||||
memset(stab->data, 0, stab->ctab->sixelcount * MAXCOLORS);
|
||||
}
|
||||
|
||||
// Use as many of the original colors as we can, but not more than will fit
|
||||
@ -91,11 +111,11 @@ initialize_ctable(colortable* ctab){
|
||||
// progressively mask more out until they all fit.
|
||||
static int
|
||||
extract_color_table(const uint32_t* data, int linesize, int begy, int begx,
|
||||
int leny, int lenx, colortable* ctab, unsigned char* mask){
|
||||
int leny, int lenx, sixeltable* stab, unsigned char* mask){
|
||||
*mask = 0xff;
|
||||
while(mask){
|
||||
initialize_ctable(ctab);
|
||||
if(extract_ctable_inner(data, linesize, begy, begx, leny, lenx, ctab, *mask) == 0){
|
||||
initialize_stable(stab);
|
||||
if(extract_ctable_inner(data, linesize, begy, begx, leny, lenx, stab, *mask) == 0){
|
||||
return 0;
|
||||
}
|
||||
*mask <<= 1;
|
||||
@ -104,41 +124,6 @@ extract_color_table(const uint32_t* data, int linesize, int begy, int begx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Having assembled the color table, build the raw sixels.
|
||||
static int
|
||||
extract_data_table(const uint32_t* data, int linesize, int begy, int begx,
|
||||
int leny, int lenx, sixeltable* stab, unsigned char mask){
|
||||
//fprintf(stderr, "colors: %d sixelcount: %d\n", stab->ctab->colors, stab->ctab->sixelcount);
|
||||
for(int c = 0 ; c < stab->ctab->colors ; ++c){
|
||||
int pos = 0;
|
||||
//fprintf(stderr, "dimy/x: %d/%d placey/x: %d/%d begyx: %d/%d lenyx: %d/%d\n", dimy, dimx, placey, placex, begy, begx, leny, lenx);
|
||||
for(int visy = begy ; visy < (begy + leny) ; visy += 6){
|
||||
for(int visx = begx ; visx < (begx + lenx) ; visx += 1){
|
||||
//fprintf(stderr, "handling sixel %d for color %d visy: %d\n", pos, c, visy);
|
||||
for(int sy = visy ; sy < (begy + leny) && sy < visy + 6 ; ++sy){
|
||||
const uint32_t* rgb = (const uint32_t*)(data + (linesize / 4 * sy) + visx);
|
||||
//fprintf(stderr, "%p: %08x\n", rgb, *rgb);
|
||||
if(rgba_trans_p(ncpixel_a(*rgb))){
|
||||
//fprintf(stderr, "transparent\n");
|
||||
continue;
|
||||
}
|
||||
unsigned char comps[3];
|
||||
break_sixel_comps(comps, *rgb, mask);
|
||||
//fprintf(stderr, "%d/%d/%d\n", comps[0], comps[1], comps[2]);
|
||||
if(memcmp(comps, stab->ctab->table + c * 3, 3) == 0){
|
||||
stab->data[c * stab->ctab->sixelcount + pos] |= (1u << (sy - visy));
|
||||
//fprintf(stderr, "%d ", c * stab->ctab->sixelcount + pos);
|
||||
//fputc(stab->data[c * stab->ctab->sixelcount + pos] + 63, stderr);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "color %d pos %d: %u\n", c, pos, stab->data[c * stab->ctab->sixelcount + pos]);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emit some number of equivalent, subsequent sixels, using sixel RLE. We've
|
||||
// seen the sixel |crle| for |seenrle| columns in a row. |seenrle| must > 0.
|
||||
static int
|
||||
@ -165,7 +150,7 @@ static int
|
||||
write_sixel_data(FILE* fp, int lenx, sixeltable* stab){
|
||||
fprintf(fp, "\e[?80h\ePq"); // FIXME pixelon
|
||||
for(int i = 0 ; i < stab->ctab->colors ; ++i){
|
||||
const unsigned char* rgb = stab->ctab->table + i * 3;
|
||||
const unsigned char* rgb = stab->ctab->table + i * 5;
|
||||
fprintf(fp, "#%d;2;%u;%u;%u", i, rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
int p = 0;
|
||||
@ -174,20 +159,21 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab){
|
||||
fprintf(fp, "#%d", i);
|
||||
int seenrle = 0;
|
||||
unsigned char crle = 0;
|
||||
int idx = ctable_to_dtable(stab->ctab->table + i * 5);
|
||||
for(int m = p ; m < stab->ctab->sixelcount && m < p + lenx ; ++m){
|
||||
//fprintf(stderr, "%d ", i * stab->ctab->sixelcount + m);
|
||||
//fputc(stab->data[i * stab->ctab->sixelcount + m] + 63, stderr);
|
||||
//fprintf(stderr, "%d ", idx * stab->ctab->sixelcount + m);
|
||||
//fputc(stab->data[idx * stab->ctab->sixelcount + m] + 63, stderr);
|
||||
if(seenrle){
|
||||
if(stab->data[i * stab->ctab->sixelcount + m] == crle){
|
||||
if(stab->data[idx * stab->ctab->sixelcount + m] == crle){
|
||||
++seenrle;
|
||||
}else{
|
||||
write_rle(fp, seenrle, crle);
|
||||
seenrle = 1;
|
||||
crle = stab->data[i * stab->ctab->sixelcount + m];
|
||||
crle = stab->data[idx * stab->ctab->sixelcount + m];
|
||||
}
|
||||
}else{
|
||||
seenrle = 1;
|
||||
crle = stab->data[i * stab->ctab->sixelcount + m];
|
||||
crle = stab->data[idx * stab->ctab->sixelcount + m];
|
||||
}
|
||||
}
|
||||
write_rle(fp, seenrle, crle);
|
||||
@ -240,23 +226,19 @@ int sixel_blit(ncplane* nc, int placey, int placex, int linesize,
|
||||
if(ctab == NULL){
|
||||
return -1;
|
||||
}
|
||||
unsigned char mask;
|
||||
if(extract_color_table(data, linesize, begy, begx, leny, lenx, ctab, &mask)){
|
||||
free(ctab);
|
||||
return -1;
|
||||
}
|
||||
ctab->sixelcount = (lenx - begx) * ((leny - begy + 5) / 6);
|
||||
sixeltable stable = {
|
||||
.ctab = ctab,
|
||||
.data = malloc(ctab->colors * ctab->sixelcount),
|
||||
.data = malloc(MAXCOLORS * ctab->sixelcount),
|
||||
};
|
||||
if(stable.data == NULL){
|
||||
free(ctab);
|
||||
return -1;
|
||||
}
|
||||
memset(stable.data, 0, ctab->colors * ctab->sixelcount);
|
||||
if(extract_data_table(data, linesize, begy, begx, leny, lenx, &stable, mask)){
|
||||
free(stable.data);
|
||||
unsigned char mask;
|
||||
if(extract_color_table(data, linesize, begy, begx, leny, lenx, &stable, &mask)){
|
||||
free(ctab);
|
||||
free(stable.data);
|
||||
return -1;
|
||||
}
|
||||
int r = sixel_blit_inner(nc, placey, placex, lenx, &stable, cellpixx);
|
||||
|
Loading…
Reference in New Issue
Block a user