summaryrefslogtreecommitdiff
path: root/fitz/filt_faxd.c
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2009-02-28 13:00:34 +0100
committerTor Andersson <tor@ghostscript.com>2009-02-28 13:00:34 +0100
commitf744dace3f0f91b8505979bf244453c9ec713b4b (patch)
tree86fed467944886a17d4d22038990a8fd8d2e3be8 /fitz/filt_faxd.c
parentd0631f32c95f656d30c90d28c15a56b09fcc86ee (diff)
downloadmupdf-f744dace3f0f91b8505979bf244453c9ec713b4b.tar.xz
Moved Fitz files into one directory.
Diffstat (limited to 'fitz/filt_faxd.c')
-rw-r--r--fitz/filt_faxd.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c
new file mode 100644
index 00000000..3eaf5f3b
--- /dev/null
+++ b/fitz/filt_faxd.c
@@ -0,0 +1,470 @@
+#include "fitz-base.h"
+#include "fitz-stream.h"
+
+#include "filt_faxd.h"
+#include "filt_faxc.h"
+
+typedef enum fax_stage_e
+{
+ SNORMAL, /* neutral state, waiting for any code */
+ SMAKEUP, /* got a 1d makeup code, waiting for terminating code */
+ SEOL, /* at eol, needs output buffer space */
+ SH1, SH2 /* in H part 1 and 2 (both makeup and terminating codes) */
+} fax_stage_e;
+
+/* TODO: uncompressed */
+
+typedef struct fz_faxd_s fz_faxd;
+
+struct fz_faxd_s
+{
+ fz_filter super;
+
+ int k;
+ int endofline;
+ int encodedbytealign;
+ int columns;
+ int rows;
+ int endofblock;
+ int blackis1;
+
+ int stride;
+ int ridx;
+
+ int bidx;
+ unsigned int word;
+
+ fax_stage_e stage;
+
+ int a, c, dim, eolc;
+ unsigned char *ref;
+ unsigned char *dst;
+};
+
+fz_error *
+fz_newfaxd(fz_filter **fp, fz_obj *params)
+{
+ fz_obj *obj;
+
+ FZ_NEWFILTER(fz_faxd, fax, faxd);
+
+ fax->ref = nil;
+ fax->dst = nil;
+
+ fax->k = 0;
+ fax->endofline = 0;
+ fax->encodedbytealign = 0;
+ fax->columns = 1728;
+ fax->rows = 0;
+ fax->endofblock = 1;
+ fax->blackis1 = 0;
+
+ obj = fz_dictgets(params, "K");
+ if (obj) fax->k = fz_toint(obj);
+
+ obj = fz_dictgets(params, "EndOfLine");
+ if (obj) fax->endofline = fz_tobool(obj);
+
+ obj = fz_dictgets(params, "EncodedByteAlign");
+ if (obj) fax->encodedbytealign = fz_tobool(obj);
+
+ obj = fz_dictgets(params, "Columns");
+ if (obj) fax->columns = fz_toint(obj);
+
+ obj = fz_dictgets(params, "Rows");
+ if (obj) fax->rows = fz_toint(obj);
+
+ obj = fz_dictgets(params, "EndOfBlock");
+ if (obj) fax->endofblock = fz_tobool(obj);
+
+ obj = fz_dictgets(params, "BlackIs1");
+ if (obj) fax->blackis1 = fz_tobool(obj);
+
+ fax->stride = ((fax->columns - 1) >> 3) + 1;
+ fax->ridx = 0;
+ fax->bidx = 32;
+ fax->word = 0;
+
+ fax->stage = SNORMAL;
+ fax->a = -1;
+ fax->c = 0;
+ fax->dim = fax->k < 0 ? 2 : 1;
+ fax->eolc = 0;
+
+ fax->ref = fz_malloc(fax->stride);
+ if (!fax->ref)
+ {
+ fz_free(fax);
+ return fz_throw("outofmem: scanline buffer one");
+ }
+
+ fax->dst = fz_malloc(fax->stride);
+ if (!fax->dst)
+ {
+ fz_free(fax);
+ fz_free(fax->ref);
+ return fz_throw("outofmem: scanline buffer two");
+ }
+
+ memset(fax->ref, 0, fax->stride);
+ memset(fax->dst, 0, fax->stride);
+
+ return fz_okay;
+}
+
+void
+fz_dropfaxd(fz_filter *p)
+{
+ fz_faxd *fax = (fz_faxd*) p;
+ fz_free(fax->ref);
+ fz_free(fax->dst);
+}
+
+static inline void eatbits(fz_faxd *fax, int nbits)
+{
+ fax->word <<= nbits;
+ fax->bidx += nbits;
+}
+
+static inline fz_error * fillbits(fz_faxd *fax, fz_buffer *in)
+{
+ while (fax->bidx >= 8)
+ {
+ if (in->rp + 1 > in->wp)
+ return fz_ioneedin;
+ fax->bidx -= 8;
+ fax->word |= *in->rp << fax->bidx;
+ in->rp ++;
+ }
+ return fz_okay;
+}
+
+static int
+getcode(fz_faxd *fax, const cfd_node *table, int initialbits)
+{
+ unsigned int word = fax->word;
+ int tidx = word >> (32 - initialbits);
+ int val = table[tidx].val;
+ int nbits = table[tidx].nbits;
+
+ if (nbits > initialbits)
+ {
+ int mask = (1 << (32 - initialbits)) - 1;
+ tidx = val + ((word & mask) >> (32 - nbits));
+ val = table[tidx].val;
+ nbits = initialbits + table[tidx].nbits;
+ }
+
+ eatbits(fax, nbits);
+
+ return val;
+}
+
+/* decode one 1d code */
+static fz_error *
+dec1d(fz_faxd *fax)
+{
+ int code;
+
+ if (fax->a == -1)
+ fax->a = 0;
+
+ if (fax->c)
+ code = getcode(fax, cf_black_decode, cfd_black_initial_bits);
+ else
+ code = getcode(fax, cf_white_decode, cfd_white_initial_bits);
+
+ if (code == UNCOMPRESSED)
+ return fz_throw("uncompressed data in faxd");
+
+ if (code < 0)
+ return fz_throw("negative code in 1d faxd");
+
+ if (fax->a + code > fax->columns)
+ return fz_throw("overflow in 1d faxd");
+
+ if (fax->c)
+ setbits(fax->dst, fax->a, fax->a + code);
+
+ fax->a += code;
+
+ if (code < 64)
+ {
+ fax->c = !fax->c;
+ fax->stage = SNORMAL;
+ }
+ else
+ fax->stage = SMAKEUP;
+
+ return fz_okay;
+}
+
+/* decode one 2d code */
+static fz_error *
+dec2d(fz_faxd *fax)
+{
+ int code, b1, b2;
+
+ if (fax->stage == SH1 || fax->stage == SH2)
+ {
+ if (fax->a == -1)
+ fax->a = 0;
+
+ if (fax->c)
+ code = getcode(fax, cf_black_decode, cfd_black_initial_bits);
+ else
+ code = getcode(fax, cf_white_decode, cfd_white_initial_bits);
+
+ if (code == UNCOMPRESSED)
+ return fz_throw("uncompressed data in faxd");
+
+ if (code < 0)
+ return fz_throw("negative code in 2d faxd");
+
+ if (fax->a + code > fax->columns)
+ return fz_throw("overflow in 2d faxd");
+
+ if (fax->c)
+ setbits(fax->dst, fax->a, fax->a + code);
+
+ fax->a += code;
+
+ if (code < 64)
+ {
+ fax->c = !fax->c;
+ if (fax->stage == SH1)
+ fax->stage = SH2;
+ else if (fax->stage == SH2)
+ fax->stage = SNORMAL;
+ }
+
+ return fz_okay;
+ }
+
+ code = getcode(fax, cf_2d_decode, cfd_2d_initial_bits);
+
+ switch (code)
+ {
+ case H:
+ fax->stage = SH1;
+ break;
+
+ case P:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ b2 = findchanging(fax->ref, b1, fax->columns);
+ if (fax->c) setbits(fax->dst, fax->a, b2);
+ fax->a = b2;
+ break;
+
+ case V0:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1);
+ fax->a = b1;
+ fax->c = !fax->c;
+ break;
+
+ case VR1:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 + 1);
+ fax->a = b1 + 1;
+ fax->c = !fax->c;
+ break;
+
+ case VR2:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 + 2);
+ fax->a = b1 + 2;
+ fax->c = !fax->c;
+ break;
+
+ case VR3:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 + 3);
+ fax->a = b1 + 3;
+ fax->c = !fax->c;
+ break;
+
+ case VL1:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 - 1);
+ fax->a = b1 - 1;
+ fax->c = !fax->c;
+ break;
+
+ case VL2:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 - 2);
+ fax->a = b1 - 2;
+ fax->c = !fax->c;
+ break;
+
+ case VL3:
+ b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
+ if (fax->c) setbits(fax->dst, fax->a, b1 - 3);
+ fax->a = b1 - 3;
+ fax->c = !fax->c;
+ break;
+
+ case UNCOMPRESSED:
+ return fz_throw("uncompressed data in faxd");
+
+ case ERROR:
+ return fz_throw("invalid code in 2d faxd");
+
+ default:
+ return fz_throw("invalid code in 2d faxd (%d)", code);
+ }
+
+ return 0;
+}
+
+fz_error *
+fz_processfaxd(fz_filter *f, fz_buffer *in, fz_buffer *out)
+{
+ fz_faxd *fax = (fz_faxd*)f;
+ fz_error *error;
+ int i;
+ unsigned char *tmp;
+
+ if (fax->stage == SEOL)
+ goto eol;
+
+loop:
+
+ if (fillbits(fax, in))
+ {
+ if (in->eof)
+ {
+ if (fax->bidx > 31)
+ {
+ if (fax->a > 0)
+ goto eol;
+ goto rtc;
+ }
+ }
+ else
+ {
+ return fz_ioneedin;
+ }
+ }
+
+ if ((fax->word >> (32 - 12)) == 0)
+ {
+ eatbits(fax, 1);
+ goto loop;
+ }
+
+ if ((fax->word >> (32 - 12)) == 1)
+ {
+ eatbits(fax, 12);
+ fax->eolc ++;
+
+ if (fax->k > 0)
+ {
+ if (fax->a == -1)
+ fax->a = 0;
+ if ((fax->word >> (32 - 1)) == 1)
+ fax->dim = 1;
+ else
+ fax->dim = 2;
+ eatbits(fax, 1);
+ }
+ }
+ else if (fax->k > 0 && fax->a == -1)
+ {
+ fax->a = 0;
+ if ((fax->word >> (32 - 1)) == 1)
+ fax->dim = 1;
+ else
+ fax->dim = 2;
+ eatbits(fax, 1);
+ }
+ else if (fax->dim == 1)
+ {
+ fax->eolc = 0;
+ error = dec1d(fax);
+ if (error) return error; /* can be fz_io* or real error */
+
+ }
+ else if (fax->dim == 2)
+ {
+ fax->eolc = 0;
+ error = dec2d(fax);
+ if (error) return error; /* can be fz_io* or real error */
+ }
+
+ /* no eol check after makeup codes nor in the middle of an H code */
+ if (fax->stage == SMAKEUP || fax->stage == SH1 || fax->stage == SH2)
+ goto loop;
+
+ /* check for eol conditions */
+ if (fax->eolc || fax->a >= fax->columns)
+ {
+ if (fax->a > 0)
+ goto eol;
+ if (fax->eolc == (fax->k < 0 ? 2 : 6))
+ goto rtc;
+ }
+
+ goto loop;
+
+eol:
+ fax->stage = SEOL;
+ if (out->wp + fax->stride > out->ep)
+ return fz_ioneedout;
+
+ if (fax->blackis1)
+ memcpy(out->wp, fax->dst, fax->stride);
+ else {
+ unsigned char * restrict d = out->wp;
+ unsigned char * restrict s = fax->dst;
+ unsigned w = fax->stride;
+ for (i = 0; i < w; i++)
+ *d++ = *s++ ^ 0xff;
+ }
+
+ tmp = fax->ref;
+ fax->ref = fax->dst;
+ fax->dst = tmp;
+ memset(fax->dst, 0, fax->stride);
+ out->wp += fax->stride;
+
+ fax->stage = SNORMAL;
+ fax->c = 0;
+ fax->a = -1;
+ fax->ridx ++;
+
+ if (!fax->endofblock && fax->rows)
+ {
+ if (fax->ridx >= fax->rows)
+ goto rtc;
+ }
+
+ /* we have not read dim from eol, make a guess */
+ if (fax->k > 0 && !fax->eolc && fax->a == -1)
+ {
+ if (fax->ridx % fax->k == 0)
+ fax->dim = 1;
+ else
+ fax->dim = 2;
+ }
+
+ /* if endofline & encodedbytealign, EOLs are *not* optional */
+ if (fax->encodedbytealign)
+ {
+ if (fax->endofline)
+ eatbits(fax, (12 - fax->bidx) & 7);
+ else
+ eatbits(fax, (8 - fax->bidx) & 7);
+ }
+
+ goto loop;
+
+rtc:
+ i = (32 - fax->bidx) / 8;
+ while (i-- && in->rp > in->bp)
+ in->rp --;
+
+ return fz_iodone;
+}
+