mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
[sixel] track lowest/highest components for relaxation #1391
This commit is contained in:
parent
66e545f160
commit
14a39c3485
117
src/lib/sixel.c
117
src/lib/sixel.c
@ -1,44 +1,50 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#define RGBSIZE 3
|
#define RGBSIZE 3
|
||||||
// FIXME you can have more (or fewer) than 256 registers...detect?
|
#define CENTSIZE (RGBSIZE + 1) // size of a color table entry
|
||||||
#define MAXCOLORS 256
|
|
||||||
#define CENTSIZE (RGBSIZE + 2) // size of a color table entry
|
// take (8-bit rgb value & mask) to sixelspace [0..100]
|
||||||
|
static inline char
|
||||||
|
ss(unsigned rgb, unsigned char mask){
|
||||||
|
return (rgb & mask) * 100 / 255;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
break_sixel_comps(unsigned char comps[static RGBSIZE], uint32_t rgba, unsigned char mask){
|
break_sixel_comps(unsigned char comps[static RGBSIZE], uint32_t rgba, unsigned char mask){
|
||||||
comps[0] = (ncpixel_r(rgba) & mask) * 100 / 255;
|
comps[0] = ss(ncpixel_r(rgba), mask);
|
||||||
comps[1] = (ncpixel_g(rgba) & mask) * 100 / 255;
|
comps[1] = ss(ncpixel_g(rgba), mask);
|
||||||
comps[2] = (ncpixel_b(rgba) & mask) * 100 / 255;
|
comps[2] = ss(ncpixel_b(rgba), mask);
|
||||||
//fprintf(stderr, "%u %u %u\n", comps[0], comps[1], comps[2]);
|
//fprintf(stderr, "%u %u %u\n", comps[0], comps[1], comps[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct cdetails {
|
typedef struct cdetails {
|
||||||
int64_t sums[3]; // sum of components of all matching original colors
|
int64_t sums[3]; // sum of components of all matching original colors
|
||||||
int32_t count; // count of pixels matching
|
int32_t count; // count of pixels matching
|
||||||
unsigned char two_colors;// have we seen at least two colors?
|
char hi[RGBSIZE]; // highest sixelspace components we've seen
|
||||||
unsigned char r, g, b; // until two_colors is true, track one r/g/b
|
char lo[RGBSIZE]; // lowest sixelspace color we've seen
|
||||||
} cdetails;
|
} cdetails;
|
||||||
|
|
||||||
// second pass: construct data for extracted colors over the sixels
|
// second pass: construct data for extracted colors over the sixels
|
||||||
typedef struct sixeltable {
|
typedef struct sixeltable {
|
||||||
// FIXME keep these internal to palette extraction; finalize there
|
// FIXME keep these internal to palette extraction; finalize there
|
||||||
int colors;
|
int colors;
|
||||||
cdetails* deets; // |maxcolors| cdetails structures
|
cdetails* deets; // |colorregs| cdetails structures
|
||||||
unsigned char* data; // |maxcolors| x |sixelcount|-byte arrays
|
unsigned char* data; // |colorregs| x |sixelcount|-byte arrays
|
||||||
unsigned char* table; // |maxcolors| x CENTSIZE: components + dtable index
|
unsigned char* table; // |colorregs| x CENTSIZE: components + dtable index
|
||||||
int sixelcount;
|
int sixelcount;
|
||||||
|
int colorregs;
|
||||||
} sixeltable;
|
} sixeltable;
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ctable_to_dtable(const unsigned char* ctable){
|
ctable_to_dtable(const unsigned char* ctable){
|
||||||
return ctable[3] * 256 + ctable[4];
|
return ctable[3]; // * 256 + ctable[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
dtable_to_ctable(int dtable, unsigned char* ctable){
|
dtable_to_ctable(int dtable, unsigned char* ctable){
|
||||||
ctable[3] = dtable / 256;
|
ctable[3] = dtable;
|
||||||
ctable[4] = dtable % 256;
|
/*ctable[3] = dtable / 256;
|
||||||
|
ctable[4] = dtable % 256;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the index at which the provided color can be found *in the
|
// returns the index at which the provided color can be found *in the
|
||||||
@ -72,7 +78,7 @@ find_color(sixeltable* stab, unsigned char comps[static RGBSIZE]){
|
|||||||
}else{
|
}else{
|
||||||
i = l;
|
i = l;
|
||||||
}
|
}
|
||||||
if(stab->colors == MAXCOLORS){
|
if(stab->colors == stab->colorregs){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(i < stab->colors){
|
if(i < stab->colors){
|
||||||
@ -117,21 +123,33 @@ extract_color_table(const uint32_t* data, int linesize, int begy, int begx,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stab->data[c * stab->sixelcount + pos] |= (1u << (sy - visy));
|
stab->data[c * stab->sixelcount + pos] |= (1u << (sy - visy));
|
||||||
|
comps[0] = ss(ncpixel_r(*rgb), 0xff);
|
||||||
|
comps[1] = ss(ncpixel_g(*rgb), 0xff);
|
||||||
|
comps[2] = ss(ncpixel_b(*rgb), 0xff);
|
||||||
if(stab->deets[c].count == 0){
|
if(stab->deets[c].count == 0){
|
||||||
stab->deets[c].two_colors = false;
|
stab->deets[c].lo[0] = stab->deets[c].hi[0] = comps[0];
|
||||||
stab->deets[c].r = ncpixel_r(*rgb);
|
stab->deets[c].lo[1] = stab->deets[c].hi[1] = comps[1];
|
||||||
stab->deets[c].g = ncpixel_g(*rgb);
|
stab->deets[c].lo[2] = stab->deets[c].hi[2] = comps[2];
|
||||||
stab->deets[c].b = ncpixel_b(*rgb);
|
}else{
|
||||||
}else if(stab->deets[c].two_colors == false){
|
if(stab->deets[c].hi[0] < comps[0]){
|
||||||
if(stab->deets[c].r != ncpixel_r(*rgb) ||
|
stab->deets[c].hi[0] = comps[0];
|
||||||
stab->deets[c].g != ncpixel_g(*rgb) ||
|
}else if(stab->deets[c].lo[0] > comps[0]){
|
||||||
stab->deets[c].b != ncpixel_b(*rgb)){
|
stab->deets[c].lo[0] = comps[0];
|
||||||
stab->deets[c].two_colors = true;
|
}
|
||||||
|
if(stab->deets[c].hi[1] < comps[1]){
|
||||||
|
stab->deets[c].hi[1] = comps[1];
|
||||||
|
}else if(stab->deets[c].lo[1] > comps[1]){
|
||||||
|
stab->deets[c].lo[1] = comps[1];
|
||||||
|
}
|
||||||
|
if(stab->deets[c].hi[2] < comps[2]){
|
||||||
|
stab->deets[c].hi[2] = comps[2];
|
||||||
|
}else if(stab->deets[c].lo[2] > comps[2]){
|
||||||
|
stab->deets[c].lo[2] = comps[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stab->deets[c].sums[0] += ncpixel_r(*rgb);
|
stab->deets[c].sums[0] += comps[0];
|
||||||
stab->deets[c].sums[1] += ncpixel_g(*rgb);
|
stab->deets[c].sums[1] += comps[1];
|
||||||
stab->deets[c].sums[2] += ncpixel_b(*rgb);
|
stab->deets[c].sums[2] += comps[2];
|
||||||
++stab->deets[c].count;
|
++stab->deets[c].count;
|
||||||
//fprintf(stderr, "color %d pos %d: 0x%x\n", c, pos, stab->data[c * stab->sixelcount + pos]);
|
//fprintf(stderr, "color %d pos %d: 0x%x\n", c, pos, stab->data[c * stab->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));
|
//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));
|
||||||
@ -142,6 +160,39 @@ extract_color_table(const uint32_t* data, int linesize, int begy, int begx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// relax segment |coloridx|. we must have room for a new color.
|
||||||
|
static void
|
||||||
|
refine_color(const uint32_t* data, int linesize, int begy, int begx,
|
||||||
|
int leny, int lenx, sixeltable* stab, int color){
|
||||||
|
}
|
||||||
|
|
||||||
|
// relax the details down into free color registers
|
||||||
|
static void
|
||||||
|
refine_color_table(const uint32_t* data, int linesize, int begy, int begx,
|
||||||
|
int leny, int lenx, sixeltable* stab){
|
||||||
|
while(stab->colors < stab->colorregs){
|
||||||
|
bool refined = false;
|
||||||
|
for(int i = 0 ; i < stab->colors ; ++i){
|
||||||
|
unsigned char* crec = stab->table + CENTSIZE * i;
|
||||||
|
int didx = ctable_to_dtable(crec);
|
||||||
|
cdetails* deets = stab->deets + didx;
|
||||||
|
fprintf(stderr, "hi: %d %d %d lo: %d %d %d\n", deets->hi[0], deets->hi[1], deets->hi[2], deets->hi[0], deets->hi[1], deets->hi[2]);
|
||||||
|
if(memcmp(deets->hi, deets->lo, RGBSIZE)){
|
||||||
|
fprintf(stderr, "good try on %d->%d (%d)\n", i, didx, stab->colorregs);
|
||||||
|
refine_color(data, linesize, begy, begx, leny, lenx, stab, i);
|
||||||
|
if(stab->colors == stab->colorregs){
|
||||||
|
fprintf(stderr, "filled table!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!refined){ // no more possible work
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we're full!
|
||||||
|
}
|
||||||
|
|
||||||
// Emit some number of equivalent, subsequent sixels, using sixel RLE. We've
|
// 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.
|
// seen the sixel |crle| for |seenrle| columns in a row. |seenrle| must > 0.
|
||||||
static int
|
static int
|
||||||
@ -270,10 +321,11 @@ int sixel_blit(ncplane* nc, int linesize, const void* data, int begy, int begx,
|
|||||||
int leny, int lenx, const blitterargs* bargs){
|
int leny, int lenx, const blitterargs* bargs){
|
||||||
int sixelcount = (lenx - begx) * ((leny - begy + 5) / 6);
|
int sixelcount = (lenx - begx) * ((leny - begy + 5) / 6);
|
||||||
sixeltable stable = {
|
sixeltable stable = {
|
||||||
.data = malloc(MAXCOLORS * sixelcount),
|
.data = malloc(bargs->pixel.colorregs * sixelcount),
|
||||||
.deets = malloc(MAXCOLORS * sizeof(cdetails)),
|
.deets = malloc(bargs->pixel.colorregs * sizeof(cdetails)),
|
||||||
.table = malloc(MAXCOLORS * CENTSIZE),
|
.table = malloc(bargs->pixel.colorregs * CENTSIZE),
|
||||||
.sixelcount = sixelcount,
|
.sixelcount = sixelcount,
|
||||||
|
.colorregs = 256, // FIXME pull in from bargs
|
||||||
.colors = 0,
|
.colors = 0,
|
||||||
};
|
};
|
||||||
if(stable.data == NULL || stable.deets == NULL || stable.table == NULL){
|
if(stable.data == NULL || stable.deets == NULL || stable.table == NULL){
|
||||||
@ -283,14 +335,15 @@ int sixel_blit(ncplane* nc, int linesize, const void* data, int begy, int begx,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// stable.table doesn't need initializing; we start from the bottom
|
// stable.table doesn't need initializing; we start from the bottom
|
||||||
memset(stable.data, 0, sixelcount * MAXCOLORS);
|
memset(stable.data, 0, sixelcount * bargs->pixel.colorregs);
|
||||||
memset(stable.deets, 0, sizeof(*stable.deets) * MAXCOLORS);
|
memset(stable.deets, 0, sizeof(*stable.deets) * bargs->pixel.colorregs);
|
||||||
if(extract_color_table(data, linesize, begy, begx, leny, lenx, &stable)){
|
if(extract_color_table(data, linesize, begy, begx, leny, lenx, &stable)){
|
||||||
free(stable.table);
|
free(stable.table);
|
||||||
free(stable.data);
|
free(stable.data);
|
||||||
free(stable.deets);
|
free(stable.deets);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
refine_color_table(data, linesize, begy, begx, leny, lenx, &stable);
|
||||||
int r = sixel_blit_inner(nc, leny, lenx, &stable, bargs);
|
int r = sixel_blit_inner(nc, leny, lenx, &stable, bargs);
|
||||||
free(stable.data);
|
free(stable.data);
|
||||||
free(stable.deets);
|
free(stable.deets);
|
||||||
|
Loading…
Reference in New Issue
Block a user