diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 8f4062224..7d37daf94 100644 --- a/src/lib/sixel.c +++ b/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);