/*
* rise and run length encoding, aka rre.
*
* the pixel contained in r are subdivided into
* rectangles of uniform color, each of which
* is encoded by <color, x, y, w, h>.
*
* use raw encoding if it's shorter.
*
* for compact rre, use limited size rectangles,
* which are shorter to encode and therefor give better compression.
*
* hextile encoding uses rre encoding on at most 16x16 rectangles tiled
* across and then down the screen.
*/
static int encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf, int maxr, uchar *done, int (*eqpix)(uchar*, int, int), uchar *(putr)(uchar*, uchar*, int, int, int, int, int, int));
static int eqpix16(uchar *raw, int p1, int p2);
static int eqpix32(uchar *raw, int p1, int p2);
static int eqpix8(uchar *raw, int p1, int p2);
static int findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int));
static uchar* putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
static uchar* putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
static void putpix(Vnc *v, uchar *raw, int p, int pixb);
static int hexcolors(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int), int back, int *fore);
static uchar *puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
static uchar *puthexcol(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
static void sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h);
/*
* default routine, no compression, just the pixels
*/
int
sendraw(Vncs *v, Rectangle r)
{
int pixb, stride;
uchar *raw;
if(!rectinrect(r, v->image->r))
sysfatal("sending bad rectangle");
pixb = v->bpp >> 3;
if((pixb << 3) != v->bpp)
sysfatal("bad pixel math in sendraw");
stride = v->image->width*sizeof(ulong);
if(((stride / pixb) * pixb) != stride)
sysfatal("bad pixel math in sendraw");
stride /= pixb;
static uchar*
puthexcol(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
{
raw += p * pixb;
while(pixb--)
*buf++ = *raw++;
*buf++ = (x << 4) | y;
*buf++ = (w - 1) << 4 | (h - 1);
return buf;
}
static uchar*
puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h)
{
*buf++ = (x << 4) | y;
*buf++ = (w - 1) << 4 | (h - 1);
return buf;
}
static void
sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h)
{
int y;
for(y = 0; y < h; y++)
vncwrbytes(v, &raw[y * stride * pixb], w * pixb);
}
static int
encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf,
int maxr, uchar *done, int (*eqpix)(uchar*, int, int),
uchar *(*putr)(uchar*, uchar*, int, int, int, int, int, int))
{
int s, es, sx, esx, sy, syx, esyx, rh, rw, y, nr, dsy, dp;
es = stride * h;
y = 0;
nr = 0;
dp = 0;
for(s = 0; s < es; s += stride){
esx = s + w;
for(sx = s; sx < esx; ){
rw = done[dp];
if(rw){
sx += rw;
dp += rw;
continue;
}
if((*eqpix)(raw, back, sx)){
sx++;
dp++;
continue;
}
if(nr >= maxr)
return -1;
/*
* find the tallest maximally wide uniform colored rectangle
* with p at the upper left.
* this isn't an optimal parse, but it's pretty good for text
*/
rw = esx - sx;
rh = 0;
for(sy = sx; sy < es; sy += stride){
if(!(*eqpix)(raw, sx, sy))
break;
esyx = sy + rw;
for(syx = sy + 1; syx < esyx; syx++){
if(!(*eqpix)(raw, sx, syx)){
if(sy == sx)
break;
goto breakout;
}
}
if(sy == sx)
rw = syx - sy;
rh++;
}
breakout:;
/*
* estimate the background color
* by finding the most frequent character in a small sample
*/
static int
findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int))
{
enum{
NCol = 6,
NExamine = 4
};
int ccount[NCol], col[NCol], i, wstep, hstep, x, y, pix, c, max, maxc;
for(i = 0; i< NCol; i++)
ccount[i] = 0;
for(y = 0; y < h; y += hstep){
for(x = 0; x < w; x += wstep){
pix = y * stride + x;
for(i = 0; i < NCol; i++){
if(ccount[i] == 0){
ccount[i] = 1;
col[i] = pix;
break;
}
if((*eqpix)(raw, pix, col[i])){
ccount[i]++;
break;
}
}
}
}
maxc = ccount[0];
max = 0;
for(i = 1; i < NCol; i++){
c = ccount[i];
if(!c)
break;
if(c > maxc){
max = i;
maxc = c;
}
}
return col[max];
}
static uchar*
putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
{
raw += p * pixb;
while(pixb--)
*buf++ = *raw++;
*buf++ = x >> 8;
*buf++ = x;
*buf++ = y >> 8;
*buf++ = y;
*buf++ = w >> 8;
*buf++ = w;
*buf++ = h >> 8;
*buf++ = h;
return buf;
}
static uchar*
putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
{
raw += p * pixb;
while(pixb--)
*buf++ = *raw++;
*buf++ = x;
*buf++ = y;
*buf++ = w;
*buf++ = h;
return buf;
}
static int
eqpix8(uchar *raw, int p1, int p2)
{
return raw[p1] == raw[p2];
}
static int
eqpix16(uchar *raw, int p1, int p2)
{
return ((ushort*)raw)[p1] == ((ushort*)raw)[p2];
}
static int
eqpix32(uchar *raw, int p1, int p2)
{
return ((ulong*)raw)[p1] == ((ulong*)raw)[p2];
}
static void
putpix(Vnc *v, uchar *raw, int p, int pixb)
{
vncwrbytes(v, raw + p * pixb, pixb);
}