ref: d613b76a67a6dbb4d2c16a17e6994e7bdf2731df
dir: /f_flate.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <flate.h>
#include "pdf.h"
typedef struct FlateParms FlateParms;
struct FlateParms {
int predictor;
int columns;
};
static uchar
paeth(uchar a, uchar b, uchar c)
{
int p, pa, pb, pc;
p = a + b - c;
pa = abs(p - a);
pb = abs(p - b);
pc = abs(p - c);
if(pa <= pb && pa <= pc)
return a;
return pb <= pc ? b : c;
}
static int
pngunpredict(int pred, uchar *buf, uchar *up, int len)
{
int i;
switch(pred){
case 0: /* None */
break;
case 1: /* Sub */
for(i = 1; i < len; ++i)
buf[i] += buf[i-1];
break;
case 2: /* Up */
for(i = 0; i < len; ++i)
buf[i] += up[i];
break;
case 3: /* Average */
buf[0] += up[0]/2;
for(i = 1; i < len; ++i)
buf[i] += (buf[i-1]+up[i])/2;
break;
case 4: /* Paeth */
buf[0] += paeth(0, up[0], 0);
for(i = 0; i < len; ++i)
buf[i] += paeth(buf[i-1], up[i], up[i-1]);
break;
/* FIXME 5 optimum??? */
default:
werrstr("unsupported predictor %d", pred);
return -1;
}
return 0;
}
static int
bw(void *aux, void *d, int n)
{
return bufput(aux, d, n);
}
static int
bget(void *aux)
{
uchar c;
return bufget(aux, &c, 1) == 1 ? c : -1;
}
int
fFlate(void *aux, Buffer *bi, Buffer *bo)
{
int r, i, rows, n;
FlateParms *fp;
uchar *x, *y, *zero;
fp = aux;
do{
r = inflatezlib(bo, bw, bi, bget);
}while(r == FlateOk && !bufeof(bi));
if(r != FlateOk){
werrstr("%s", flateerr(r));
return -1;
}
/* 7.4.4.4 LZW and Flate predictor functions */
if(fp->predictor >= 10 && fp->columns > 0){
n = fp->columns + 1;
rows = bo->sz/n;
x = bo->b;
y = bo->b;
zero = mallocz(fp->columns, 1);
for(i = r = 0; i < rows && r == 0; i++, x += n, y += n)
r = pngunpredict(x[0], x+1, i < 1 ? zero : y+1-n, fp->columns);
free(zero);
x = bo->b;
y = bo->b+1;
for(i = 0; i < rows; i++, x += fp->columns, y += n)
memmove(x, y, fp->columns);
bo->sz -= rows;
}
return r;
}
int
openFlate(Filter *f, Object *o)
{
Object *parms;
FlateParms *fp;
int predictor, columns;
parms = dictget(o, "DecodeParms");
predictor = dictint(parms, "Predictor");
columns = dictint(parms, "Columns");
if((predictor >= 2 && predictor < 10) || predictor >= 15){
werrstr("unsupported flate predictor %d", predictor);
return -1;
}
if(predictor >= 10 && predictor <= 15 && columns < 1){
werrstr("invalid columns %d for predictor %d", columns, predictor);
return -1;
}
if((fp = malloc(sizeof(FlateParms))) == nil)
return -1;
fp->predictor = predictor;
fp->columns = columns;
f->aux = fp;
return 0;
}
void
closeFlate(Filter *f)
{
free(f->aux);
}