summaryrefslogtreecommitdiff
path: root/filter/faxe.c
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2004-09-27 02:15:04 +0200
committerTor Andersson <tor@ghostscript.com>2004-09-27 02:15:04 +0200
commit6ddde92a3a45e970b05770633dc6a337d5d013c5 (patch)
tree1dec4612d7469839478e72d16d30a0da5755243c /filter/faxe.c
downloadmupdf-6ddde92a3a45e970b05770633dc6a337d5d013c5.tar.xz
Initial import
Diffstat (limited to 'filter/faxe.c')
-rw-r--r--filter/faxe.c448
1 files changed, 448 insertions, 0 deletions
diff --git a/filter/faxe.c b/filter/faxe.c
new file mode 100644
index 00000000..20e776dd
--- /dev/null
+++ b/filter/faxe.c
@@ -0,0 +1,448 @@
+#include <fitz.h>
+
+#include "faxe.h"
+#include "faxc.h"
+
+/* TODO: honor Rows param */
+
+#define noDEBUGBITS 1
+#define noDEBUG 1
+
+#ifdef DEBUG
+#define DPRINT(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DPRINT(...)
+#endif
+
+typedef struct fz_faxe_s fz_faxe;
+
+struct fz_faxe_s
+{
+ fz_filter super;
+
+ int k;
+ int endofline;
+ int encodedbytealign;
+ int columns;
+ int endofblock;
+ int blackis1;
+
+ int stride;
+ int ridx; /* how many rows in total */
+ int bidx; /* how many bits are already used in out->wp */
+ unsigned char bsave; /* partial byte saved between process() calls */
+
+ int stage;
+ int a0, c; /* mid-line coding state */
+
+ unsigned char *ref;
+ unsigned char *src;
+};
+
+fz_error *
+fz_newfaxe(fz_filter **fp, fz_obj *params)
+{
+ fz_obj *obj;
+
+ FZ_NEWFILTER(fz_faxe, fax, faxe);
+
+ fax->ref = nil;
+ fax->src = nil;
+
+ fax->k = 0;
+ fax->endofline = 0;
+ fax->encodedbytealign = 0;
+ fax->columns = 1728;
+ 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, "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->bidx = 0;
+ fax->ridx = 0;
+
+ fax->stage = 0;
+ fax->a0 = -1;
+ fax->c = 0;
+
+ fax->ref = fz_malloc(fax->stride);
+ if (!fax->ref) { fz_free(fax); return fz_outofmem; }
+
+ fax->src = fz_malloc(fax->stride);
+ if (!fax->src) { fz_free(fax); fz_free(fax->ref); return fz_outofmem; }
+
+ memset(fax->ref, 0, fax->stride);
+ memset(fax->src, 0, fax->stride);
+
+ return nil;
+}
+
+void
+fz_freefaxe(fz_filter *p)
+{
+ fz_faxe *fax = (fz_faxe*) p;
+ fz_free(fax->src);
+ fz_free(fax->ref);
+ fz_free(fax);
+}
+
+enum { codebytes = 2 };
+
+static inline int
+runbytes(int run)
+{
+ int m = (run / 64) / 40 + 1; /* number of makeup codes */
+ return codebytes * (m + 1); /* bytes for makeup + term codes */
+}
+
+static void
+putbits(fz_faxe *fax, fz_buffer *out, int code, int nbits)
+{
+#ifdef DEBUGBITS
+ fprintf(stderr, "BITS ");
+ printbits(stderr, code, nbits);
+ fprintf(stderr, "\n");
+#endif
+
+ while (nbits > 0)
+ {
+ if (fax->bidx == 0) {
+ *out->wp = 0;
+ }
+
+ /* code does not fit: shift right */
+ if (nbits > (8 - fax->bidx)) {
+ *out->wp |= code >> (nbits - (8 - fax->bidx));
+ nbits = nbits - (8 - fax->bidx);
+ fax->bidx = 0;
+ out->wp ++;
+ }
+
+ /* shift left */
+ else {
+ *out->wp |= code << ((8 - fax->bidx) - nbits);
+ fax->bidx += nbits;
+ if (fax->bidx == 8) {
+ fax->bidx = 0;
+ out->wp ++;
+ }
+ nbits = 0;
+ }
+ }
+}
+
+static inline void
+putcode(fz_faxe *fax, fz_buffer *out, const cfe_code *run)
+{
+ putbits(fax, out, run->code, run->nbits);
+}
+
+static void
+putrun(fz_faxe *fax, fz_buffer *out, int run, int c)
+{
+ int m;
+
+ const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs;
+
+ if (run > 63) {
+ m = run / 64;
+ while (m > 40) {
+ DPRINT("%c %d\n", c?'b':'w', 40 * 64);
+ putcode(fax, out, &codetable->makeup[40]);
+ m -= 40;
+ }
+ if (m > 0) {
+ DPRINT("%c %d\n", c?'b':'w', m * 64);
+ putcode(fax, out, &codetable->makeup[m]);
+ }
+ DPRINT("%c %d\n", c?'b':'w', run % 64);
+ putcode(fax, out, &codetable->termination[run % 64]);
+ }
+ else {
+ DPRINT("%c %d\n", c?'b':'w', run);
+ putcode(fax, out, &codetable->termination[run]);
+ }
+}
+
+static fz_error *
+enc1d(fz_faxe *fax, unsigned char *line, fz_buffer *out)
+{
+ int run;
+
+#ifdef DEBUG
+if (fax->a0 < 0) {
+ DPRINT("1d scanline %d\n", fax->ridx + 1);
+ DPRINT("color = %d\n", fax->c);
+}
+#endif
+
+ if (fax->a0 < 0)
+ fax->a0 = 0;
+
+ while (fax->a0 < fax->columns)
+ {
+ run = getrun(line, fax->a0, fax->columns, fax->c);
+
+ if (out->wp + 1 + runbytes(run) > out->ep)
+ return fz_ioneedout;
+
+ putrun(fax, out, run, fax->c);
+
+ fax->a0 += run;
+ fax->c = !fax->c;
+ }
+
+ return 0;
+}
+
+static fz_error *
+enc2d(fz_faxe *fax, unsigned char *ref, unsigned char *src, fz_buffer *out)
+{
+ int a1, a2, b1, b2;
+ int run1, run2, n;
+
+
+#ifdef DEBUG
+if (fax->a0 < 0)
+{
+ DPRINT("2d scanline %d\n", fax->ridx + 1);
+}
+#endif
+
+ DPRINT("color = %d\n", fax->c);
+
+ while (fax->a0 < fax->columns)
+ {
+ a1 = findchanging(src, fax->a0, fax->columns);
+ b1 = findchangingcolor(ref, fax->a0, fax->columns, !fax->c);
+ b2 = findchanging(ref, b1, fax->columns);
+
+#ifdef DEBUGBITS
+ DPRINT("twod a0=%d a1=%d b1=%d b2=%d\n", fax->a0, a1, b1, b2);
+#endif
+
+ /* pass */
+ if (b2 < a1)
+ {
+ if (out->wp + 1 + codebytes > out->ep)
+ return fz_ioneedout;
+
+ DPRINT("P\n");
+
+ putcode(fax, out, &cf2_run_pass);
+
+ fax->a0 = b2;
+ }
+
+ /* vertical */
+ else if (ABS(b1 - a1) <= 3)
+ {
+ if (out->wp + 1 + codebytes > out->ep)
+ return fz_ioneedout;
+
+#ifdef DEBUG
+ if (b1 - a1 == 0)
+ DPRINT("V0\n");
+ else if (b1 - a1 < 0)
+ DPRINT("VR%d\n", a1 - b1);
+ else
+ DPRINT("VL%d\n", b1 - a1);
+#endif
+
+ putcode(fax, out, &cf2_run_vertical[b1 - a1 + 3]);
+
+ fax->a0 = a1;
+ fax->c = !fax->c;
+ }
+
+ /* horizontal */
+ else
+ {
+ a2 = findchanging(src, a1, fax->columns);
+ run1 = a1 - fax->a0;
+ run2 = a2 - a1;
+ n = codebytes + runbytes(run1) + runbytes(run2);
+
+ if (out->wp + 1 + n > out->ep)
+ return fz_ioneedout;
+
+ DPRINT("H\n");
+
+ putcode(fax, out, &cf2_run_horizontal);
+ putrun(fax, out, run1, fax->c);
+ putrun(fax, out, run2, !fax->c);
+
+ fax->a0 = a2;
+ }
+ }
+
+ return 0;
+}
+
+static fz_error *
+process(fz_faxe *fax, fz_buffer *in, fz_buffer *out)
+{
+ fz_error *err;
+ int i, n;
+
+ while (1)
+ {
+ if (in->rp == in->wp && in->eof)
+ goto rtc;
+
+ switch (fax->stage)
+ {
+ case 0:
+ if (fax->encodedbytealign)
+ {
+ if (fax->endofline) {
+ if (out->wp + 1 + 1 > out->ep)
+ return fz_ioneedout;
+
+ /* make sure that EOL ends on a byte border */
+ putbits(fax, out, 0, (12 - fax->bidx) & 7);
+ }
+ else {
+ if (fax->bidx) {
+ if (out->wp + 1 > out->ep)
+ return fz_ioneedout;
+ fax->bidx = 0;
+ out->wp ++;
+ }
+ }
+ }
+
+ fax->stage ++;
+
+ case 1:
+ if (fax->endofline)
+ {
+ if (out->wp + 1 + codebytes + 1 > out->ep)
+ return fz_ioneedout;
+
+ DPRINT("EOL\n");
+ if (fax->k > 0) {
+ if (fax->ridx % fax->k == 0)
+ putcode(fax, out, &cf2_run_eol_1d);
+ else
+ putcode(fax, out, &cf2_run_eol_2d);
+ }
+ else {
+ putcode(fax, out, &cf_run_eol);
+ }
+ }
+
+ fax->stage ++;
+
+ case 2:
+ if (in->rp + fax->stride > in->wp) {
+ if (in->eof) /* XXX barf here? */
+ goto rtc;
+ return fz_ioneedin;
+ }
+
+ memcpy(fax->ref, fax->src, fax->stride);
+ memcpy(fax->src, in->rp, fax->stride);
+
+ if (!fax->blackis1)
+ {
+ for (i = 0; i < fax->stride; i++)
+ fax->src[i] = ~fax->src[i];
+ }
+
+ in->rp += fax->stride;
+
+ fax->c = 0;
+ fax->a0 = -1;
+
+#ifdef DEBUGBITS
+ DPRINT("LINE %d\n", fax->ridx);
+ printline(stderr, fax->ref, fax->columns);
+ printline(stderr, fax->src, fax->columns);
+#endif
+
+ fax->stage ++;
+
+ case 3:
+ err = 0; /* to silence compiler */
+
+ if (fax->k < 0) {
+ err = enc2d(fax, fax->ref, fax->src, out);
+ }
+ else if (fax->k == 0) {
+ err = enc1d(fax, fax->src, out);
+ }
+ else if (fax->k > 0) {
+ if (fax->ridx % fax->k == 0) {
+ err = enc1d(fax, fax->src, out);
+ }
+ else {
+ err = enc2d(fax, fax->ref, fax->src, out);
+ }
+ }
+
+ if (err) return err;
+
+ fax->ridx ++;
+
+ fax->stage = 0;
+ }
+ }
+
+rtc:
+ if (fax->endofblock)
+ {
+ n = fax->k < 0 ? 2 : 6;
+
+ if (out->wp + 1 + codebytes * n > out->ep)
+ return fz_ioneedout;
+
+ for (i = 0; i < n; i++) {
+ putcode(fax, out, &cf_run_eol);
+ if (fax->k > 0)
+ putbits(fax, out, 1, 1);
+ }
+ DPRINT("RTC\n");
+ }
+
+ if (fax->bidx)
+ out->wp ++;
+ out->eof = 1;
+
+ return fz_iodone;
+}
+
+fz_error *
+fz_processfaxe(fz_filter *p, fz_buffer *in, fz_buffer *out)
+{
+ fz_faxe *fax = (fz_faxe*) p;
+ fz_error *err;
+
+ /* restore partial bits */
+ *out->wp = fax->bsave;
+
+ err = process(fax, in, out);
+
+ /* save partial bits */
+ fax->bsave = *out->wp;
+
+ return err;
+}
+