ref: ef5d7bc12ccaa8052b1b1705e5a7d6c87ad4eefe
parent: 7c3dae6ee98d99ea92bc06a830acf59f40108d45
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Nov 22 15:18:38 EST 2020
lzw and flate filters: use common predict logic
--- a/f_flate.c
+++ b/f_flate.c
@@ -3,70 +3,8 @@
#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);
@@ -83,12 +21,8 @@
static int
flreadall(void *aux, Buffer *bi, Buffer *bo)
{
- int r, i, rows, n;
- FlateParms *fp;
- uchar *x, *y, *zero;
+ int r;
- fp = aux;
-
do{
r = inflatezlib(bo, bw, bi, bget);
}while(r == FlateOk && !bufeof(bi));
@@ -97,66 +31,13 @@
werrstr("%s", flateerr(r));
return -1;
}
- r = 0;
- /* 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;
+ return unpredict(aux, bo);
}
-static int
-flopen(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;
-}
-
-static void
-flclose(Filter *f)
-{
- free(f->aux);
-}
-
Filter filterFlate = {
.name = "FlateDecode",
.readall = flreadall,
- .open = flopen,
- .close = flclose,
+ .open = flopenpredict,
+ .close = flclosepredict,
};
--- a/f_lzw.c
+++ b/f_lzw.c
@@ -121,8 +121,6 @@
uchar *in;
Tb tb;
- USED(aux);
-
memset(&tb, 0, sizeof(tb));
in = bufdata(bi, &insz);
width = 9;
@@ -155,10 +153,12 @@
tbfree(&tb);
bi->off = bi->sz;
- return 0;
+ return unpredict(aux, bo);
}
Filter filterLZW = {
.name = "LZWDecode",
.readall = flreadall,
+ .open = flopenpredict,
+ .close = flclosepredict,
};
--- a/mkfile
+++ b/mkfile
@@ -7,12 +7,12 @@
buffer.$O\
dict.$O\
eval.$O\
- f_dct.$O\
f_ascii85.$O\
f_asciihex.$O\
f_ccittfax.$O\
f_crypt.$O\
f_dct.$O\
+ f_dct.$O\
f_flate.$O\
f_jbig2.$O\
f_jpx.$O\
@@ -25,6 +25,7 @@
object.$O\
pdf.$O\
pdffs.$O\
+ predict.$O\
stream.$O\
string.$O\
xref.$O\
--- a/pdf.h
+++ b/pdf.h
@@ -15,6 +15,8 @@
typedef struct KeyValue KeyValue;
typedef struct Object Object;
typedef struct Pdf Pdf;
+typedef struct PredictParms PredictParms;
+#pragma incomplete PredictParms;
typedef struct Stream Stream;
typedef struct Xref Xref;
@@ -185,6 +187,11 @@
Filter *filteropen(char *name, Object *o);
int filterrun(Filter *f, Buffer *bi, Buffer *bo);
void filterclose(Filter *f);
+
+/* 7.4.4.4 LZW and Flate predictor functions */
+int unpredict(PredictParms *pp, Buffer *bo);
+int flopenpredict(Filter *f, Object *o);
+void flclosepredict(Filter *f);
void bufinit(Buffer *b, uchar *d, int sz);
void buffree(Buffer *b);
--- /dev/null
+++ b/predict.c
@@ -1,0 +1,128 @@
+#include <u.h>
+#include <libc.h>
+#include "pdf.h"
+
+struct PredictParms {
+ 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;
+}
+
+int
+unpredict(PredictParms *pp, Buffer *bo)
+{
+ uchar *x, *y, *zero;
+ int i, r, rows, n;
+
+ if(pp->predictor < 10 || pp->columns < 1)
+ return 0;
+
+ n = pp->columns + 1;
+ rows = bo->sz/n;
+ x = bo->b;
+ y = bo->b;
+ zero = mallocz(pp->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, pp->columns);
+ free(zero);
+
+ if(r != 0)
+ return r;
+
+ x = bo->b;
+ y = bo->b+1;
+ for(i = 0; i < rows; i++, x += pp->columns, y += n)
+ memmove(x, y, pp->columns);
+ bo->sz -= rows;
+
+ return r;
+}
+
+int
+flopenpredict(Filter *f, Object *o)
+{
+ Object *parms;
+ PredictParms *pp;
+ 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((pp = malloc(sizeof(*pp))) == nil)
+ return -1;
+ pp->predictor = predictor;
+ pp->columns = columns;
+ f->aux = pp;
+
+ return 0;
+}
+
+void
+flclosepredict(Filter *f)
+{
+ free(f->aux);
+}