summaryrefslogtreecommitdiffstats
path: root/kfaxview/libkfaximage
diff options
context:
space:
mode:
Diffstat (limited to 'kfaxview/libkfaximage')
-rw-r--r--kfaxview/libkfaximage/Makefile.am14
-rw-r--r--kfaxview/libkfaximage/faxexpand.cpp745
-rw-r--r--kfaxview/libkfaximage/faxexpand.h126
-rw-r--r--kfaxview/libkfaximage/faxinit.cpp345
-rw-r--r--kfaxview/libkfaximage/kfaximage.cpp667
-rw-r--r--kfaxview/libkfaximage/kfaximage.h162
6 files changed, 2059 insertions, 0 deletions
diff --git a/kfaxview/libkfaximage/Makefile.am b/kfaxview/libkfaximage/Makefile.am
new file mode 100644
index 00000000..616afb3c
--- /dev/null
+++ b/kfaxview/libkfaximage/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(top_srcdir) $(all_includes)
+
+lib_LTLIBRARIES = libkfaximage.la
+libkfaximage_la_LDFLAGS = $(all_libraries) -no-undefined -avoid-version
+libkfaximage_la_LIBADD = $(LIB_KDECORE)
+libkfaximage_la_SOURCES = kfaximage.cpp faxexpand.cpp faxinit.cpp
+
+include_HEADERS = kfaximage.h
+noinst_HEADERS = faxexpand.h
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) $(libkfaximage_la_SOURCES) -o $(podir)/libkfaximgage.pot
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 */
+}
diff --git a/kfaxview/libkfaximage/faxexpand.h b/kfaxview/libkfaximage/faxexpand.h
new file mode 100644
index 00000000..8da4e8bc
--- /dev/null
+++ b/kfaxview/libkfaximage/faxexpand.h
@@ -0,0 +1,126 @@
+/* Include file for fax routines
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+ Copyright (C) 2005 Helge Deller <deller@kde.org>
+
+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. */
+
+#ifndef _faxexpand_h_
+#define _faxexpand_h_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qimage.h>
+
+#define t32bits Q_UINT32
+#define t16bits Q_UINT16
+
+typedef t16bits pixnum;
+
+class pagenode;
+
+/* drawfunc() points to a function which processes a line of the
+ expanded image described as a list of run lengths.
+ run is the base of an array of lengths, starting with a
+ (possibly empty) white run for line number linenum.
+ pn points to the page descriptor */
+typedef void (*drawfunc)(pixnum *run, int linenum, class pagenode *pn);
+
+struct strip { /* tiff strip descriptor */
+ off_t offset; /* offset in file */
+ off_t size; /* size of this strip */
+};
+
+
+/* defines for the pagenode member: type */
+#define FAX_TIFF 1
+#define FAX_RAW 2
+
+class pagenode { /* compressed page descriptor */
+ public:
+ pagenode();
+ ~pagenode() { };
+ int nstrips; /* number of strips */
+ int rowsperstrip; /* number of rows per strip */
+ int stripnum; /* current strip while expanding */
+ struct strip *strips; /* array of strips containing fax data in file */
+ t16bits *data; /* in-memory copy of strip */
+ size_t length; /* length of data */
+ QSize size; /* width & height of page in pixels */
+ int inverse; /* black <=> white */
+ int lsbfirst; /* bit order is lsb first */
+ int type; /* Bernd: tiff vs no tiff*/
+ int orient; /* orientation - upsidedown, landscape, mirrored */
+ int vres; /* vertical resolution: 1 = fine */
+ QPoint dpi; /* DPI horz/vert */
+ void (*expander)(class pagenode *, drawfunc);
+ QImage image;
+ unsigned int bytes_per_line;
+};
+
+extern class pagenode *firstpage, *lastpage, *thispage;
+extern class pagenode defaultpage;
+
+/* page orientation flags */
+#define TURN_NONE 0
+#define TURN_U 1
+#define TURN_L 2
+#define TURN_M 4
+
+/* fsm state codes */
+#define S_Null 0
+#define S_Pass 1
+#define S_Horiz 2
+#define S_V0 3
+#define S_VR 4
+#define S_VL 5
+#define S_Ext 6
+#define S_TermW 7
+#define S_TermB 8
+#define S_MakeUpW 9
+#define S_MakeUpB 10
+#define S_MakeUp 11
+#define S_EOL 12
+
+/* state table entry */
+struct tabent {
+ unsigned char State;
+ unsigned char Width; /* width of code in bits */
+ pixnum Param; /* run length */
+};
+
+extern struct tabent MainTable[]; /* 2-D state table */
+extern struct tabent WhiteTable[]; /* White run lengths */
+extern struct tabent BlackTable[]; /* Black run lengths */
+
+void MHexpand(class pagenode *pn, drawfunc df);
+void g31expand(class pagenode *pn, drawfunc df);
+void g32expand(class pagenode *pn, drawfunc df);
+void g4expand(class pagenode *pn, drawfunc df);
+
+unsigned char *getstrip(class pagenode *pn, int strip);
+class pagenode *notefile(const char *name);
+int notetiff(const char *name);
+
+/* initialise code tables */
+extern void fax_init_tables(void);
+
+/* count lines in image */
+extern int G3count(class pagenode *pn, int twoD);
+
+#endif
diff --git a/kfaxview/libkfaximage/faxinit.cpp b/kfaxview/libkfaximage/faxinit.cpp
new file mode 100644
index 00000000..aa6166aa
--- /dev/null
+++ b/kfaxview/libkfaximage/faxinit.cpp
@@ -0,0 +1,345 @@
+/* Initialise fax decoder tables
+ 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 <sys/types.h>
+#include "faxexpand.h"
+
+struct tabent MainTable[128];
+struct tabent WhiteTable[4096];
+struct tabent BlackTable[8192];
+
+struct proto {
+ t16bits code; /* right justified, lsb-first, zero filled */
+ t16bits val; /* (pixel count)<<4 + code width */
+};
+
+static const struct proto Pass[] = {
+{ 0x0008, 4 },
+{ 0, 0 }
+};
+
+static const struct proto Horiz[] = {
+{ 0x0004, 3 },
+{ 0, 0 }
+};
+
+static const struct proto V0[] = {
+{ 0x0001, 1 },
+{ 0, 0 }
+};
+
+static const struct proto VR[] = {
+{ 0x0006, (1<<4)+3 },
+{ 0x0030, (2<<4)+6 },
+{ 0x0060, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static const struct proto VL[] = {
+{ 0x0002, (1<<4)+3 },
+{ 0x0010, (2<<4)+6 },
+{ 0x0020, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static const struct proto ExtV[] = {
+{ 0x0040, 7 },
+{ 0, 0 }
+};
+
+static const struct proto EOLV[] = {
+{ 0x0000, 7 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUpW[] = {
+{ 0x001b, 1029 },
+{ 0x0009, 2053 },
+{ 0x003a, 3078 },
+{ 0x0076, 4103 },
+{ 0x006c, 5128 },
+{ 0x00ec, 6152 },
+{ 0x0026, 7176 },
+{ 0x00a6, 8200 },
+{ 0x0016, 9224 },
+{ 0x00e6, 10248 },
+{ 0x0066, 11273 },
+{ 0x0166, 12297 },
+{ 0x0096, 13321 },
+{ 0x0196, 14345 },
+{ 0x0056, 15369 },
+{ 0x0156, 16393 },
+{ 0x00d6, 17417 },
+{ 0x01d6, 18441 },
+{ 0x0036, 19465 },
+{ 0x0136, 20489 },
+{ 0x00b6, 21513 },
+{ 0x01b6, 22537 },
+{ 0x0032, 23561 },
+{ 0x0132, 24585 },
+{ 0x00b2, 25609 },
+{ 0x0006, 26630 },
+{ 0x01b2, 27657 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUpB[] = {
+{ 0x03c0, 1034 },
+{ 0x0130, 2060 },
+{ 0x0930, 3084 },
+{ 0x0da0, 4108 },
+{ 0x0cc0, 5132 },
+{ 0x02c0, 6156 },
+{ 0x0ac0, 7180 },
+{ 0x06c0, 8205 },
+{ 0x16c0, 9229 },
+{ 0x0a40, 10253 },
+{ 0x1a40, 11277 },
+{ 0x0640, 12301 },
+{ 0x1640, 13325 },
+{ 0x09c0, 14349 },
+{ 0x19c0, 15373 },
+{ 0x05c0, 16397 },
+{ 0x15c0, 17421 },
+{ 0x0dc0, 18445 },
+{ 0x1dc0, 19469 },
+{ 0x0940, 20493 },
+{ 0x1940, 21517 },
+{ 0x0540, 22541 },
+{ 0x1540, 23565 },
+{ 0x0b40, 24589 },
+{ 0x1b40, 25613 },
+{ 0x04c0, 26637 },
+{ 0x14c0, 27661 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUp[] = {
+{ 0x0080, 28683 },
+{ 0x0180, 29707 },
+{ 0x0580, 30731 },
+{ 0x0480, 31756 },
+{ 0x0c80, 32780 },
+{ 0x0280, 33804 },
+{ 0x0a80, 34828 },
+{ 0x0680, 35852 },
+{ 0x0e80, 36876 },
+{ 0x0380, 37900 },
+{ 0x0b80, 38924 },
+{ 0x0780, 39948 },
+{ 0x0f80, 40972 },
+{ 0, 0 }
+};
+
+static const struct proto TermW[] = {
+{ 0x00ac, 8 },
+{ 0x0038, 22 },
+{ 0x000e, 36 },
+{ 0x0001, 52 },
+{ 0x000d, 68 },
+{ 0x0003, 84 },
+{ 0x0007, 100 },
+{ 0x000f, 116 },
+{ 0x0019, 133 },
+{ 0x0005, 149 },
+{ 0x001c, 165 },
+{ 0x0002, 181 },
+{ 0x0004, 198 },
+{ 0x0030, 214 },
+{ 0x000b, 230 },
+{ 0x002b, 246 },
+{ 0x0015, 262 },
+{ 0x0035, 278 },
+{ 0x0072, 295 },
+{ 0x0018, 311 },
+{ 0x0008, 327 },
+{ 0x0074, 343 },
+{ 0x0060, 359 },
+{ 0x0010, 375 },
+{ 0x000a, 391 },
+{ 0x006a, 407 },
+{ 0x0064, 423 },
+{ 0x0012, 439 },
+{ 0x000c, 455 },
+{ 0x0040, 472 },
+{ 0x00c0, 488 },
+{ 0x0058, 504 },
+{ 0x00d8, 520 },
+{ 0x0048, 536 },
+{ 0x00c8, 552 },
+{ 0x0028, 568 },
+{ 0x00a8, 584 },
+{ 0x0068, 600 },
+{ 0x00e8, 616 },
+{ 0x0014, 632 },
+{ 0x0094, 648 },
+{ 0x0054, 664 },
+{ 0x00d4, 680 },
+{ 0x0034, 696 },
+{ 0x00b4, 712 },
+{ 0x0020, 728 },
+{ 0x00a0, 744 },
+{ 0x0050, 760 },
+{ 0x00d0, 776 },
+{ 0x004a, 792 },
+{ 0x00ca, 808 },
+{ 0x002a, 824 },
+{ 0x00aa, 840 },
+{ 0x0024, 856 },
+{ 0x00a4, 872 },
+{ 0x001a, 888 },
+{ 0x009a, 904 },
+{ 0x005a, 920 },
+{ 0x00da, 936 },
+{ 0x0052, 952 },
+{ 0x00d2, 968 },
+{ 0x004c, 984 },
+{ 0x00cc, 1000 },
+{ 0x002c, 1016 },
+{ 0, 0 }
+};
+
+static const struct proto TermB[] = {
+{ 0x03b0, 10 },
+{ 0x0002, 19 },
+{ 0x0003, 34 },
+{ 0x0001, 50 },
+{ 0x0006, 67 },
+{ 0x000c, 84 },
+{ 0x0004, 100 },
+{ 0x0018, 117 },
+{ 0x0028, 134 },
+{ 0x0008, 150 },
+{ 0x0010, 167 },
+{ 0x0050, 183 },
+{ 0x0070, 199 },
+{ 0x0020, 216 },
+{ 0x00e0, 232 },
+{ 0x0030, 249 },
+{ 0x03a0, 266 },
+{ 0x0060, 282 },
+{ 0x0040, 298 },
+{ 0x0730, 315 },
+{ 0x00b0, 331 },
+{ 0x01b0, 347 },
+{ 0x0760, 363 },
+{ 0x00a0, 379 },
+{ 0x0740, 395 },
+{ 0x00c0, 411 },
+{ 0x0530, 428 },
+{ 0x0d30, 444 },
+{ 0x0330, 460 },
+{ 0x0b30, 476 },
+{ 0x0160, 492 },
+{ 0x0960, 508 },
+{ 0x0560, 524 },
+{ 0x0d60, 540 },
+{ 0x04b0, 556 },
+{ 0x0cb0, 572 },
+{ 0x02b0, 588 },
+{ 0x0ab0, 604 },
+{ 0x06b0, 620 },
+{ 0x0eb0, 636 },
+{ 0x0360, 652 },
+{ 0x0b60, 668 },
+{ 0x05b0, 684 },
+{ 0x0db0, 700 },
+{ 0x02a0, 716 },
+{ 0x0aa0, 732 },
+{ 0x06a0, 748 },
+{ 0x0ea0, 764 },
+{ 0x0260, 780 },
+{ 0x0a60, 796 },
+{ 0x04a0, 812 },
+{ 0x0ca0, 828 },
+{ 0x0240, 844 },
+{ 0x0ec0, 860 },
+{ 0x01c0, 876 },
+{ 0x0e40, 892 },
+{ 0x0140, 908 },
+{ 0x01a0, 924 },
+{ 0x09a0, 940 },
+{ 0x0d40, 956 },
+{ 0x0340, 972 },
+{ 0x05a0, 988 },
+{ 0x0660, 1004 },
+{ 0x0e60, 1020 },
+{ 0, 0 }
+};
+
+static const struct proto ExtH[] = {
+{ 0x0100, 9 },
+{ 0, 0 }
+};
+
+static const struct proto EOLH[] = {
+{ 0x0000, 11 },
+{ 0, 0 }
+};
+
+static void
+FillTable(struct tabent *T, int Size, const struct proto *P, int State)
+{
+ int limit = 1 << Size;
+
+ while (P->val) {
+ int width = P->val & 15;
+ int param = P->val >> 4;
+ int incr = 1 << width;
+ int code;
+ for (code = P->code; code < limit; code += incr) {
+ struct tabent *E = T+code;
+ E->State = State;
+ E->Width = width;
+ E->Param = param;
+ }
+ P++;
+ }
+}
+
+/* initialise the huffman code tables */
+void
+fax_init_tables(void)
+{
+ static bool already_initialized = 0;
+ if (already_initialized)
+ return;
+
+ ++already_initialized;
+
+ FillTable(MainTable, 7, Pass, S_Pass);
+ FillTable(MainTable, 7, Horiz, S_Horiz);
+ FillTable(MainTable, 7, V0, S_V0);
+ FillTable(MainTable, 7, VR, S_VR);
+ FillTable(MainTable, 7, VL, S_VL);
+ FillTable(MainTable, 7, ExtV, S_Ext);
+ FillTable(MainTable, 7, EOLV, S_EOL);
+ FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW);
+ FillTable(WhiteTable, 12, MakeUp, S_MakeUp);
+ FillTable(WhiteTable, 12, TermW, S_TermW);
+ FillTable(WhiteTable, 12, ExtH, S_Ext);
+ FillTable(WhiteTable, 12, EOLH, S_EOL);
+ FillTable(BlackTable, 13, MakeUpB, S_MakeUpB);
+ FillTable(BlackTable, 13, MakeUp, S_MakeUp);
+ FillTable(BlackTable, 13, TermB, S_TermB);
+ FillTable(BlackTable, 13, ExtH, S_Ext);
+ FillTable(BlackTable, 13, EOLH, S_EOL);
+}
diff --git a/kfaxview/libkfaximage/kfaximage.cpp b/kfaxview/libkfaximage/kfaximage.cpp
new file mode 100644
index 00000000..28744923
--- /dev/null
+++ b/kfaxview/libkfaximage/kfaximage.cpp
@@ -0,0 +1,667 @@
+/*
+ This file is part of KDE FAX image library
+ Copyright (c) 2005 Helge Deller <deller@kde.org>
+
+ based on Frank D. Cringle's viewfax package
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. 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 <qimage.h>
+#include <qfile.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "faxexpand.h"
+#include "kfaximage.h"
+
+static const char FAXMAGIC[] = "\000PC Research, Inc\000\000\000\000\000\000";
+static const char littleTIFF[] = "\x49\x49\x2a\x00";
+static const char bigTIFF[] = "\x4d\x4d\x00\x2a";
+
+KFaxImage::KFaxImage( const QString &filename, QObject *parent, const char *name )
+ : QObject(parent,name)
+{
+ KGlobal::locale()->insertCatalogue( QString::fromLatin1("libkfaximage") );
+ loadImage(filename);
+}
+
+KFaxImage::~KFaxImage()
+{ }
+
+bool KFaxImage::loadImage( const QString &filename )
+{
+ reset();
+
+ m_filename = filename;
+ m_errorString = QString::null;
+
+ if (m_filename.isEmpty())
+ return false;
+
+ int ok = notetiff();
+ if (!ok) {
+ reset();
+ }
+ return ok == 1;
+}
+
+void KFaxImage::reset()
+{
+ fax_init_tables();
+ m_pagenodes.setAutoDelete(true);
+ m_pagenodes.clear();
+ // do not reset m_errorString and m_filename, since
+ // they may be needed by calling application
+}
+
+QImage KFaxImage::page( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page() called with invalid page number\n";
+ return QImage();
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->image;
+}
+
+QPoint KFaxImage::page_dpi( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page_dpi() called with invalid page number\n";
+ return QPoint(0,0);
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->dpi;
+}
+
+QSize KFaxImage::page_size( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page_size() called with invalid page number\n";
+ return QSize(0,0);
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->size;
+}
+
+
+pagenode *KFaxImage::AppendImageNode(int type)
+{
+ pagenode *pn = new pagenode();
+ if (pn) {
+ pn->type = type;
+ pn->expander = g31expand;
+ pn->strips = NULL;
+ pn->size = QSize(1728,2339);
+ pn->vres = -1;
+ pn->dpi = KFAX_DPI_FINE;
+ m_pagenodes.append(pn);
+ }
+ return pn;
+}
+
+bool KFaxImage::NewImage(pagenode *pn, int w, int h)
+{
+ pn->image = QImage( w, h, 1, 2, QImage::systemByteOrder() );
+ pn->image.setColor(0, qRgb(255,255,255));
+ pn->image.setColor(1, qRgb(0,0,0));
+ pn->data = (Q_UINT16*) pn->image.bits();
+ pn->bytes_per_line = pn->image.bytesPerLine();
+ pn->dpi = KFAX_DPI_FINE;
+
+ return !pn->image.isNull();
+}
+
+void KFaxImage::FreeImage(pagenode *pn)
+{
+ pn->image = QImage();
+ pn->data = NULL;
+ pn->bytes_per_line = 0;
+}
+
+void KFaxImage::kfaxerror(const QString& error)
+{
+ m_errorString = error;
+ kdError() << "kfaxerror: " << error << endl;
+}
+
+
+/* Enter an argument in the linked list of pages */
+pagenode *
+KFaxImage::notefile(int type)
+{
+ pagenode *newnode = new pagenode();
+ newnode->type = type;
+ newnode->size = QSize(1728,0);
+ return newnode;
+}
+
+static t32bits
+get4(unsigned char *p, QImage::Endian endian)
+{
+ return (endian == QImage::BigEndian)
+ ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
+ p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+}
+
+static int
+get2(unsigned char *p, QImage::Endian endian)
+{
+ return (endian == QImage::BigEndian) ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
+}
+
+/* generate pagenodes for the images in a tiff file */
+int
+KFaxImage::notetiff()
+{
+#define SC(x) (char *)(x)
+ unsigned char header[8];
+ QImage::Endian endian;
+ t32bits IFDoff;
+ pagenode *pn = NULL;
+ QString str;
+
+ QFile file(filename());
+ if (!file.open(IO_ReadOnly)) {
+ kfaxerror(i18n("Unable to open file for reading."));
+ return 0;
+ }
+
+ if (file.readBlock(SC(header), 8) != 8) {
+ kfaxerror(i18n("Unable to read file header (file too short)."));
+ return 0;
+ }
+ if (memcmp(header, &littleTIFF, 4) == 0)
+ endian = QImage::LittleEndian;
+ else if (memcmp(header, &bigTIFF, 4) == 0)
+ endian = QImage::BigEndian;
+ else {
+ maybe_RAW_FAX:
+ kfaxerror(i18n("This is not a TIFF FAX file."));
+ // AppendImageNode(FAX_RAW);
+ return 0;
+ }
+ IFDoff = get4(header+4, endian);
+ if (IFDoff & 1) {
+ goto maybe_RAW_FAX;
+ }
+ do { /* for each page */
+ unsigned char buf[8];
+ unsigned char *dir = NULL , *dp = NULL;
+ int ndirent;
+ pixnum iwidth = 1728;
+ pixnum iheight = 2339;
+ int inverse = false;
+ int lsbfirst = 0;
+ int t4opt = 0, comp = 0;
+ int orient = TURN_NONE;
+ int yres = 196; /* 98.0 */
+ struct strip *strips = NULL;
+ unsigned int rowsperstrip = 0;
+ t32bits nstrips = 1;
+
+ if (!file.at(IFDoff)) {
+ realbad:
+ kfaxerror( i18n("Invalid or incomplete TIFF file.") );
+ bad:
+ if (strips)
+ free(strips);
+ if (dir)
+ free(dir);
+ file.close();
+ return 1;
+ }
+ if (file.readBlock(SC(buf), 2) != 2)
+ goto realbad;
+ ndirent = get2(buf, endian);
+ int len = 12*ndirent+4;
+ dir = (unsigned char *) malloc(len);
+ if (file.readBlock(SC(dir), len) != len)
+ goto realbad;
+ for (dp = dir; ndirent; ndirent--, dp += 12) {
+ /* for each directory entry */
+ int tag, ftype;
+ t32bits count, value = 0;
+ tag = get2(dp, endian);
+ ftype = get2(dp+2, endian);
+ count = get4(dp+4, endian);
+ switch(ftype) { /* value is offset to list if count*size > 4 */
+ case 3: /* short */
+ value = get2(dp+8, endian);
+ break;
+ case 4: /* long */
+ value = get4(dp+8, endian);
+ break;
+ case 5: /* offset to rational */
+ value = get4(dp+8, endian);
+ break;
+ }
+ switch(tag) {
+ case 256: /* ImageWidth */
+ iwidth = value;
+ break;
+ case 257: /* ImageLength */
+ iheight = value;
+ break;
+ case 259: /* Compression */
+ comp = value;
+ break;
+ case 262: /* PhotometricInterpretation */
+ inverse ^= (value == 1);
+ break;
+ case 266: /* FillOrder */
+ lsbfirst = (value == 2);
+ break;
+ case 273: /* StripOffsets */
+ nstrips = count;
+ strips = (struct strip *) malloc(count * sizeof *strips);
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].offset = value;
+ if (count == 2)
+ strips[1].offset = get2(dp+10, endian);
+ break;
+ }
+ if (!file.at(value))
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0)
+ goto realbad;
+ strips[count].offset = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 274: /* Orientation */
+ switch(value) {
+ default: /* row0 at top, col0 at left */
+ orient = 0;
+ break;
+ case 2: /* row0 at top, col0 at right */
+ orient = TURN_M;
+ break;
+ case 3: /* row0 at bottom, col0 at right */
+ orient = TURN_U;
+ break;
+ case 4: /* row0 at bottom, col0 at left */
+ orient = TURN_U|TURN_M;
+ break;
+ case 5: /* row0 at left, col0 at top */
+ orient = TURN_M|TURN_L;
+ break;
+ case 6: /* row0 at right, col0 at top */
+ orient = TURN_U|TURN_L;
+ break;
+ case 7: /* row0 at right, col0 at bottom */
+ orient = TURN_U|TURN_M|TURN_L;
+ break;
+ case 8: /* row0 at left, col0 at bottom */
+ orient = TURN_L;
+ break;
+ }
+ break;
+ case 278: /* RowsPerStrip */
+ rowsperstrip = value;
+ break;
+ case 279: /* StripByteCounts */
+ if (count != nstrips) {
+ str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n")
+ .arg(filename()).arg(nstrips).arg(count);
+ kfaxerror(str);
+ goto realbad;
+ }
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].size = value;
+ if (count == 2)
+ strips[1].size = get2(dp+10, endian);
+ break;
+ }
+ if (!file.at(value))
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0)
+ goto realbad;
+ strips[count].size = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 283: /* YResolution */
+ if (!file.at(value) ||
+ file.readBlock(SC(buf), 8) != 8)
+ goto realbad;
+ yres = get4(buf, endian) / get4(buf+4, endian);
+ break;
+ case 292: /* T4Options */
+ t4opt = value;
+ break;
+ case 293: /* T6Options */
+ /* later */
+ break;
+ case 296: /* ResolutionUnit */
+ if (value == 3)
+ yres = (yres * 254) / 100; /* *2.54 */
+ break;
+ }
+ }
+ IFDoff = get4(dp, endian);
+ free(dir);
+ dir = NULL;
+ if (comp == 5) {
+ // compression type 5 is LZW compression // XXX
+ kfaxerror(i18n("Due to patent reasons LZW (Lempel-Ziv & Welch) "
+ "compressed Fax files cannot be loaded yet.\n"));
+ goto bad;
+ }
+ if (comp < 2 || comp > 4) {
+ kfaxerror(i18n("This version can only handle Fax files\n"));
+ goto bad;
+ }
+ pn = AppendImageNode(FAX_TIFF);
+ pn->nstrips = nstrips;
+ pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight;
+ pn->strips = strips;
+ pn->size = QSize(iwidth,iheight);
+ pn->inverse = inverse;
+ pn->lsbfirst = lsbfirst;
+ pn->orient = orient;
+ pn->dpi.setY(yres);
+ pn->vres = (yres > 150) ? 1:0; /* arbitrary threshold for fine resolution */
+ if (comp == 2)
+ pn->expander = MHexpand;
+ else if (comp == 3)
+ pn->expander = (t4opt & 1) ? g32expand : g31expand;
+ else
+ pn->expander = g4expand;
+ } while (IFDoff);
+ file.close();
+ return 1;
+#undef UC
+}
+
+/* report error and remove bad file from the list */
+void
+KFaxImage::badfile(pagenode *pn)
+{
+ kfaxerror(i18n("%1: Bad Fax File").arg(filename()));
+ FreeImage(pn);
+}
+
+/* rearrange input bits into t16bits lsb-first chunks */
+static void
+normalize(pagenode *pn, int revbits, int swapbytes, size_t length)
+{
+ t32bits *p = (t32bits *) pn->data;
+
+ kdDebug() << "normalize = " << ((revbits<<1)|swapbytes) << endl;
+ switch ((revbits<<1)|swapbytes) {
+ case 0:
+ break;
+ case 1:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ }
+ break;
+ case 2:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ break;
+ case 3:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ }
+}
+
+
+/* get compressed data into memory */
+unsigned char *
+KFaxImage::getstrip(pagenode *pn, int strip)
+{
+ size_t offset, roundup;
+ unsigned char *Data;
+
+ union { t16bits s; unsigned char b[2]; } so;
+#define ShortOrder so.b[1]
+ so.s = 1; /* XXX */
+
+ QFile file(filename());
+ if (!file.open(IO_ReadOnly)) {
+ badfile(pn);
+ return NULL;
+ }
+
+ if (pn->strips == NULL) {
+ offset = 0;
+ pn->length = file.size();
+ }
+ else if (strip < pn->nstrips) {
+ offset = pn->strips[strip].offset;
+ pn->length = pn->strips[strip].size;
+ }
+ else {
+ kfaxerror( i18n("Trying to expand too many strips.") );
+ return NULL;
+ }
+
+ /* round size to full boundary plus t32bits */
+ roundup = (pn->length + 7) & ~3;
+
+ Data = (unsigned char *) malloc(roundup);
+ /* clear the last 2 t32bits, to force the expander to terminate
+ even if the file ends in the middle of a fax line */
+ *((t32bits *) Data + roundup/4 - 2) = 0;
+ *((t32bits *) Data + roundup/4 - 1) = 0;
+
+ /* we expect to get it in one gulp... */
+ if (!file.at(offset) ||
+ (size_t) file.readBlock((char *)Data, pn->length) != pn->length) {
+ badfile(pn);
+ free(Data);
+ return NULL;
+ }
+ file.close();
+
+ pn->data = (t16bits *) Data;
+ if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)-1) == 0) {
+ /* handle ghostscript / PC Research fax file */
+ if (Data[24] != 1 || Data[25] != 0){
+ kfaxerror( i18n("Only the first page of the PC Research multipage file will be shown.") );
+ }
+ pn->length -= 64;
+ pn->vres = Data[29];
+ pn->data += 32;
+ roundup -= 64;
+ }
+
+ normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
+ if (pn->size.height() == 0)
+ pn->size.setHeight( G3count(pn, pn->expander == g32expand) );
+ if (pn->size.height() == 0) {
+
+ kfaxerror( i18n("No fax found in file.") );
+ badfile(pn);
+ free(Data);
+ return NULL;
+ }
+ if (pn->strips == NULL)
+ pn->rowsperstrip = pn->size.height();
+ return Data;
+}
+
+
+static void
+drawline(pixnum *run, int LineNum, pagenode *pn)
+{
+ t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */
+ pixnum *r; /* pointer to run-lengths */
+ t32bits pix; /* current pixel value */
+ t32bits acc; /* pixel accumulator */
+ int nacc; /* number of valid bits in acc */
+ int tot; /* total pixels in line */
+ int n;
+
+ LineNum += pn->stripnum * pn->rowsperstrip;
+ if (LineNum >= pn->size.height()) {
+ if (LineNum == pn->size.height())
+ kdError() << "Height exceeded\n";
+ return;
+ }
+
+ p = (t32bits *) pn->image.scanLine(LineNum*(2-pn->vres));
+ p1 =(t32bits *)( pn->vres ? 0 : pn->image.scanLine(1+LineNum*(2-pn->vres)));
+ r = run;
+ acc = 0;
+ nacc = 0;
+ pix = pn->inverse ? ~0 : 0;
+ tot = 0;
+ while (tot < pn->size.width()) {
+ n = *r++;
+ tot += n;
+ /* Watch out for buffer overruns, e.g. when n == 65535. */
+ if (tot > pn->size.width())
+ break;
+ if (pix)
+ acc |= (~(t32bits)0 >> nacc);
+ else if (nacc)
+ acc &= (~(t32bits)0 << (32 - nacc));
+ else
+ acc = 0;
+ if (nacc + n < 32) {
+ nacc += n;
+ pix = ~pix;
+ continue;
+ }
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ n -= 32 - nacc;
+ while (n >= 32) {
+ n -= 32;
+ *p++ = pix;
+ if (p1)
+ *p1++ = pix;
+ }
+ acc = pix;
+ nacc = n;
+ pix = ~pix;
+ }
+ if (nacc) {
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ }
+}
+
+int
+KFaxImage::GetPartImage(pagenode *pn, int n)
+{
+ unsigned char *Data = getstrip(pn, n);
+ if (Data == 0)
+ return 3;
+ pn->stripnum = n;
+ (*pn->expander)(pn, drawline);
+ free(Data);
+ return 1;
+}
+
+int
+KFaxImage::GetImage(pagenode *pn)
+{
+ if (!pn->image.isNull())
+ return 1;
+
+ int i;
+ if (pn->strips == 0) {
+
+ kdDebug() << "Loading RAW fax file " << m_filename << " size=" << pn->size << endl;
+
+ /* raw file; maybe we don't have the height yet */
+ unsigned char *Data = getstrip(pn, 0);
+ if (Data == 0){
+ return 0;
+ }
+ if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height()))
+ return 0;
+
+ (*pn->expander)(pn, drawline);
+ }
+ else {
+ /* multi-strip tiff */
+ kdDebug() << "Loading MULTI STRIP TIFF fax file " << m_filename << endl;
+
+ if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height()))
+ return 0;
+ pn->stripnum = 0;
+ kdDebug() << "has " << pn->nstrips << " strips.\n";
+ for (i = 0; i < pn->nstrips; i++){
+
+ int k = GetPartImage(pn, i);
+ if ( k == 3 ){
+ FreeImage(pn);
+ kfaxerror( i18n("Fax G3 format not yet supported.") );
+ return k;
+ }
+
+ }
+ }
+
+ // byte-swapping the image on little endian machines
+#if defined(Q_BYTE_ORDER) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
+ for (int y=pn->image.height()-1; y>=0; --y) {
+ Q_UINT32 *source = (Q_UINT32 *) pn->image.scanLine(y);
+ Q_UINT32 *dest = source;
+ for (int x=(pn->bytes_per_line/4)-1; x>=0; --x) {
+ Q_UINT32 dv = 0, sv = *source;
+ for (int bit=32; bit>0; --bit) {
+ dv <<= 1;
+ dv |= sv&1;
+ sv >>= 1;
+ }
+ *dest = dv;
+ ++dest;
+ ++source;
+ }
+ }
+#endif
+
+ kdDebug() << filename()
+ << "\n\tsize = " << pn->size
+ << "\n\tDPI = " << pn->dpi
+ << "\n\tresolution = " << (pn->vres ? "fine" : "normal")
+ << endl;
+
+ return 1;
+}
+
+
+#include "kfaximage.moc"
diff --git a/kfaxview/libkfaximage/kfaximage.h b/kfaxview/libkfaximage/kfaximage.h
new file mode 100644
index 00000000..0ed2db90
--- /dev/null
+++ b/kfaxview/libkfaximage/kfaximage.h
@@ -0,0 +1,162 @@
+/*
+ This file is part of KDE FAX image loading library
+ Copyright (c) 2005 Helge Deller <deller@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _LIBKFAXIMAGE_H_
+#define _LIBKFAXIMAGE_H_
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qimage.h>
+#include <qptrlist.h>
+#include <kdelibs_export.h>
+
+class pagenode;
+
+
+/**
+ * This is KFaxImage, a class for loading FAX files under KDE
+ *
+ * @short KFaxImage
+ * @author Helge Deller
+ * @version 0.1
+ *
+ *
+ * Standard fax dpi values:
+ * ------------------------
+ * Standard: 203 dpi x 98 lpi
+ * Fine: 203 dpi x 196 lpi
+ * Super Fine: 203 dpi y 392 lpi, or
+ * 406 dpi x 392 lpi
+ */
+
+#define KFAX_DPI_STANDARD QPoint(203,98)
+#define KFAX_DPI_FINE QPoint(203,196)
+#define KFAX_DPI_SUPERFINE QPoint(406,392)
+
+
+class KDE_EXPORT KFaxImage : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * KFaxImage - the KDE FAX loader class
+ * constructor.
+ * @param filename: an optional FAX file which should be loaded.
+ * @see: numPages
+ */
+
+ KFaxImage( const QString &filename = QString::null, QObject *parent = 0, const char *name = 0 );
+
+ /**
+ * Destructor
+ *
+ * releases internal allocated memory.
+ */
+
+ virtual ~KFaxImage();
+
+ /**
+ * loads the FAX image and returns true when sucessful.
+ * @param filename: the file which should be loaded.
+ * @return boolean value on success or failure
+ * @see: numPages
+ * @see: errorString
+ */
+
+ bool loadImage( const QString &filename );
+
+ /**
+ * returns currently loaded image file name.
+ * @return FAX filename
+ */
+
+ QString filename() { return m_filename; };
+
+ /**
+ * returns number of pages which are stored in the FAX file
+ * @return page count
+ */
+
+ unsigned int numPages() const { return m_pagenodes.count(); };
+
+ /**
+ * returns a QImage which holds the contents of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return QImage of the page pageNr
+ */
+
+ QImage page( unsigned int pageNr );
+
+ /**
+ * returns the DPI (dots per inch) of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return a QPoint value with the DPIs in X- and Y-direction
+ */
+
+ QPoint page_dpi( unsigned int pageNr );
+
+ /**
+ * returns the physical pixels of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return a QSize value with the width and height of the image
+ */
+
+ QSize page_size( unsigned int pageNr );
+
+ /**
+ * @return a user-visible, translated error string
+ */
+
+ const QString errorString() const { return m_errorString; };
+
+
+
+ private:
+
+ /**
+ * private member variables
+ */
+
+ QString m_filename;
+ QString m_errorString;
+
+ typedef QPtrList<pagenode> t_PageNodeList;
+ t_PageNodeList m_pagenodes;
+
+ /**
+ * private member functions
+ */
+
+ void reset();
+ void kfaxerror(const QString& error);
+ pagenode *AppendImageNode(int type);
+ bool NewImage(pagenode *pn, int w, int h);
+ void FreeImage(pagenode *pn);
+ unsigned char *getstrip(pagenode *pn, int strip);
+ int GetPartImage(pagenode *pn, int n);
+ int GetImage(pagenode *pn);
+ pagenode *notefile(int type);
+ int notetiff();
+ void badfile(pagenode *pn);
+};
+
+#endif /* _LIBKFAXIMAGE_H_ */
+