[sixel] sparse band extension #2573

pull/2599/head
nick black 2 years ago committed by nick black
parent abbf36304d
commit f96713d18f

@ -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;
}

Loading…
Cancel
Save