summaryrefslogtreecommitdiffstats
path: root/kfaxview/libkfaximage/faxexpand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kfaxview/libkfaximage/faxexpand.cpp')
-rw-r--r--kfaxview/libkfaximage/faxexpand.cpp745
1 files changed, 745 insertions, 0 deletions
diff --git a/kfaxview/libkfaximage/faxexpand.cpp b/kfaxview/libkfaximage/faxexpand.cpp
new file mode 100644
index 00000000..9c4b4082
--- /dev/null
+++ b/kfaxview/libkfaximage/faxexpand.cpp
@@ -0,0 +1,745 @@
+/* Expand one page of fax data
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <kdebug.h>
+
+#include "faxexpand.h"
+
+//Uncomment this for verbose debug output
+//#define DEBUG_FAX
+#define verbose false
+
+pagenode::pagenode()
+{
+}
+
+/* Note that NeedBits() only works for n <= 16 */
+#define NeedBits(n) do { \
+ if (BitsAvail < (n)) { \
+ BitAcc |= *sp++ << BitsAvail; \
+ BitsAvail += 16; \
+ } \
+} while (0)
+#define GetBits(n) (BitAcc & ((1<<(n))-1))
+#define ClrBits(n) do { \
+ BitAcc >>= (n); \
+ BitsAvail -= (n); \
+} while (0)
+
+#ifdef DEBUG_FAX
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP(wid,tab) do { \
+ int t; \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, \
+ StateNames[TabEnt->State], TabEnt->Param); \
+ for (t = 0; t < TabEnt->Width; t++) \
+ DEBUG_SHOW; \
+ putchar('\n'); \
+ fflush(stdout); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+
+const char *StateNames[] = {
+ "Null ",
+ "Pass ",
+ "Horiz ",
+ "V0 ",
+ "VR ",
+ "VL ",
+ "Ext ",
+ "TermW ",
+ "TermB ",
+ "MakeUpW",
+ "MakeUpB",
+ "MakeUp ",
+ "EOL ",
+};
+
+#else
+#define LOOKUP(wid,tab) do { \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+#endif
+
+#define dumpruns(runs) do { \
+ printf("-------------------- %d\n", LineNum); \
+ for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \
+ printf("%4d %d\n", a0, *pa); \
+} while (0)
+
+#define EndOfData(pn) (sp >= pn->data + pn->length/sizeof(*pn->data))
+
+/* This macro handles coding errors in G3 data.
+ We redefine it below for the G4 case */
+#define SKIP_EOL do { \
+ while (!EndOfData(pn)) { \
+ NeedBits(11); \
+ if (GetBits(11) == 0) \
+ break; \
+ ClrBits(1); \
+ } \
+ ClrBits(11); \
+ goto EOL; \
+} while (0)
+#define eol2lab EOL2:
+
+/* the line expanders are written as macros so that they can be reused
+ (twice each) but still have direct access to the local variables of
+ the "calling" function */
+#define expand1d() do { \
+ while (a0 < lastx) { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = a0 >= lastx; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ EOL: ; \
+} while (0)
+
+#define CHECK_b1 do { \
+ if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \
+ b1 += pb[0] + pb[1]; \
+ pb += 2; \
+ } \
+} while (0)
+
+#define expand2d(eolab) do { \
+ while (a0 < lastx) { \
+ LOOKUP(7, MainTable); \
+ switch (TabEnt->State) { \
+ case S_Pass: \
+ CHECK_b1; \
+ b1 += *pb++; \
+ RunLength += b1 - a0; \
+ a0 = b1; \
+ b1 += *pb++; \
+ break; \
+ case S_Horiz: \
+ if ((pa-run0)&1) { \
+ int done = 0; \
+ while (!done) { /* black first */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then white */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ else { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ CHECK_b1; \
+ break; \
+ case S_V0: \
+ CHECK_b1; \
+ SETVAL(b1 - a0); \
+ b1 += *pb++; \
+ break; \
+ case S_VR: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 + TabEnt->Param); \
+ b1 += *pb++; \
+ break; \
+ case S_VL: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 - TabEnt->Param); \
+ b1 -= *--pb; \
+ break; \
+ case S_Ext: \
+ *pa++ = lastx - a0; \
+ if (verbose) \
+ kdDebug() << "Line " << LineNum << ": extension code\n";\
+ SKIP_EOL; \
+ break; \
+ case S_EOL: \
+ *pa++ = lastx - a0; \
+ NeedBits(4); \
+ if (GetBits(4) && verbose) /* already seen 7 zeros */ \
+ kdDebug() << "Line " << LineNum << ": Bad EOL\n"; \
+ ClrBits(4); \
+ EOLcnt = 1; \
+ goto eolab; \
+ break; \
+ default: \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ if (RunLength) { \
+ if (RunLength + a0 < lastx) { \
+ /* expect a final V0 */ \
+ NeedBits(1); \
+ if (!GetBits(1)) { \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ } \
+ ClrBits(1); \
+ } \
+ SETVAL(0); \
+ } \
+ eol2lab ; \
+} while (0)
+
+static void
+unexpected(const char *what, int LineNum)
+{
+ if (verbose)
+ kdError() << "Line " << LineNum << ": Unexpected state in "
+ << what << endl;
+}
+
+/* Expand tiff modified huffman data (g3-1d without EOLs) */
+void
+MHexpand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->size.width();
+ runs = (pixnum *) malloc(lastx * sizeof(pixnum));
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ if (BitsAvail & 7) /* skip to byte boundary */
+ ClrBits(BitsAvail & 7);
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 1-dimensional data */
+void
+g31expand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->size.width();
+ runs = (pixnum *) malloc(lastx * sizeof(pixnum));
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(11);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(runs);
+ return;
+ }
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 2-dimensional data */
+void
+g32expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->size.width();/* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int EOLcnt; /* number of consecutive EOLs */
+ int refline = 0; /* 1D encoded reference line */
+ int LineNum; /* line number */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx;
+ run1[1] = 0;
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(12);
+ refline = GetBits(1); /* 1D / 2D flag */
+ ClrBits(1);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(run0);
+ return;
+ }
+ if (LineNum == 0 && refline == 0 && verbose)
+ kdDebug() << "First line is 2-D encoded\n";
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ EOLcnt = 0;
+ a0 = 0;
+ b1 = *pb++;
+
+ if (refline) {
+ expand1d();
+ }
+ else {
+ expand2d(EOL2);
+ }
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ }
+ free(run0);
+}
+
+/* Redefine the "skip to eol" macro. We cannot recover from coding
+ errors in G4 data */
+#undef SKIP_EOL
+#undef eol2lab
+#define SKIP_EOL do { \
+ if (verbose) \
+ kdError() << "Line " << LineNum << ": G4 coding error\n"; \
+ free(run0); \
+ return; \
+} while (0)
+#define eol2lab
+
+/* Expand group-4 data */
+void
+g4expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->size.width();/* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int LineNum; /* line number */
+ int EOLcnt;
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx; /* initial reference line */
+ run1[1] = 0;
+
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ a0 = 0;
+ b1 = *pb++;
+ expand2d(EOFB);
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ continue;
+ EOFB:
+ NeedBits(13);
+ if (GetBits(13) != 0x1001 && verbose)
+ kdError() << "Bad RTC\n";
+ break;
+ }
+ free(run0);
+}
+
+static const unsigned char zerotab[256] = {
+ 0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05,
+ 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04,
+ 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00
+};
+
+#define check(v) do { \
+ prezeros = zerotab[v]; \
+ postzeros = prezeros & 15; \
+ prezeros >>= 4; \
+ if (prezeros == 8) { \
+ zeros += 8; \
+ continue; \
+ } \
+ if (zeros + prezeros < 11) { \
+ empty = 0; \
+ zeros = postzeros; \
+ continue; \
+ } \
+ zeros = postzeros; \
+ if (empty) \
+ EOLcnt++; \
+ lines++; \
+ empty = 1; \
+} while (0)
+
+/* count fax lines */
+int
+G3count(struct pagenode *pn, int twoD)
+{
+ t16bits *p = pn->data;
+ t16bits *end = p + pn->length/sizeof(*p);
+ int lines = 0; /* lines seen so far */
+ int zeros = 0; /* number of consecutive zero bits seen */
+ int EOLcnt = 0; /* number of consecutive EOLs seen */
+ int empty = 1; /* empty line */
+ int prezeros, postzeros;
+
+ while (p < end && EOLcnt < 6) {
+ t16bits bits = *p++;
+ check(bits&255);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((bits & 0x100) == 0))
+ zeros--;
+ }
+ check(bits>>8);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((p < end) && ((*p & 1) == 0)))
+ zeros--;
+ }
+ }
+ return lines - EOLcnt; /* don't count trailing EOLs */
+}