[sixel] kill FIXME about setting p2 on reblit

This commit is contained in:
nick black 2021-12-25 22:01:13 -05:00 committed by nick black
parent 6bc9e9f7f3
commit 62fc112bf0

View File

@ -2,7 +2,8 @@
#include "fbuf.h"
#define RGBSIZE 3
#define CENTSIZE (RGBSIZE + 1) // size of a color table entry
// size of a color table entry: three components and a dtable index
#define CENTSIZE (RGBSIZE + 1)
// we set P2 based on whether there is any transparency in the sixel. if not,
// use SIXEL_P2_ALLOPAQUE (0), for faster drawing in certain terminals.
@ -49,8 +50,11 @@ sixel_auxiliary_vector(const sprixel* s){
typedef struct sixelmap {
int colors;
int sixelcount;
// for each color, for each sixel (stack of six), the representation
unsigned char* data; // |colors| x |sixelcount|-byte arrays
// for each color, the components and an index into the dtable
unsigned char* table; // |colors| x CENTSIZE: components + dtable index
sixel_p2_e p2; // set to SIXEL_P2_TRANS if we have transparent pixels
} sixelmap;
// whip up an all-zero sixelmap for the specified pixel geometry and color
@ -60,6 +64,7 @@ static sixelmap*
sixelmap_create(int cregs, int dimy, int dimx){
sixelmap* ret = malloc(sizeof(*ret));
if(ret){
ret->p2 = SIXEL_P2_ALLOPAQUE,
ret->sixelcount = sixelcount(dimy, dimx);
if(ret->sixelcount){
size_t dsize = sizeof(*ret->data) * cregs * ret->sixelcount;
@ -117,19 +122,34 @@ void sixelmap_free(sixelmap *s){
typedef struct cdetails {
int64_t sums[3]; // sum of components of all matching original colors
int32_t count; // count of pixels matching
char hi[RGBSIZE]; // highest sixelspace components we've seen
char lo[RGBSIZE]; // lowest sixelspace color we've seen
unsigned char hi[RGBSIZE]; // highest sixelspace components we've seen
unsigned char lo[RGBSIZE]; // lowest sixelspace color we've seen
} cdetails;
// second pass: construct data for extracted colors over the sixels
// second pass: construct data for extracted colors over the sixels. the
// map will be persisted in the sprixel; the remainder is lost.
typedef struct sixeltable {
sixelmap* map; // copy of palette indices / transparency bits
// FIXME keep these internal to palette extraction; finalize there
cdetails* deets; // |colorregs| cdetails structures
int colorregs;
sixel_p2_e p2; // set to SIXEL_P2_TRANS if we have transparent pixels
} sixeltable;
static inline int
ctable_to_dtable(const unsigned char* ctable){
return ctable[3]; // * 256 + ctable[4];
}
static void
debug_color_table(const sixeltable* st){
for(int z = 0 ; z < st->map->colors ; ++z){
const cdetails* d = &st->deets[z];
unsigned char* crec = st->map->table + CENTSIZE * z;
int didx = ctable_to_dtable(crec);
fprintf(stderr, "[%03d->%d] %"PRId32" hi %u/%u/%u lo %u/%u/%u\n", z, didx, d->count,
d->hi[0], d->hi[1], d->hi[2], d->lo[0], d->lo[1], d->lo[2]);
}
}
// the P2 parameter on a sixel specifies how unspecified pixels are drawn.
// if P2 is 1, unspecified pixels are transparent. otherwise, they're drawn
// as something else. some terminals (e.g. foot) can draw more quickly if
@ -155,11 +175,6 @@ break_sixel_comps(unsigned char comps[static RGBSIZE], uint32_t rgba, unsigned c
//fprintf(stderr, "%u %u %u\n", comps[0], comps[1], comps[2]);
}
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;
@ -455,7 +470,7 @@ extract_color_table(const uint32_t* data, int linesize, int cols,
}else if(tam[txyidx].state == SPRIXCELL_OPAQUE_SIXEL){
tam[txyidx].state = SPRIXCELL_MIXED_SIXEL;
}
stab->p2 = SIXEL_P2_TRANS; // even one forces P2=1
stab->map->p2 = SIXEL_P2_TRANS; // even one forces P2=1
}else{
if(firstpix){
update_rmatrix(rmatrix, txyidx, tam);
@ -481,7 +496,7 @@ extract_color_table(const uint32_t* data, int linesize, int cols,
}
tam[txyidx].state = SPRIXCELL_ANNIHILATED;
}
stab->p2 = SIXEL_P2_TRANS; // even one forces P2=1
stab->map->p2 = SIXEL_P2_TRANS; // even one forces P2=1
}
if(lastrow){
bool lastcol = visx + 1 >= begx + lenx;
@ -500,12 +515,14 @@ extract_color_table(const uint32_t* data, int linesize, int cols,
unsigned char comps[RGBSIZE];
break_sixel_comps(comps, *rgb, mask);
int c = find_color(stab, comps);
fprintf(stderr, "FOUND COLOR %d %u %u %u (orig 0x%08x)\n", c, comps[0], comps[1], comps[2], *rgb);
if(c < 0){
//fprintf(stderr, "FAILED FINDING COLOR AUGH 0x%02x\n", mask);
return -1;
}
stab->map->data[c * stab->map->sixelcount + pos] |= (1u << (sy - visy));
update_deets(*rgb, &stab->deets[c]);
debug_color_table(stab);
//fprintf(stderr, "color %d pos %d: 0x%x\n", c, pos, stab->data[c * stab->map->sixelcount + pos]);
//fprintf(stderr, " sums: %u %u %u count: %d r/g/b: %u %u %u\n", stab->deets[c].sums[0], stab->deets[c].sums[1], stab->deets[c].sums[2], stab->deets[c].count, ncpixel_r(*rgb), ncpixel_g(*rgb), ncpixel_b(*rgb));
}
@ -558,13 +575,15 @@ unzip_color(const uint32_t* data, int linesize, int begy, int begx,
}
// relax segment |coloridx|. we must have room for a new color. we find the
// biggest component gap, and split our color entry in half there. we know
// the elements can't go into any preexisting color entry, so the only
// biggest component gap, and split our color entry between lo and hi there.
// we know the elements can't go into any preexisting color entry, so the only
// choices are staying where they are, or going to the new one. "unzip" the
// sixels from the data table by looking back to the sources and classifying
// them in one or the other centry. rebuild our sums, sixels, hi/lo, and
// counts as we do so. anaphase, baybee! target always gets the upper range.
// returns 1 if we did a refinement, 0 otherwise.
// it's important to use the lo and hi because those correspond to real colors
// from the image, whereas an average might not apply to anything.
static int
refine_color(const uint32_t* data, int linesize, int begy, int begx,
int leny, int lenx, sixeltable* stab, int color){
@ -603,6 +622,7 @@ refine_color(const uint32_t* data, int linesize, int begy, int begx,
static void
refine_color_table(const uint32_t* data, int linesize, int begy, int begx,
int leny, int lenx, sixeltable* stab){
debug_color_table(stab);
while(stab->map->colors < stab->colorregs){
bool refined = false;
int tmpcolors = stab->map->colors; // force us to come back through
@ -610,11 +630,11 @@ refine_color_table(const uint32_t* data, int linesize, int begy, int begx,
unsigned char* crec = stab->map->table + CENTSIZE * i;
int didx = ctable_to_dtable(crec);
cdetails* deets = stab->deets + didx;
//fprintf(stderr, "[%d->%d] hi: %d %d %d lo: %d %d %d\n", i, didx, deets->hi[0], deets->hi[1], deets->hi[2], deets->lo[0], deets->lo[1], deets->lo[2]);
fprintf(stderr, "[%d->%d] hi: %d %d %d lo: %d %d %d\n", i, didx, deets->hi[0], deets->hi[1], deets->hi[2], deets->lo[0], deets->lo[1], deets->lo[2]);
if(deets->count > leny * lenx / stab->colorregs){
if(refine_color(data, linesize, begy, begx, leny, lenx, stab, i)){
if(stab->map->colors == stab->colorregs){
//fprintf(stderr, "filled table!\n");
fprintf(stderr, "filled table!\n");
break;
}
refined = true;
@ -740,12 +760,12 @@ write_sixel_creg(fbuf* f, int idx, int rc, int gc, int bc){
// future reencodings. |leny| and |lenx| are output pixel geometry.
// returns the number of bytes written, so it can be stored at *parse_start.
static int
write_sixel_header(fbuf* f, int leny, int lenx, const sixeltable* stab, sixel_p2_e p2){
write_sixel_header(fbuf* f, int leny, int lenx, const sixeltable* stab){
if(leny % 6){
return -1;
}
// Set Raster Attributes - pan/pad=1 (pixel aspect ratio), Ph=lenx, Pv=leny
int r = write_sixel_intro(f, p2, leny, lenx);
int r = write_sixel_intro(f, stab->map->p2, leny, lenx);
if(r < 0){
return -1;
}
@ -821,9 +841,8 @@ write_sixel_payload(fbuf* f, int lenx, const sixelmap* map){
// constant, and is simply copied. fclose()s |fp| on success. |outx| and |outy|
// are output geometry.
static int
write_sixel(fbuf* f, int outy, int outx, const sixeltable* stab,
int* parse_start, sixel_p2_e p2){
*parse_start = write_sixel_header(f, outy, outx, stab, p2);
write_sixel(fbuf* f, int outy, int outx, const sixeltable* stab, int* parse_start){
*parse_start = write_sixel_header(f, outy, outx, stab);
if(*parse_start < 0){
return -1;
}
@ -856,8 +875,8 @@ sixel_reblit(sprixel* s){
return -1;
}
fbuf_free(&s->glyph);
// FIXME update P2 if necessary
memcpy(&s->glyph, &f, sizeof(f));
change_p2(s->glyph.buf, s->smap->p2);
return 0;
}
@ -880,10 +899,10 @@ sixel_blit_inner(int leny, int lenx, sixeltable* stab, const blitterargs* bargs,
int outy = leny;
if(leny % 6){
outy += 6 - (leny % 6);
stab->p2 = SIXEL_P2_TRANS;
stab->map->p2 = SIXEL_P2_TRANS;
}
// calls fclose() on success
if(write_sixel(&f, outy, lenx, stab, &parse_start, stab->p2)){
if(write_sixel(&f, outy, lenx, stab, &parse_start)){
fbuf_free(&f);
return -1;
}
@ -912,7 +931,6 @@ int sixel_blit(ncplane* n, int linesize, const void* data, int leny, int lenx,
.map = sixelmap_create(colorregs, leny - bargs->begy, lenx - bargs->begx),
.deets = malloc(colorregs * sizeof(cdetails)),
.colorregs = colorregs,
.p2 = SIXEL_P2_ALLOPAQUE,
};
if(stable.deets == NULL || stable.map == NULL){
sixelmap_free(stable.map);