From f96713d18f47c3f6f258883f137e044928a5ff5f Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 30 Jan 2022 05:42:15 -0500 Subject: [PATCH] [sixel] sparse band extension #2573 --- src/lib/sixel.c | 73 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 64350df3d..3875e3a9e 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -89,6 +89,7 @@ sixelband_free(sixelband* s){ for(int j = 0 ; j < s->size ; ++j){ free(s->vecs[j]); } + free(s->vecs); } void sixelmap_free(sixelmap *s){ @@ -712,19 +713,65 @@ load_color_table(const qstate* qs){ assert(loaded == qs->stab->map->colors); } +struct band_extender { + int length; // current length of the vector + int next; // next x location we will cover with a write +}; + +// add the supplied rle section to the appropriate vector, which might +// need to be created. +static inline int +sixelband_extend(sixelband* b, struct band_extender* bes, int maxlen, + int color, int rep, int rle, int curx){ + assert(maxlen >= rle); + assert(0 < rle); + assert(b->size > color); + assert(0 < rep); + assert(64 > rep); + struct band_extender* ourbes = &bes[color]; + if(b->vecs[color] == NULL){ + // FIXME for now we make it as big as it could possibly need to be + if((b->vecs[color] = malloc(maxlen + 1)) == NULL){ + return -1; + } + ourbes->length = 0; + ourbes->next = 0; + } + int clearlen = (curx - rle + 1) - ourbes->next; + if(clearlen > 2){ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "!%d?", clearlen); + }else if(clearlen == 2){ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "??"); + }else if(clearlen){ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "?"); + } + rep += 63; + if(rle > 2){ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "!%d%c", rle, rep); + }else if(rle == 2){ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "%c%c", rep, rep); + }else{ + ourbes->length += sprintf(b->vecs[color] + ourbes->length, "%c", rep); + } + ourbes->next = curx + 1; + return 0; +} + // build up a sixel band from (up to) 6 rows of the source RGBA. static inline int build_sixel_band(qstate* qs, int i){ sixelband* b = &qs->stab->map->bands[i]; - size_t bsize = sizeof(*b->vecs) * qs->stab->map->colors; + b->size = qs->stab->map->colors; + size_t bsize = sizeof(*b->vecs) * b->size; b->vecs = malloc(bsize); if(b->vecs == NULL){ return -1; } memset(b->vecs, 0, bsize); + struct band_extender* meta = malloc(qs->stab->map->colors * sizeof(*meta)); const int ystart = qs->bargs->begy + i * 6; - const int endy = i + 1 == qs->stab->map->sixelbands ? - qs->leny - (i * 6) : qs->bargs->begy + 6; + const int endy = (i + 1 == qs->stab->map->sixelbands ? + qs->leny - (i * 6) : ystart + 6); struct { int color; // color, -1 for unused int rep; // representation, 0..63 @@ -736,7 +783,8 @@ build_sixel_band(qstate* qs, int i){ } int prevactive = 0; // we're going to advance horizontally through the sixelband - for(int x = qs->bargs->begx ; x < (qs->bargs->begx + qs->lenx) ; ++x){ // pixel column + int x; + for(x = qs->bargs->begx ; x < (qs->bargs->begx + qs->lenx) ; ++x){ // pixel column // there are at most 6 colors represented in any given sixel. similarly, // there were at most 6 colors in the previous sixel, each with some 6-bit // representation. at each sixel, we need to *start tracking* new colors, @@ -767,6 +815,7 @@ build_sixel_band(qstate* qs, int i){ if(act == activepos){ // didn't find it; create new entry active[activepos].color = cidx; active[activepos].rep = (1u << (y - ystart)); + active[activepos].rle = 1; ++activepos; } } @@ -775,6 +824,7 @@ build_sixel_band(qstate* qs, int i){ int check = 0; while(check < prevactive){ int targ; + bool found = false; for(targ = 0 ; targ < activepos ; ++targ){ if(active[targ].color == prev[check].color && active[targ].rep == prev[check].rep){ // found it! extend our rle and wipe this one from the active set @@ -786,16 +836,17 @@ build_sixel_band(qstate* qs, int i){ active[targ].rle = 1; } --activepos; + found = true; break; } } - if(targ == activepos){ // didn't find it; finalize it - // FIXME write me out to vector + if(!found){ // didn't find it; finalize it + sixelband_extend(b, meta, qs->lenx, prev[check].color, prev[check].rep, prev[check].rle, x); if(check + 1 < prevactive){ // swap source with the top of the previous set - prev[targ].color = prev[prevactive - 1].color; - prev[targ].rep = prev[prevactive - 1].rep; - prev[targ].rle = prev[prevactive - 1].rle; + prev[check].color = prev[prevactive - 1].color; + prev[check].rep = prev[prevactive - 1].rep; + prev[check].rle = prev[prevactive - 1].rle; } --prevactive; }else{ @@ -825,6 +876,10 @@ build_sixel_band(qstate* qs, int i){ } prevactive += activepos; } + for(int j = 0 ; j < prevactive ; ++j){ + sixelband_extend(b, meta, qs->lenx, prev[j].color, prev[j].rep, prev[j].rle, x); + } + free(meta); return 0; }