diff options
Diffstat (limited to 'kfax')
32 files changed, 5421 insertions, 0 deletions
diff --git a/kfax/AUTHORS b/kfax/AUTHORS new file mode 100644 index 00000000..88b4ef2b --- /dev/null +++ b/kfax/AUTHORS @@ -0,0 +1,3 @@ +Bernd Johannes Wuebben +wuebben@math.cornell.edu +wuebben@kde.org diff --git a/kfax/ChangeLog b/kfax/ChangeLog new file mode 100644 index 00000000..39accef4 --- /dev/null +++ b/kfax/ChangeLog @@ -0,0 +1,28 @@ +1999-03-03 Harri Porten <porten@kde.org> + + * viewfax.cpp: prefix getopt declarations with 'extern'. Bug reported + by Oliver Oster <olio@zait.uni-bremen.de> + +1999-02-08 Harri Porten <porten@kde.org> + + * fixed segfault caused by infinite recursion in kfaxerror() + +Sun May 3 16:48:13 1998 Bernd Johannes Wuebben <wuebben@math.cornell.edu> + + * fixed print dialog + adjusted layout for i18n + +Sun Oct 5 22:17:09 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu> + + * added support for printing all fax formats at all printer page + sizes. + +Sun Aug 3 09:55:52 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu> + + * Made kfax work with the new KToolBar etc. + +Thu Jul 24 20:44:33 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu> + + * made the necessary changes so that kfax will compile with + the new libs. + diff --git a/kfax/Makefile.am b/kfax/Makefile.am new file mode 100644 index 00000000..fd3e478c --- /dev/null +++ b/kfax/Makefile.am @@ -0,0 +1,32 @@ +AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) +LDADD = $(LIB_KFILE) $(LIB_KDEPRINT) -lm +INCLUDES = $(all_includes) + +####### Files +noinst_HEADERS = kfax.h faxexpand.h options.h + +kfax_SOURCES = options.cpp kfax.cpp faxexpand.cpp faxinit.cpp faxinput.cpp \ + viewfax.cpp kfax_printsettings.cpp + +METASOURCES = AUTO + +bin_PROGRAMS = kfax + +xdg_apps_DATA = kfax.desktop + +picsdir = $(kde_datadir)/kfax/pics +pics_DATA = kfax.tif kfaxlogo.xpm + +rcdir = $(kde_datadir)/kfax +rc_DATA = kfaxui.rc + +KDE_ICON = kfax + +EXTRA_DIST = $(xdg_apps_DATA) $(pics_DATA) + +messages: rc.cpp + $(XGETTEXT) $(kfax_SOURCES) -o $(podir)/kfax.pot + +####### Explicit dependencies + + diff --git a/kfax/NOTES b/kfax/NOTES new file mode 100644 index 00000000..9a3c70b6 --- /dev/null +++ b/kfax/NOTES @@ -0,0 +1,49 @@ + +Drag and Drop +Net Drag and Drop + +kfax can display all fax output modes of ghostscript: +raw: fag3 faxg32d faxg4 +tiff: tiffg3 tiffg32d tiffg4 + +By default raw fax files are interpreted as g3 files. If you want +to display faxg3-2d and faxg4 files you have to specifiy this on +the command line and in the case of raw g4 files also specify +the height in scan lines of the fax if it differs from the +default 2155. + +A raw file will have no pagignation information and will be displayed +as a whole in the fax window. +tiff files contain pagination information can be paged through in the +fax window + +kfax can not display image file formats which are not related to +faxing, such as an arbitrary tiff or gif file. + + +How to create fax file that sendfax /mgetty can accept and send: +gs -sDEVICE=faxg3 -sOutputFile=/tmp/fax.g3.%d yourdocument.ps + +Assume that you ps document yourdocumnet.ps contains three pages, +this will produce fax.g3.1 fax.g3.2 fax.g3.3 + + +HylaFAX: +http://info-sys.home.vix.com/flexfax/toc.html + +sendfax/mgetty: +http://www.leo.org/~doering/mgetty/ + +cat fax.g3 | g32pbm | pnmtops -noturn > output.ps + + + +How to print raw " no tiff " g3 fax data: + + + +fax2tiff -M viewfax.g3 -o viewfax.tiff +(M for: Treat input data as having bits filled from most + significant bit (MSB) to most least bit (LSB)) +This is what I need on my intel machine, I would presume this +might be different on a Sun station. diff --git a/kfax/README b/kfax/README new file mode 100644 index 00000000..23d3c6c2 --- /dev/null +++ b/kfax/README @@ -0,0 +1,34 @@ +KFax 0.3 + +Added printing for g32 and g4, so that kfax can now print all fax formats. +Added support for all pages sizes. + +Bernd +wuebben@kde.org + + +I am please to release KFax 0.2, the first public release of +KFax - a fax file viewer for the KDE project. + +Please peruse the accompanying html documentation for more information +about KFax + +Help wanted: +============ + +Much of my work was done "in vitro". Now it is time to go out into +the wilderness and test KFax: + +I need people to send me faxes from all sorts of programs and machines +in order to thoroughly test KFax and develop further ideas as to what needs +to be implemented. If you own a fax modem or a fax machine and you would +like to help, please write to me by email. I will then give you my phone +number and we will agree on which fax program I will used for reception. +You can then send me a fax from your favorite program or machine, stating +what machine/program you used, from where you sent the fax, what +the size of the fax is, the number of pages you transmitted etc. +This would be very helpful. Thanks for your coorporation. + +thanks, +Bernd Wuebben +wuebben@kde.org diff --git a/kfax/TODO b/kfax/TODO new file mode 100644 index 00000000..2e9d8464 --- /dev/null +++ b/kfax/TODO @@ -0,0 +1,2 @@ +o Page Marking +o Printing of only the Marked pages diff --git a/kfax/examples/README b/kfax/examples/README new file mode 100644 index 00000000..74631fe6 --- /dev/null +++ b/kfax/examples/README @@ -0,0 +1,22 @@ +If you have the kdeapps distributions, please also read README.kdeapps +thanks, +Bernd + +This directory contains a number of fax files which you can use to +test and play with KFax: + +kde.g3 a group 3 raw fax file +kde.g32d a group 3, 2-dim raw fax file +kde.g4 a group 4 raw fax file + +Note: the g32d and g4 raw fax files will not display correctly + unless you change the default raw fax file format on the + Fax Options dialog. + +kdefaq.tiff.g3 a tiff group 3 encoded fax file +kdefaq.tiff.g32d a tiff group 3, 2-dim, encoded fax file +kdefaq.tiff.g4 a tiff group 4 encoded fax file + +Note that the tiff file format is the superiour format. Each +of the above tiff fax files contains several pages. + diff --git a/kfax/examples/README.kdeapps b/kfax/examples/README.kdeapps new file mode 100644 index 00000000..6664690a --- /dev/null +++ b/kfax/examples/README.kdeapps @@ -0,0 +1,12 @@ +Note from the kdeapps maintainer: + +This directory used to contain several example fax files. Some of which are +raw fax files others tiff fax files. Since I need to keep the kdeapps +distributions small in size, I removed them with the permission of the author. +You will still find all example files in the original kfax distribution +at: + +ftp.kde.org//pub/kde/apps/graphics/ + +Stephan Kulow <coolo@kde.org> + diff --git a/kfax/examples/kde.g3 b/kfax/examples/kde.g3 Binary files differnew file mode 100644 index 00000000..a419e9af --- /dev/null +++ b/kfax/examples/kde.g3 diff --git a/kfax/examples/nasty.tiff b/kfax/examples/nasty.tiff Binary files differnew file mode 100644 index 00000000..e9edd50c --- /dev/null +++ b/kfax/examples/nasty.tiff diff --git a/kfax/faxexpand.cpp b/kfax/faxexpand.cpp new file mode 100644 index 00000000..93f1bc85 --- /dev/null +++ b/kfax/faxexpand.cpp @@ -0,0 +1,732 @@ +/* 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 <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include "faxexpand.h" + +//Uncomment this for verbose debug output +//#define DEBUG_FAX + +/* 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) + +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) \ + fprintf(stderr, "Line %d: extension code\n", LineNum); \ + SKIP_EOL; \ + break; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits(4); \ + if (GetBits(4) && verbose) /* already seen 7 zeros */ \ + fprintf(stderr, "Line %d: Bad EOL\n", LineNum); \ + 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) + fprintf(stderr, "Line %d: Unexpected state in %s\n", + LineNum, what); +} + +/* Expand tiff modified huffman data (g3-1d without EOLs) */ +void +MHexpand(struct pagenode *pn, drawfunc df) +{ + int a0; /* reference element */ + int lastx = pn->width; /* 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->width; + runs = (pixnum *) xmalloc(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) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + 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 = pn->width; /* 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->width; + runs = (pixnum *) xmalloc(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) + fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt); + 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) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + 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->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 *) xmalloc(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) + fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt); + if (EOLcnt >= 6 || EndOfData(pn)) { + free(run0); + return; + } + if (LineNum == 0 && refline == 0 && verbose) + fprintf(stderr, "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) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + 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) \ + fprintf(stderr, "Line %d: G4 coding error\n", LineNum); \ + 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->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 *) xmalloc(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) + fputs("Bad RTC\n", stderr); + break; + } + free(run0); +} + +static 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/kfax/faxexpand.h b/kfax/faxexpand.h new file mode 100644 index 00000000..a1be736f --- /dev/null +++ b/kfax/faxexpand.h @@ -0,0 +1,160 @@ +/* Include file for fax routines + 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. */ + +#ifndef _faxexpand_h_ +#define _faxexpand_h_ + +#include <limits.h> + +#if ULONG_MAX == 4294967295UL +typedef unsigned long t32bits; +#elif UINT_MAX == 4294967295UL +typedef unsigned int t32bits; +#else +#error need a 32-bit unsigned type +/* if you expirence the above error, and live to tell about it, + add an #elif case for your architecture + and tell wuebben@math.cornell.edu , wuebben@kde.org about it */ +#endif + +#if USHRT_MAX == 65535 +typedef unsigned short t16bits; +#elif UINT_MAX == 65535 +typedef unsigned int t16bits; +#else +#error need a 16-bit unsigned type +/* if you experience the above error, and live to tell about it, + add an #elif case for your architecture + and tell fdc@cliwe.ping.de about it */ +#endif +typedef t16bits pixnum; + +struct 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, struct 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 + +struct pagenode { /* compressed page descriptor */ + struct pagenode *prev, *next; /* list links */ + char *name; /* basename of file */ + char *pathname; /* full name of file */ + 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 */ + pixnum width; /* width of page in pixels */ + pixnum height; /* height of page in lines */ + 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 */ + int dpiX,dpiY; /* DPI horz/vert */ + void (*expander)(struct pagenode *, drawfunc); + void *extra; /* used for Ximage */ +}; +extern struct pagenode *firstpage, *lastpage, *thispage,* auxpage; +extern struct pagenode defaultpage; + +/* page orientation flags */ +#define TURN_U 1 +#define TURN_L 2 +#define TURN_M 4 + +extern const char *ProgName; + +/* 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 */ + +extern int verbose; + +void MHexpand(struct pagenode *pn, drawfunc df); +void g31expand(struct pagenode *pn, drawfunc df); +void g32expand(struct pagenode *pn, drawfunc df); +void g4expand(struct pagenode *pn, drawfunc df); + +unsigned char * getstrip(struct pagenode *pn, int strip); +struct pagenode *notefile(const char *name); +int notetiff(const char *name); + +/* initialise code tables */ +extern void faxinit(void); +/* count lines in image */ +extern int G3count(struct pagenode *pn, int twoD); + +/* get memory or abort if none available */ +extern char *xmalloc(unsigned int size); + +#ifdef __linux__ +#define _HAVE_USLEEP +#endif + +#if defined(BSD) || defined(__FreeBSD__) || defined(_BSD_SOURCE) +#define _HAVE_USLEEP +#ifndef rindex +#define rindex strrchr +#endif +#ifndef bcmp +#define memcmp bcmp +#endif +#define memclr(p,n) bzero(p,n) +#else /* not BSD */ +#define memclr(p,n) memset(p,0,n) +#endif + +#endif diff --git a/kfax/faxinit.cpp b/kfax/faxinit.cpp new file mode 100644 index 00000000..62ee0569 --- /dev/null +++ b/kfax/faxinit.cpp @@ -0,0 +1,337 @@ +/* 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 <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 struct proto Pass[] = { +{ 0x0008, 4 }, +{ 0, 0 } +}; + +static struct proto Horiz[] = { +{ 0x0004, 3 }, +{ 0, 0 } +}; + +static struct proto V0[] = { +{ 0x0001, 1 }, +{ 0, 0 } +}; + +static struct proto VR[] = { +{ 0x0006, (1<<4)+3 }, +{ 0x0030, (2<<4)+6 }, +{ 0x0060, (3<<4)+7 }, +{ 0, 0 } +}; + +static struct proto VL[] = { +{ 0x0002, (1<<4)+3 }, +{ 0x0010, (2<<4)+6 }, +{ 0x0020, (3<<4)+7 }, +{ 0, 0 } +}; + +static struct proto ExtV[] = { +{ 0x0040, 7 }, +{ 0, 0 } +}; + +static struct proto EOLV[] = { +{ 0x0000, 7 }, +{ 0, 0 } +}; + +static 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 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 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 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 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 struct proto ExtH[] = { +{ 0x0100, 9 }, +{ 0, 0 } +}; + +static struct proto EOLH[] = { +{ 0x0000, 11 }, +{ 0, 0 } +}; + +static void +FillTable(struct tabent *T, int Size, 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 +faxinit(void) +{ + 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/kfax/faxinput.cpp b/kfax/faxinput.cpp new file mode 100644 index 00000000..8ca7fe85 --- /dev/null +++ b/kfax/faxinput.cpp @@ -0,0 +1,479 @@ +/* Fax file input processing + 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include "faxexpand.h" +#include <qstring.h> +#include <qfile.h> +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> + +void statusbarupdate(char* name,int width,int height,char* res); +extern void kfaxerror(const QString& title, const QString& error); + +#define FAXMAGIC "\000PC Research, Inc\000\000\000\000\000\000" + +/* Enter an argument in the linked list of pages */ +struct pagenode * +notefile(const char *name, int type) +{ + struct pagenode *newnode = (struct pagenode *) xmalloc(sizeof *newnode); + + *newnode = defaultpage; + if (firstpage == NULL){ + firstpage = newnode; + auxpage = firstpage; + } + newnode->prev = lastpage; + newnode->next = NULL; + if (lastpage != NULL) + lastpage->next = newnode; + lastpage = newnode; + + // kdDebug() << "Adding new node " << newnode << endl; + + newnode->pathname = (char*) malloc (strlen(name) +1); + if(!newnode->pathname){ + kfaxerror(i18n("Sorry"),i18n("Out of memory\n")); + exit(1); + } + + strcpy(newnode->pathname,name); + + newnode->type = type; + + + if ((newnode->name = strrchr(newnode->pathname, '/')) != NULL) + newnode->name++; + else + newnode->name = newnode->pathname; + + if (newnode->width == 0) + newnode->width = 1728; + if (newnode->vres < 0) + newnode->vres = !(newnode->name[0] == 'f' && newnode->name[1] == 'n'); + newnode->extra = NULL; + + return newnode; +} + +static t32bits +get4(unsigned char *p, int endian) +{ + return endian ? (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, int endian) +{ + return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8); +} + +/* generate pagenodes for the images in a tiff file */ +int +notetiff(const char *name) +{ + + FILE *tf; + unsigned char header[8]; + static const char littleTIFF[5] = "\x49\x49\x2a\x00"; + static const char bigTIFF[5] = "\x4d\x4d\x00\x2a"; + int endian; + t32bits IFDoff; + struct pagenode *pn = NULL; + QString str; + + + if ((tf = fopen(name, "r")) == NULL) { + QString mesg = i18n("Unable to open:\n%1\n").arg(QFile::decodeName(name)); + kfaxerror(i18n("Sorry"), mesg); + return 0; + } + + if (fread(header, 8, 1, tf) == 0) { + nottiff: + fclose(tf); + (void) notefile(name,FAX_RAW); + return 0; + } + if (memcmp(header, &littleTIFF, 4) == 0) + endian = 0; + else if (memcmp(header, &bigTIFF, 4) == 0) + endian = 1; + else + goto nottiff; + IFDoff = get4(header+4, endian); + if (IFDoff & 1) + goto nottiff; + do { /* for each page */ + unsigned char buf[8]; + unsigned char *dir = NULL , *dp = NULL; + int ndirent; + pixnum iwidth = defaultpage.width ? defaultpage.width : 1728; + pixnum iheight = defaultpage.height ? defaultpage.height : 2339; + int inverse = defaultpage.inverse; + int lsbfirst = 0; + int t4opt = 0, comp = 0; + int orient = defaultpage.orient; + double yres = defaultpage.vres ? 196.0 : 98.0; + struct strip *strips = NULL; + unsigned long rowsperstrip = 0; + t32bits nstrips = 1; + + if (fseek(tf, IFDoff, SEEK_SET) < 0) { + realbad: + str = i18n("Invalid tiff file:\n%1\n").arg(QFile::decodeName(name)); + kfaxerror(i18n("Sorry"),str); + bad: + if (strips) + free(strips); + if (dir) + free(dir); + fclose(tf); + return 1; + } + if (fread(buf, 2, 1, tf) == 0) + goto realbad; + ndirent = get2(buf, endian); + dir = (unsigned char *) xmalloc(12*ndirent+4); + if (fread(dir, 12*ndirent+4, 1, tf) == 0) + 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 *) xmalloc(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 (fseek(tf, value, SEEK_SET) < 0) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 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(QFile::decodeName(name)).arg(nstrips).arg(count); + kfaxerror(i18n("Message"),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 (fseek(tf, value, SEEK_SET) < 0) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0) + goto realbad; + strips[count].size = (ftype == 3) ? + get2(buf, endian) : get4(buf, endian); + } + break; + case 283: /* YResolution */ + if (fseek(tf, value, SEEK_SET) < 0 || + fread(buf, 8, 1, tf) == 0) + 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 *= 2.54; + break; + } + } + IFDoff = get4(dp, endian); + free(dir); + dir = NULL; + if (comp == 5) { + // compression type 5 is LZW compression + kfaxerror(i18n("Sorry"),i18n("Due to patent reasons KFax can not handle LZW (Lempel-Ziv & Welch) " + "compressed Fax files.\n")); + goto bad; + } + if (comp < 2 || comp > 4) { + kfaxerror(i18n("Sorry"),i18n("This version can only handle Fax files\n")); + goto bad; + } + pn = notefile(name,FAX_TIFF); + pn->nstrips = nstrips; + pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight; + pn->strips = strips; + pn->width = iwidth; + pn->height = iheight; + pn->inverse = inverse; + pn->lsbfirst = lsbfirst; + pn->orient = orient; + pn->vres = (yres > 150); /* 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); + fclose(tf); + return 1; +} + +/* report error and remove bad file from the list */ +static void +badfile(struct pagenode *pn) +{ + struct pagenode *p; + + if (errno) + perror(pn->pathname); + if (pn == firstpage) { + if (pn->next == NULL){ + kfaxerror(i18n("Sorry"),i18n("Bad Fax File")); + return; + } + else{ + firstpage = thispage = firstpage->next; + firstpage->prev = NULL; + } + } + else + for (p = firstpage; p; p = p->next) + if (p->next == pn) { + thispage = p; + p->next = pn->next; + if (pn->next) + pn->next->prev = p; + break; + } + if (pn) free(pn); + pn = NULL; +} + +/* rearrange input bits into t16bits lsb-first chunks */ +static void +normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length) +{ + t32bits *p = (t32bits *) pn->data; + + 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 * +getstrip(struct pagenode *pn, int strip) +{ + int fd; + size_t offset, roundup; + struct stat sbuf; + unsigned char *Data; + union { t16bits s; unsigned char b[2]; } so; + QString str; + +#define ShortOrder so.b[1] + + so.s = 1; + if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) { + badfile(pn); + return NULL; + } + + if (pn->strips == NULL) { + if (fstat(fd, &sbuf) != 0) { + close(fd); + badfile(pn); + return NULL; + } + offset = 0; + pn->length = sbuf.st_size; + } + else if (strip < pn->nstrips) { + offset = pn->strips[strip].offset; + pn->length = pn->strips[strip].size; + } + else { + str = i18n("Trying to expand too many strips\n%1%n").arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Warning"),str); + return NULL; + } + + /* round size to full boundary plus t32bits */ + roundup = (pn->length + 7) & ~3; + + Data = (unsigned char *) xmalloc(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 (lseek(fd, offset, SEEK_SET) < 0 || + (uint) read(fd, Data, pn->length) != pn->length) { + badfile(pn); + free(Data); + close(fd); + return NULL; + } + close(fd); + + pn->data = (t16bits *) Data; + if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) { + /* handle ghostscript / PC Research fax file */ + if (Data[24] != 1 || Data[25] != 0){ + str = i18n("Only the first page of the PC Research multipage file\n%1\nwill be shown\n") + .arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Message"),str); + } + pn->length -= 64; + pn->vres = Data[29]; + pn->data += 32; + roundup -= 64; + } + + normalize(pn, !pn->lsbfirst, ShortOrder, roundup); + if (pn->height == 0) + pn->height = G3count(pn, pn->expander == g32expand); + if (pn->height == 0) { + + str = i18n("No fax found in file:\n%1\n").arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Sorry"),str); + errno = 0; + badfile(pn); + free(Data); + return NULL; + } + if (pn->strips == NULL) + pn->rowsperstrip = pn->height; + if (verbose && strip == 0) + kdWarning() << pn->name << "\n\twidth = " << pn->width << "\n\theight = " + << pn->height << "\n\tresolution = " << (pn->vres ? "fine" : "normal") << endl; +// statusbarupdate(pn->name,pn->width,pn->height,pn->vres ? "fine" : "normal"); + return Data; +} diff --git a/kfax/hi16-app-kfax.png b/kfax/hi16-app-kfax.png Binary files differnew file mode 100644 index 00000000..bb676f8b --- /dev/null +++ b/kfax/hi16-app-kfax.png diff --git a/kfax/hi22-app-kfax.png b/kfax/hi22-app-kfax.png Binary files differnew file mode 100644 index 00000000..90fc64b0 --- /dev/null +++ b/kfax/hi22-app-kfax.png diff --git a/kfax/hi32-app-kfax.png b/kfax/hi32-app-kfax.png Binary files differnew file mode 100644 index 00000000..7330eb41 --- /dev/null +++ b/kfax/hi32-app-kfax.png diff --git a/kfax/hi48-app-kfax.png b/kfax/hi48-app-kfax.png Binary files differnew file mode 100644 index 00000000..3f58c369 --- /dev/null +++ b/kfax/hi48-app-kfax.png diff --git a/kfax/hisc-app-kfax.svgz b/kfax/hisc-app-kfax.svgz Binary files differnew file mode 100644 index 00000000..f46fd440 --- /dev/null +++ b/kfax/hisc-app-kfax.svgz diff --git a/kfax/kfax.cpp b/kfax/kfax.cpp new file mode 100644 index 00000000..02661325 --- /dev/null +++ b/kfax/kfax.cpp @@ -0,0 +1,1695 @@ + /* + + $Id$ + + Copyright (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + This program 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. + + */ + +#ifdef KDE_USE_FINAL +/* NewImage() in viewfax.cpp needs to fiddle with the Display structure */ +#define XLIB_ILLEGAL_ACCESS +#endif + +#include <stdlib.h> +#include <signal.h> +#include <time.h> +#include <unistd.h> + +#include <qfile.h> +#include <qstrlist.h> +#include <qtimer.h> +#include <qpopupmenu.h> +#include <qpainter.h> +#include <qpaintdevicemetrics.h> +#include <qbitmap.h> + +#include <klocale.h> +#include <kaboutdata.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kfilemetainfo.h> +#include <kstdaccel.h> +#include <kconfig.h> +#include <kmenubar.h> +#include <kmessagebox.h> +#include <kcmdlineargs.h> +#include <kio/netaccess.h> +#include <knotifyclient.h> +#include <ktempfile.h> +#include <kstdaction.h> +#include <kdebug.h> +#include <kurldrag.h> +#include <kstatusbar.h> +#include <kaction.h> +#include <kprocess.h> +#include <kprinter.h> +#include <kio/job.h> +#include <kdebug.h> + +#include "faxexpand.h" +#include "kfax.h" +#include "version.h" +#include "viewfax.h" +#include "options.h" +#include "kfax_printsettings.h" + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/keysymdef.h> +#include <X11/cursorfont.h> + +// StatusBar field IDs +#define ID_LINE_COLUMN 1 +#define ID_INS_OVR 2 +#define ID_GENERAL 3 +#define ID_FNAME 4 +#define ID_TYPE 5 +#define ID_PAGE_NO 6 + + +TopLevel *toplevel; + +extern int GetImage(struct pagenode *pn); + +void TurnFollowing(int How, struct pagenode *pn); +void handle_X_event(XEvent event); +void ShowLoop(void); +void SetupDisplay(); +void mysighandler(int sig); +void setFaxDefaults(); + +void parse(char* buf, char** args); + +extern void g31expand(struct pagenode *pn, drawfunc df); +extern void g32expand(struct pagenode *pn, drawfunc df); +extern void g4expand(struct pagenode *pn, drawfunc df); + +#define PATIENCE 100000 + +static char KFAX_FILETYPES[] = "image/fax-g3 image/tiff"; + +int ExpectConfNotify = 1; + +GC PaintGC; +Cursor WorkCursor; +Cursor ReadyCursor; +Cursor MoveCursor; +Cursor LRCursor; +Cursor UDCursor; + +extern Time Lasttime; +extern bool have_cmd_opt; +extern struct pagenode *viewpage; + +extern XImage *FlipImage(XImage *xi); +extern XImage *MirrorImage(XImage *xi); +extern XImage *RotImage(XImage *Image); +extern XImage *ZoomImage(XImage *Big); +extern void FreeImage(XImage *Image); + +extern XImage *Image, *Images[MAXZOOM]; + +int xpos, ox; /* x, old x, offset x, new xpos*/ +int ypos, oy; /* y, old y, offset y, new y */ +int offx, offy; +int nx, ny; + +int oz, Resize, Refresh; /* old zoom, window size changed, + needs updating */ +int PaneWidth, PaneHeight; /* current size of our window */ +int AbsX, AbsY; /* absolute position of centre of window */ + +Display* qtdisplay; + +int startingup; +Window qtwin; // the qt window +Window Win; +int qwindow_height; +int qwindow_width; +bool have_no_fax = TRUE; +bool display_is_setup = FALSE; +struct optionsinfo fop; // contains the fax options + +extern struct pagenode *firstpage, *lastpage, *thispage; +extern struct pagenode* auxpage; + +extern struct pagenode defaultpage; + +bool buttondown; + +bool MyApp::x11EventFilter( XEvent * ev) +{ + if (KApplication::x11EventFilter(ev)) + return TRUE; + + if (ev->type == ButtonRelease){ + /* this is so that the cursor goes back to normal on leaving the fax window + and that the fax won't be moved when I reenter after I release the mouse*/ + + if (buttondown == true){ + buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + } + } + if ( ev->xany.window == qtwin || + ev->xany.window == Win){ + + if(startingup || have_no_fax) + return FALSE; + + toplevel->handle_X_event(*ev); + ev->xany.window = qtwin; + + } + + return FALSE; + +} + +TopLevel::TopLevel (QWidget *, const char *name) + : KMainWindow (0, name) +{ + setMinimumSize (100, 100); + + buttondown = false; + + setupMenuBar(); + setupStatusBar(); + updateActions(); + + resize(550,400); + setupGUI(); + + readSettings(); + + faxqtwin = new QFrame(this); + + qtwin = faxqtwin->winId(); + faxqtwin->setFrameStyle(QFrame::Panel | QFrame::Sunken); + + // Create a Vertical scroll bar + + vsb = new QScrollBar( QScrollBar::Vertical,faxqtwin,"scrollBar" ); + vsb->hide(); + connect( vsb, SIGNAL(valueChanged(int)), SLOT(scrollVert(int)) ); + + // Create a Horizontal scroll bar + + hsb = new QScrollBar( QScrollBar::Horizontal,faxqtwin,"scrollBar" ); + connect( hsb, SIGNAL(valueChanged(int)), SLOT(scrollHorz(int)) ); + hsb->hide(); + + setCentralWidget(faxqtwin); + + setAcceptDrops(true); + + show(); +} + + +TopLevel::~TopLevel() +{ +} + +void TopLevel::setupMenuBar() +{ + // File menu + KStdAction::open( this, SLOT( faxOpen() ), actionCollection() ); + actRecent = KStdAction::openRecent( this, SLOT( faxOpen( const KURL & ) ), + actionCollection() ); + actSave = KStdAction::save( this, SLOT( faxSave() ), actionCollection() ); + actSaveAs = KStdAction::saveAs( this, SLOT( faxSaveAs() ), + actionCollection() ); + actPrint = KStdAction::print( this, SLOT( print() ), actionCollection() ); + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + actAdd = new KAction( i18n( "A&dd..." ), "filenew", KShortcut(), this, + SLOT( faxAdd() ), actionCollection(), "file_add_fax" ); + + actRecent->setMaxItems( 5 ); + + // View Menu + actSize = KStdAction::actualSize( this, SLOT( actualSize() ), + actionCollection() ); + actZoomIn = KStdAction::zoomIn( this, SLOT( zoomin() ), actionCollection() ); + actZoomOut = KStdAction::zoomOut( this, SLOT( zoomout() ), + actionCollection() ); + + actRotate = new KAction( i18n( "&Rotate Page" ), "rotate", KShortcut(), this, + SLOT( rotatePage() ), actionCollection(), "view_rotate" ); + actMirror = new KAction( i18n( "Mirror Page" ), KShortcut(), this, + SLOT( mirrorPage() ), actionCollection(), "view_mirror" ); + actFlip = new KAction( i18n( "&Flip Page" ), KShortcut(), this, + SLOT( flipPage() ), actionCollection(), "view_flip" ); + + // Go menu + actNext = KStdAction::next( this, SLOT( nextPage() ), actionCollection() ); + actPrev = KStdAction::prior( this, SLOT( prevPage() ), actionCollection() ); + actFirst = KStdAction::firstPage( this, SLOT( firstPage() ), + actionCollection() ); + actLast = KStdAction::lastPage( this, SLOT( lastPage() ), + actionCollection() ); + + // Settings menu + KStdAction::preferences( this, SLOT( faxoptions() ), actionCollection() ); +} + +void TopLevel::setupStatusBar() +{ + statusbar = statusBar(); + + statusbar->insertFixedItem(i18n("w: 00000 h: 00000"), ID_INS_OVR); + statusbar->insertFixedItem(i18n("Res: XXXXX"), ID_GENERAL); + statusbar->insertFixedItem(i18n("Type: XXXXXXX"), ID_TYPE); + statusbar->insertFixedItem(i18n("Page: XX of XX"), ID_PAGE_NO); + statusbar->insertItem(QString::null, ID_FNAME, 1); + statusbar->setItemAlignment( ID_FNAME, AlignLeft ); + + statusbar->changeItem(QString::null, ID_INS_OVR); + statusbar->changeItem(QString::null, ID_GENERAL); + statusbar->changeItem(QString::null, ID_TYPE); + statusbar->changeItem(QString::null, ID_PAGE_NO); + statusbar->changeItem(QString::null, ID_FNAME); +} + +void TopLevel::readSettings() +{ + config = kapp->config(); + + applyMainWindowSettings( config, "MainWindowSettings" ); + + actRecent->loadEntries( config ); + + config->setGroup("General Options"); + + config->setGroup("Fax Options"); + + fop.width = config->readNumEntry("width", 1728); + fop.resauto = config->readNumEntry("resauto", 1); + fop.geomauto = config->readNumEntry("geomauto", 1); + fop.height = config->readNumEntry("height", 2339); + fop.fine = config->readNumEntry("resolution", 1); + fop.flip = config->readNumEntry("flip", 0); + fop.invert = config->readNumEntry("invert", 0); + fop.lsbfirst = config->readNumEntry("lsb", 0); + fop.raw = config->readNumEntry("raw", 3); + + setFaxDefaults(); +} + +void TopLevel::updateActions() +{ + actAdd->setEnabled( thispage ); + actSave->setEnabled( thispage ); + actSaveAs->setEnabled( thispage ); + actPrint->setEnabled( thispage ); + + actRotate->setEnabled( thispage ); + actFlip->setEnabled( thispage ); + actMirror->setEnabled( thispage ); + + updateGoActions(); + updateZoomActions(); +} + +void TopLevel::updateGoActions() +{ + actNext->setEnabled( thispage && thispage->next ); + actPrev->setEnabled( thispage && thispage->prev ); + actFirst->setEnabled( thispage && thispage->prev ); + actLast->setEnabled( thispage && thispage->next ); +} + +void TopLevel::updateZoomActions() +{ + actSize->setEnabled( Image && oz > 0 ); + actZoomIn->setEnabled( Image && oz > 0 ); + actZoomOut->setEnabled( Image && oz < MAXZOOM-1 && Image->width >= 256 ); +} + +bool TopLevel::queryClose() +{ + saveMainWindowSettings( config, "MainWindowSettings" ); + actRecent->saveEntries( config ); + + return true; +} + +void TopLevel::writeSettings() +{ + config = kapp->config(); + + config->setGroup("General Options"); + + config->setGroup("Fax Options"); + + config->writeEntry("resauto",fop.resauto); + config->writeEntry("geomauto",fop.geomauto); + config->writeEntry("width",fop.width); + config->writeEntry("height",fop.height); + config->writeEntry("resolution",fop.fine); + config->writeEntry("flip",fop.flip); + config->writeEntry("invert",fop.invert); + config->writeEntry("lsb",fop.lsbfirst); + config->writeEntry("raw",fop.raw); + + config->sync(); +} + +void TopLevel::faxOpen() +{ + KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES); + + faxOpen( url ); + + actRecent->addURL( fileURL ); +} + +void TopLevel::faxOpen( const KURL & url ) +{ + if (!url.isValid()) + return; + + faxClose(); + faxAdd( url ); + + fileURL = url; + + updateActions(); +} + +void TopLevel::faxAdd() +{ + KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES); + + faxAdd( url ); + + actRecent->addURL( fileURL ); +} + +void TopLevel::faxAdd( const KURL & url ) +{ + if (!url.isValid()) + return; + + openNetFile(url); + + updateGoActions(); +} + +void TopLevel::faxSave() +{ + saveNetFile(fileURL); +} + +void TopLevel::faxSaveAs() +{ + fileURL = KFileDialog::getSaveURL(QString::null, KFAX_FILETYPES); + + if (fileURL.isEmpty()) + return; + + faxSave(); + + actRecent->addURL( fileURL ); +} + + +static void freeImages() +{ + int i; + for (i = 1; i < MAXZOOM; i++) { + if (Images[i]) + FreeImage(Images[i]); + Images[i] = NULL; + } +} + +static XImage *generateZoomImages(int maxzoom) +{ + int i; + for (i = 1; i < MAXZOOM; i++){ + if (!Images[i-1]) + continue; + Image = Images[i] = ZoomImage(Images[i-1]); + if(Image == NULL){// out of memory + Image = Images[i -1]; + break; + } + } + + i = maxzoom; + while (!Images[i]) + i--; + return Images[i]; +} + + +void TopLevel::zoom( int factor ) +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + Resize = Refresh = 1; + + Image = generateZoomImages(factor); + + PaneWidth = Image->width; + PaneHeight = Image->height; + + resizeView(); + putImage(); + + uiUpdate(); + + updateZoomActions(); +} + +void TopLevel::zoomin() +{ + if ( oz > 0 ) + { + oz--; + zoom( oz ); + } +} + +void TopLevel::zoomout() +{ + if (oz < MAXZOOM && Image->width >= 256) + { + ++oz; + zoom( oz ); + } +} + +void TopLevel::actualSize() +{ + oz = 0; + zoom( oz ); +} + +void loadfile(QString filename) +{ + // Typical FAX resolutions are: + // Standard: 203 dpi x 98 dpi + // Fine: 203 dpi x 196 lpi + // Super Fine: 203 dpi y 392 lpi, or + // 406 dpi x 392 lpi + QSize dpi(203,196); + + KFileMetaInfo metaInfo(filename); + if (metaInfo.isValid() && metaInfo.item("Resolution").isValid()) + { + QSize s = metaInfo.item("Resolution").value().toSize(); + if (s.width() >= 100 && s.height() >= 100) + dpi = s; + } + + (void) notetiff(QFile::encodeName(filename)); + + struct pagenode *pn; + for(pn = firstpage; pn; pn = pn->next) + if (!pn->dpiX) { + pn->dpiX = dpi.width(); + pn->dpiY = dpi.height(); + } +} + +void TopLevel::openadd(QString filename) +{ + auxpage = lastpage; + + loadfile(filename); + + if( firstpage != lastpage ) + { + if(auxpage->next) + auxpage = auxpage->next; + } + + // auxpage should now point to the first pagenode which was created for + // the newly added fax file. + have_no_fax = false; + thispage = auxpage; + newPage(); + resizeView(); + putImage(); +} + +void TopLevel::resizeEvent(QResizeEvent *e) +{ + KMainWindow::resizeEvent(e); + + resizeView(); +} + +void TopLevel::wheelEvent( QWheelEvent *e ) +{ + e->accept(); + + if ( e->state() & ShiftButton ) + { + if ( e->delta() < 0 ) + zoomin(); + else + zoomout(); + } + else + { + int offset = QApplication::wheelScrollLines()*vsb->lineStep(); + if ( e->state() & ControlButton ) + offset = vsb->pageStep(); + offset = -e->delta()*offset/120; + vsb->setValue( vsb->value() + offset ); + } +} + +void TopLevel::resizeView() +{ + if(!faxqtwin || !display_is_setup) + return; + +//printf("In resizeView() entered\n"); + + qwindow_width = faxqtwin->width(); + qwindow_height = faxqtwin->height(); + + if( hsb->isVisible()) + qwindow_height -= 16; + + if( vsb->isVisible()) + qwindow_width -= 16; + + if(Image){ + PaneWidth = Image->width; + PaneHeight = Image->height; + } + + // printf("faxw %d qtw %d\n", PaneWidth , faxqtwin->width()); + + if( (PaneHeight > qwindow_height ) && + (PaneWidth > qwindow_width)){ + + vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()-16); + hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width()-16,16); + + qwindow_width = faxqtwin->width() -16; + qwindow_height = faxqtwin->height()-16; + + + vsb->raise(); + vsb->show(); + hsb->show(); + } + else{ + + if( PaneHeight > qwindow_height){ + vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()); + + + qwindow_width = faxqtwin->width() -16 ; + qwindow_height = faxqtwin->height(); + + + vsb->show(); + hsb->hide(); + hsb->raise(); + } + else + vsb->hide(); + + if( PaneWidth > qwindow_width ){ + hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width(),16); + hsb->show(); + hsb->raise(); + vsb->hide(); + qwindow_width = faxqtwin->width() ; + qwindow_height = faxqtwin->height() -16; + + } + else + hsb->hide(); + + } + + if(Image){ + hsb->setRange(0,QMAX(0,Image->width - qwindow_width)); + hsb->setSteps(5,qwindow_width/2); + // printf("hsb range: %d\n",QMAX(0,Image->width - qwindow_width)); + vsb->setRange(0,QMAX(0,Image->height - qwindow_height)); + vsb->setSteps(5,qwindow_height/2); + // printf("vsb range: %d\n",QMAX(0,Image->height - qwindow_height)); + // printf("vsb QMIN %d vdb QMAX %d\n",vsb->QMINValue(),vsb->QMAXValue()); + } + + + Resize = 1; + uiUpdate(); + +} + +bool TopLevel::loadAllPages( int &numpages, int ¤tpage ) +{ + struct pagenode *pn; + + numpages = 0; + currentpage = 1; + + for(pn = firstpage; pn; pn = pn->next) { + ++numpages; + if (pn == thispage) + currentpage = numpages; + if (!Pimage(pn)) { + int k = -1; + while((k != 0) && (k != 3) && (k != 1)) + k = GetImage(pn); // fetch image if it is not available yet. + } + } + return (numpages != 0); +} + +void TopLevel::print(){ + if(!thispage || !firstpage) { + return KMessageBox::sorry(this, i18n("There is no document active.")); + } + + int pages, currentpage; + loadAllPages(pages, currentpage); + + KPrinter printer(true, QPrinter::HighResolution); + printer.setFullPage( true ); + printer.setUsePrinterResolution( true ); + printer.setCreator( i18n("KFax") + " " KFAXVERSION ); + printer.setDocName( QString("%1 - %2").arg(firstpage->name).arg(i18n("KFax"))); + printer.setDocFileName( firstpage->name ); + printer.setPageSelection( KPrinter::ApplicationSide ); + printer.setMinMax( 1, pages ); + printer.setCurrentPage( currentpage ); + printer.addDialogPage(new KFAXPrintSettings()); + if ( !printer.setup( this ) ) + return; + + QPainter painter; + painter.begin( &printer ); + printIt(printer, painter); + painter.end(); +} + + +void TopLevel::printIt( KPrinter &printer, QPainter &painter ) +{ + QPaintDeviceMetrics dm(painter.device()); + + QApplication::setOverrideCursor( waitCursor ); + kapp->processEvents(); + + const bool fullpage = printer.option(APP_KFAX_SCALE_FULLPAGE) == "true"; + const bool center_h = printer.option(APP_KFAX_CENTER_HORZ) == "true"; + const bool center_v = printer.option(APP_KFAX_CENTER_VERT) == "true"; + + int currentpage = 0; + bool first_page_printed = false; + struct pagenode *pn; + for(pn = firstpage; pn; pn = pn->next) { + + ++currentpage; + // should this page be printed ? + if (printer.pageList().findIndex(currentpage) < 0) + continue; + + XImage *Image = Pimage(pn); + if (!Image) + continue; + + // byte-swapping the image + QByteArray bytes( Image->height*Image->bytes_per_line ); + for (int y=Image->height-1; y>=0; --y) { + Q_UINT32 offset = y*Image->bytes_per_line; + Q_UINT32 *source = (Q_UINT32 *) (Image->data + offset); + Q_UINT32 *dest = (Q_UINT32 *) (bytes.data() + offset); + for (int x=(Image->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; + } + } + + QImage image( (uchar *)bytes.data(), Image->bytes_per_line*8, Image->height, 1, NULL, 2, QImage::LittleEndian); + + if (first_page_printed) + printer.newPage(); + first_page_printed = true; + + const QSize printersize( dm.width(), dm.height() ); + kdDebug() << "Printersize = " << printersize << endl; + // print Image in original size if possible, else scale it. + + const QSize size( // logical size of the image + Image->width * dm.logicalDpiX() / pn->dpiX, + Image->height * dm.logicalDpiY() / pn->dpiY + ); + + kdDebug() << "Org image size = " << Image->width << "x" << Image->height + << " logical picture res = " << pn->dpiX << "x" << pn->dpiY << endl; + kdDebug() << "New image size = " << size + << " logical printer res = " << dm.logicalDpiX() << "x" << dm.logicalDpiY() << endl; + + uint top, left, bottom, right; + if (fullpage) + top = left = bottom = right = 0; + else + printer.margins( &top, &left, &bottom, &right ); + kdDebug() << "Margins = " << top << " " << left << " " << bottom << " " << right << endl; + + const QSize maxSize( printersize.width()-left-right, printersize.height()-top-bottom ); + QSize scaledImageSize = size; + if (size.width() > maxSize.width() || size.height() > maxSize.height() ) { + // Image does not fit - scale it and print centered + scaledImageSize.scale( maxSize, QSize::ScaleMin ); + kdDebug() << "Image does not fit - scaling to " << maxSize << endl; + } else { + // Image does fit - print it in original size, but centered + scaledImageSize.scale( size, QSize::ScaleMin ); + kdDebug() << "Image does fit - scaling to " << size << endl; + } + kdDebug() << "Final image size " << scaledImageSize << endl; + int x,y; + if (center_h) + x = (maxSize.width()-scaledImageSize.width())/2 + left; + else + x = left; + if (center_v) + y = (maxSize.height()-scaledImageSize.height())/2 + top; + else + y = top; + painter.drawImage( QRect(x,y,scaledImageSize.width(), scaledImageSize.height()), image ); + + } + + QApplication::restoreOverrideCursor(); +} + +void TopLevel::saveNetFile( const KURL& dest) +{ + if ( !dest.isValid() ) + { + KMessageBox::sorry(this, i18n("Malformed URL")); + return; + } + + statusbar->message( i18n( "Saving..." ) ); + + KURL source = KURL::fromPathOrURL(thispage->pathname); + bool ok = KIO::NetAccess::file_copy( source, dest, -1, true, false, this); + + statusbar->clear(); + + if (!ok) + KMessageBox::error(this, i18n("Failure in 'copy file()'\n" + "Could not save file!")); +} + +void TopLevel::openNetFile( const KURL &u) +{ + if ( !u.isValid() ) + { + KMessageBox::error(this, i18n("Malformed URL")); + return; + } + + if ( u.isLocalFile() ) + { + QString string = i18n("Loading '%1'").arg(u.path()); + statusbar->message(string); + openadd( u.path()); + statusbar->clear(); + } + else + { + statusbar->message(i18n("Downloading...")); + QString tmpFile = QString::null; + if ( KIO::NetAccess::download( u, tmpFile, this ) ) + { + openadd( tmpFile ); + setCaption( u.prettyURL() ); + } + statusbar->clear(); + KIO::NetAccess::removeTempFile( tmpFile ); + } +} + +void TopLevel::dragEnterEvent( QDragEnterEvent * event) +{ + event->accept(KURLDrag::canDecode(event)); +} + +void TopLevel::dropEvent( QDropEvent * event) +{ + + KURL::List list; + + if (KURLDrag::decode(event, list) && !list.isEmpty()) + { + // Load the first file in this window + const KURL &url = list.first(); + openNetFile( url ); + } +} + +void SetupDisplay(){ + + if(display_is_setup){ + return; + } + + display_is_setup = TRUE; + + xpos = ypos = ox = oy = 0; + ExpectConfNotify = 1; + + /* XSizeHints size_hints;*/ + + Win = XCreateSimpleWindow(qtdisplay,qtwin,1,1, + 1,1, + 0, + BlackPixel(qtdisplay,XDefaultScreen(qtdisplay)), + WhitePixel(qtdisplay,XDefaultScreen(qtdisplay))); + + PaintGC = XCreateGC(qtdisplay, Win, 0L, (XGCValues *) NULL); + XSetForeground(qtdisplay, PaintGC, BlackPixel(qtdisplay, XDefaultScreen(qtdisplay) )); + XSetBackground(qtdisplay, PaintGC, WhitePixel(qtdisplay, XDefaultScreen(qtdisplay) )); + XSetFunction(qtdisplay, PaintGC, GXcopy); + WorkCursor = XCreateFontCursor(qtdisplay, XC_watch); + //ReadyCursor = XCreateFontCursor(qtdisplay, XC_plus); + ReadyCursor = XCreateFontCursor(qtdisplay, XC_hand2); + MoveCursor = XCreateFontCursor(qtdisplay, XC_fleur); + LRCursor = XCreateFontCursor(qtdisplay, XC_sb_h_double_arrow); + UDCursor = XCreateFontCursor(qtdisplay, XC_sb_v_double_arrow); + + XSelectInput(qtdisplay, Win, Button2MotionMask | ButtonPressMask | + ButtonReleaseMask | ExposureMask | KeyPressMask | + SubstructureNotifyMask | LeaveWindowMask | OwnerGrabButtonMask | + StructureNotifyMask); + + XMapRaised(qtdisplay, Win); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + + memset(Images, 0, sizeof(Images)); + + // Start at half the Size + oz = 1; +} + +void TopLevel::handle_X_event(XEvent Event) +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + bool putimage = false; // Do we actually have to write the image to the scree? + + do { + switch(Event.type) { + case MappingNotify: + XRefreshKeyboardMapping((XMappingEvent *)(&Event)); + break; + + case LeaveNotify: + /* buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay);*/ + break; + case Expose: + { + + if(Event.xexpose.count != 0) + break; + + if(!Image) + break; + + putimage = TRUE; + } + break; + + case KeyPress: + if (ExpectConfNotify && + (Event.xkey.time < (Lasttime + PATIENCE))) + break; + Lasttime = Event.xkey.time; + ExpectConfNotify = 0; + switch(XKeycodeToKeysym(qtdisplay, Event.xkey.keycode, 0)) { + case XK_m: + mirrorPage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_M, thispage->next); + break; + case XK_o: + zoomout(); + break; + + case XK_i: + zoomin(); + break; + + case XK_Up: + ypos-= qwindow_height / 3; + putimage = TRUE; + break; + case XK_Down: + ypos+= qwindow_height / 3; + putimage = TRUE; + break; + case XK_Left: + xpos-= qwindow_width / 4; + putimage = TRUE; + break; + case XK_Right: + xpos+= qwindow_width / 4; + putimage = TRUE; + break; + case XK_Home: + case XK_R7: + if (Event.xkey.state & ShiftMask) { + thispage = firstpage; + newPage(); + resizeView(); + putImage(); + break; + } + xpos= 0; + ypos= 0; + putImage(); + break; + case XK_End: + case XK_R13: + if (Event.xkey.state & ShiftMask) { + thispage = lastpage; + newPage(); + resizeView(); + putImage(); + break; + } + xpos= Image->width; + ypos= Image->height; + putImage(); + break; + case XK_l: + case XK_r: + rotatePage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_L, thispage->next); + break; + case XK_p: + case XK_minus: + case XK_Prior: + case XK_R9: + case XK_BackSpace: + prevPage(); + break; + case XK_n: + case XK_plus: + case XK_space: + case XK_Next: + case XK_R15: + nextPage(); + break; + case XK_u: + flipPage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_U, thispage->next); + break; + + case XK_q: + if (viewpage) { + thispage = viewpage; + viewpage = NULL; + newPage(); + resizeView(); + putImage(); + } + + } + + break; + + case ButtonPress: + + if (ExpectConfNotify && (Event.xbutton.time < (Lasttime + PATIENCE))) + break; + + Lasttime = Event.xbutton.time; + ExpectConfNotify = 0; + + + switch (Event.xbutton.button) { + + case Button1: + buttondown = true; + + switch (((Image->width > qwindow_width)<<1) | + (Image->height > qwindow_height)) { + case 0: + break; + case 1: + XDefineCursor(qtdisplay, Win, UDCursor); + break; + case 2: + XDefineCursor(qtdisplay, Win, LRCursor); + break; + case 3: + XDefineCursor(qtdisplay, Win, MoveCursor); + } + + XFlush(qtdisplay); + offx = Event.xbutton.x; + offy = Event.xbutton.y; + break; + + } + + break; + + case MotionNotify: + if(!buttondown) + break; + do { + + nx = Event.xmotion.x; + ny = Event.xmotion.y; + + + } while (XCheckTypedEvent(qtdisplay, MotionNotify, &Event)); + + + xpos+= offx - nx; + ypos+= offy - ny; + + offx = nx; + offy = ny; + + putimage = TRUE; + + break; + + case ButtonRelease: + + if (Event.xbutton.button == Button1) { + + buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + } + + } + + } while (XCheckWindowEvent(qtdisplay, Win, KeyPressMask|ButtonPressMask, &Event)); + + if(putimage == TRUE) { + Refresh = Resize = 1; + putImage(); + } +} + +void TopLevel::rotatePage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newrotimage = RotImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newrotimage == NULL){ // out of memory + return; + } + + thispage->extra = Images[0] = newrotimage; + thispage->orient ^= TURN_L; + + freeImages(); + Image = generateZoomImages(oz); + + { int t = xpos ; xpos= ypos; ypos= t; } + + Refresh = Resize = 1; + + putImage(); +} + +void TopLevel::flipPage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newflipimage = FlipImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newflipimage == NULL){ // out of memory + return; + } + + thispage->extra = Images[0] = newflipimage; + thispage->orient ^= TURN_U; + + freeImages(); + Image = generateZoomImages(oz); + + Refresh = Resize = 1; + putImage(); +} + +void TopLevel::mirrorPage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newmirror = MirrorImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newmirror == NULL){ // out of memory + return; + } + thispage->extra = Images[0] = newmirror; + thispage->orient ^= TURN_M; + + freeImages(); + Image = generateZoomImages(oz); + + Refresh = Resize = 1; + putImage(); +} + +void TopLevel::scrollHorz(int){ + + if(!Image) + return; + + // printf("hsb value: %d\n",hsb->value()); + xpos= hsb->value() + qwindow_width/2; + + Refresh = 1; + putImage(); +} + +void TopLevel::scrollVert(int ){ + + if(!Image) + return; + + // printf("vsb value: %d\n",vsb->value()); + ypos= vsb->value() + qwindow_height/2; + + Refresh = 1; + putImage(); +} + +void TopLevel::lastPage() +{ + if(!thispage) + return; + + if ( thispage->next ) + { + while(thispage->next != NULL) + thispage = thispage->next; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::firstPage() +{ + if(!thispage) + return; + + if ( thispage->prev ) + { + while(thispage->prev != NULL) + thispage = thispage->prev; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::nextPage() +{ + if(!thispage) + return; + + if (thispage->next) + { + thispage = thispage->next; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::prevPage() +{ + if(!thispage) + return; + + if (thispage->prev) + { + thispage = thispage->prev; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::newPage(){ + + if(!display_is_setup) + SetupDisplay(); + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + freeImages(); + + int k = -1; + + if(!thispage) { + XDefineCursor(qtdisplay, Win, ReadyCursor); + return; + } + + if (Pimage(thispage) == NULL){ + + while((k != 0) && (k != 3) && (k !=1)) + k = GetImage(thispage); + + } + + if (k == 3 ){ + + XDefineCursor(qtdisplay, Win, ReadyCursor); + FreeFax(); + /* KMessageBox::sorry(i18n("Bad fax file k=3"));*/ + return; + } + + if (k == 0 ){ + + XDefineCursor(qtdisplay, Win, ReadyCursor); + FreeFax(); + /* KMessageBox::sorry(i18n("Bad fax file k=0"));*/ + return; + } + + Image = Images[0] = Pimage(thispage); + + setCaption(QFile::decodeName(thispage->name)); + + Image = generateZoomImages(oz); + + PaneWidth = Image->width; + PaneHeight = Image->height; + Refresh = 1; + + XDefineCursor(qtdisplay, Win, ReadyCursor); + uiUpdate(); + +} + + +void TopLevel::faxClose() +{ + FreeFax(); + + setCaption(i18n("KFax")); + // TODO replace this with unmapping the window. + if(display_is_setup) + XResizeWindow(qtdisplay,Win,1,1); // we want a clear gray background. + + resizeView(); + vsb->hide(); + hsb->hide(); + + fileURL = QString::null; + + updateActions(); +} + +void TopLevel::FreeFax() +{ + if(display_is_setup) + XClearWindow(qtdisplay, Win); + + freeImages(); + + pagenode *pn; + for (pn = firstpage; pn; pn = pn->next){ + if(Pimage(pn)){ + FreeImage(Pimage(pn)); + pn->extra = NULL; + } + } + + Image = NULL; + + for (pn = firstpage; pn; pn = pn->next){ + if(pn->pathname){ + free(pn->pathname); + } + } + + + if(firstpage){ + for(pn = firstpage->next; pn; pn = pn->next){ + if(pn->prev){ + free(pn->prev); + } + } + } + + if(lastpage) + free(lastpage); + + firstpage = lastpage = viewpage = thispage = auxpage = NULL; + + uiUpdate(); +} + +void TopLevel::uiUpdate(){ + + if(thispage){ + + struct pagenode *pn ; + int pages = 0; + int currentpage = 0; + + for(pn = firstpage; pn ; pn = pn->next){ + pages ++; + if (thispage == pn) + currentpage = pages; + } + + QString pagestr = i18n("Page: %1 of %2").arg(currentpage).arg(pages); + + statusbar->changeItem(pagestr, ID_PAGE_NO); + + if(Image){ + QString wh = i18n("W: %1 H: %2").arg(Image->width).arg(Image->height); + statusbar->changeItem(wh, ID_INS_OVR); + } + + QString resolution = i18n("Res: %1").arg(thispage->vres?i18n("Fine"):i18n("Normal")); + // TODO: resolution += QString("%1x%2").arg(thispage->dpiX).arg(thispage->dpiY); + statusbar->changeItem(resolution, ID_GENERAL); + + statusbar->changeItem(thispage->name, ID_FNAME); + + QString typestring; + + if(thispage->type == FAX_TIFF){ + typestring = i18n("Type: Tiff "); + } + else if ( thispage->type == FAX_RAW){ + typestring = i18n("Type: Raw "); + } + + if ( thispage->expander == g31expand ) + typestring += "G3"; + + if ( thispage->expander == g32expand ) + typestring += "G3 2D"; + + if ( thispage->expander == g4expand ) + typestring += "G4"; + + statusbar->changeItem(typestring,ID_TYPE); + updateActions(); + } +} + +void kfaxerror(const QString& title, const QString& error){ + KMessageBox::error(toplevel, error, title); +} + +void TopLevel::putImage() +{ + + // TODO do I really need to set Refresh or Resize to 1 , is there + // really still someonce calling this with out haveing set Refresh or Resize to 1? + + if ( !Image || !display_is_setup || !thispage ) + return; + + if ( qwindow_width > Image->width){ + xpos= Image->width/2; + } + else{ + if(xpos< qwindow_width/2){ + xpos = qwindow_width/2; + } + else{ + if(xpos> Image->width - qwindow_width/2){ + xpos= Image->width - qwindow_width/2; + } + + } + } + + if ( qwindow_height > Image->height){ + ypos= Image->height/2; + } + else{ + if(ypos< qwindow_height/2){ + ypos = qwindow_height/2; + } + else{ + if(ypos> Image->height - qwindow_height/2){ + ypos= Image->height - qwindow_height/2; + } + + } + } + + if (xpos!= ox || ypos!= oy || Refresh || Resize){ + + /* In the following we use qwindow_height -1 etc since the main view + has a sunken frame and I need to offset by 1 pixel to the right and + one pixel down so that I don't paint my fax into the border of the frame*/ + + XResizeWindow(qtdisplay,Win,QMIN(qwindow_width -1,Image->width ), + QMIN(qwindow_height -1,Image->height )); + + XPutImage(qtdisplay, Win, PaintGC, Image, + QMAX(xpos - qwindow_width/2,0), QMAX(ypos - qwindow_height/2,0), + 0, 0, QMIN(qwindow_width -1,Image->width) , + QMIN(qwindow_height -1,Image->height) ); + + vsb->setValue(QMAX(ypos - qwindow_height/2,0)); + hsb->setValue(QMAX(xpos - qwindow_width/2,0)); + + XFlush(qtdisplay); + } + + ox = xpos; + oy = ypos; + + Resize = Refresh = 0; + +} + +void TopLevel::faxoptions(){ + + OptionsDialog * opd = new OptionsDialog(this, "options"); + opd->setWidgets(&fop); + + if(opd->exec()){ + + struct optionsinfo *newops; + newops = opd->getInfo(); + + fop.resauto = newops->resauto; + fop.geomauto = newops->geomauto; + fop.width = newops->width; + fop.height = newops->height; + fop.fine = newops->fine; + fop.landscape= newops->landscape; + fop.flip = newops->flip; + fop.invert = newops->invert; + fop.lsbfirst = newops->lsbfirst; + fop.raw = newops->raw; + + setFaxDefaults(); + + writeSettings(); + } + + delete opd; +} + +void setFaxDefaults(){ + + // fop is called in readSettings, so this can't be + // called after a TopLevel::readSettings() + + if(have_cmd_opt ) // we have commad line options all kfaxrc defaults are + return; // overridden + + if(fop.resauto == 1) + defaultpage.vres = -1; + else + defaultpage.vres = fop.fine; + + if(fop.geomauto == 1){ + defaultpage.width = defaultpage.height = 0; + } + else{ + defaultpage.width = fop.width; + defaultpage.height = fop.height; + } + + if(fop.landscape) + defaultpage.orient |= TURN_L; + + if(fop.flip) + defaultpage.orient |= TURN_U; + + defaultpage.inverse = fop.invert; + defaultpage.lsbfirst = fop.lsbfirst; + + switch (fop.raw) { + case 2: defaultpage.expander = g32expand; + break; + case 4: defaultpage.expander = g4expand; + break; + default:defaultpage.expander = g31expand; + } + +} + +static const char description[] = + I18N_NOOP("KDE G3/G4 Fax Viewer"); + +static KCmdLineOptions options[] = +{ + {"f", 0, 0 }, + {"fine", I18N_NOOP( "Fine resolution" ), 0 }, + {"n", 0, 0 }, + {"normal", I18N_NOOP( "Normal resolution" ), 0 }, + {"height", I18N_NOOP( "Height (number of fax lines)" ), 0 }, + {"w", 0, 0 }, + {"width", I18N_NOOP( "Width (dots per fax line)" ), 0 }, + {"l", 0, 0 }, + {"landscape", I18N_NOOP( "Turn image 90 degrees (landscape mode)" ), 0 }, + {"u", 0, 0 }, + {"upsidedown", I18N_NOOP( "Turn image upside down" ), 0 }, + {"i", 0, 0 }, + {"invert", I18N_NOOP( "Invert black and white" ), 0 }, + {"m", 0, 0 }, + {"mem <bytes>", I18N_NOOP( "Limit memory use to 'bytes'" ), "8M" }, + {"r", 0, 0 }, + {"reverse", I18N_NOOP( "Fax data is packed lsb first" ), 0 }, + {"2" , I18N_NOOP( "Raw files are g3-2d" ), 0 }, + {"4", I18N_NOOP( "Raw files are g4" ), 0 }, + {"+file(s)", I18N_NOOP( "Fax file(s) to show" ), 0 }, + KCmdLineLastOption +}; + +int main (int argc, char **argv) +{ + KAboutData aboutData( "kfax", I18N_NOOP("KFax"), + KFAXVERSION, description, KAboutData::License_GPL, + "(c) 1997-98 Bernd Johannes Wuebben"); + aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@kde.org" ); + aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "UI Rewrite, lots of code " + "cleanups and fixes" ), "nhasan@kde.org" ); + aboutData.addCredit( "Helge Deller", I18N_NOOP( "Printing Rewrite, lots of code " + "cleanups and fixes"), "deller@kde.org" ); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions( options ); + + MyApp a; + + qtdisplay = qt_xdisplay(); + + viewfaxmain(); + + toplevel = new TopLevel(); + toplevel->show(); + + startingup = 1; + a.processEvents(); + a.flushX(); + + startingup = 0; + + faxinit(); + if(!have_no_fax){ + + thispage = firstpage; + + toplevel->newPage(); + toplevel->resizeView(); + //TODO : I don't think I need this putImage(); + toplevel->putImage(); + } + + toplevel->uiUpdate(); + + return a.exec (); +} + + +#include "kfax.moc" diff --git a/kfax/kfax.desktop b/kfax/kfax.desktop new file mode 100644 index 00000000..eefd8b87 --- /dev/null +++ b/kfax/kfax.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +MimeType=image/fax-g3;image/tiff; +GenericName=Fax Viewer +GenericName[af]=Faks Aansig +GenericName[ar]=عارض الفاكس +GenericName[bg]=Преглед на факсове +GenericName[br]=Gweler faks +GenericName[bs]=Preglednik faxova +GenericName[ca]=Visualitzador de fax +GenericName[cs]=Prohlížeč faxů +GenericName[cy]=Gwelydd Ffacs +GenericName[da]=Fax-fremviser +GenericName[de]=Faxbetrachter +GenericName[el]=Προβολέας φαξ +GenericName[eo]=Faksrigardilo +GenericName[es]=Visor de faxes +GenericName[et]=Fakside vaataja +GenericName[eu]=Fax ikustailua +GenericName[fa]=مشاهدهگر دورنگار +GenericName[fi]=Faksinäytin +GenericName[fr]=Afficheur de fax +GenericName[gl]=Visor de fax +GenericName[he]=מציג פקסים +GenericName[hi]=फ़ैक्स प्रदर्शक +GenericName[hr]=Preglednik faksova +GenericName[hu]=Faxnézegető +GenericName[is]=Fax sjá +GenericName[it]=Visore di fax +GenericName[ja]=ファクスビューア +GenericName[kk]=Факсты қарау +GenericName[km]=កម្មវិធីមើលទូរសារ +GenericName[lt]=Faksų žiūriklis +GenericName[lv]=Faksu Skatītājs +GenericName[ms]=Pemapar Faks +GenericName[nb]=Faksfremviser +GenericName[nds]=Faxkieker +GenericName[ne]=फ्याक्स द्रष्टा +GenericName[nl]=Faxweergaveprogramma +GenericName[nn]=Faksvisar +GenericName[pa]=ਫੈਕਸ ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka faksów +GenericName[pt]=Visualizador de Faxes +GenericName[pt_BR]=Visualizador de Faxes +GenericName[ro]=Vizualizor FAX +GenericName[ru]=Просмотр факсов +GenericName[se]=Fáksačájeheaddji +GenericName[sk]=Prehliadač faxov +GenericName[sl]=Pregledovalnik faksov +GenericName[sr]=Приказивач факсова +GenericName[sr@Latn]=Prikazivač faksova +GenericName[sv]=Faxvisare +GenericName[ta]=ஃபாக்ஸ் காட்சி +GenericName[tg]=Хондани факс +GenericName[th]=เครื่องมือแสดงโทรสารของ KDE +GenericName[tr]=Faks Görüntüleyici +GenericName[uk]=Переглядач факсів +GenericName[uz]=Faks koʻruvchi +GenericName[uz@cyrillic]=Факс кўрувчи +GenericName[ven]=Muvhoni wa Fekisi +GenericName[wa]=Håyneu di facs +GenericName[xh]=Umboniseli Wefax +GenericName[zh_CN]=传真查看器 +GenericName[zh_HK]=傳真檢視器 +GenericName[zh_TW]=傳真檢視器 +GenericName[zu]=Umbonisi wefax +Name=KFax +Name[af]=K-faks +Name[ar]=برنامج KFax +Name[cy]=KFfacs +Name[eo]=Faksrigardilo +Name[hi]=के-फ़ैक्स +Name[lv]=KFakss +Name[ne]=केडीई फ्याक्स +Name[sv]=Kfax +Name[ta]=கேஃபாக்ஸ் +Name[ven]=Fekisi ya K +Name[wa]=KFacs +Name[zh_TW]=KFax 傳真檢視器 +Exec=kfax %f -caption "%c" %i %m +Icon=kfax +Path= +Type=Application +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kfax/kfax.h b/kfax/kfax.h new file mode 100644 index 00000000..506a1452 --- /dev/null +++ b/kfax/kfax.h @@ -0,0 +1,159 @@ + /* + + $Id$ + + Requires the Qt widget libraries, available at no cost at + http://www.troll.no + + Copyright (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + + This program 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 _KFAX_H_ +#define _KFAX_H_ + +#include <kapplication.h> +#include <kmainwindow.h> +#include <qptrlist.h> +#include <kurl.h> + +#define Pimage(p) ((XImage *)(p)->extra) + +class QPopupMenu; +class KConfig; +class KStatusBar; +class KAction; +class KRecentFilesAction; +class KPrinter; +class QPainter; +class QScrollBar; + +typedef KToolBar::BarPosition BarPosition; + +class MyApp:public KApplication { +public: + virtual bool x11EventFilter( XEvent * ); +}; + +class TopLevel : public KMainWindow +{ + Q_OBJECT + + +public: + + TopLevel( QWidget *parent=0, const char *name=0 ); + ~TopLevel(); + + void openNetFile( const KURL& _url); + void saveNetFile( const KURL& _url ); + + static QPtrList<TopLevel> windowList; + QPopupMenu *right_mouse_button, *colors; + + void handle_X_event(XEvent Event); + void putImage(); + +protected: + + void resizeEvent( QResizeEvent * ); + void wheelEvent( QWheelEvent * ); + void dragEnterEvent( QDragEnterEvent * event ); + void dropEvent( QDropEvent * event ); + + void updateActions(); + void updateGoActions(); + void updateZoomActions(); + + void zoom( int ); + + void readSettings(); + void writeSettings(); + void setupActions(); + void setupMenuBar(); + void setupToolBar(); + void setupEditWidget(); + void setupStatusBar(); + + bool queryClose(); + +private: + + QFrame *faxqtwin; + + int indentID; + QColor forecolor; + QColor backcolor; + + KURL fileURL; + KStatusBar *statusbar; + + KRecentFilesAction *actRecent; + KAction *actAdd, *actSave, *actSaveAs, *actPrint; + KAction *actSize, *actZoomIn, *actZoomOut, *actRotate, *actMirror; + KAction *actFlip, *actNext, *actPrev, *actFirst, *actLast; + + int open_mode; + + KConfig *config; + + QScrollBar *hsb; + QScrollBar *vsb; + QFrame* mainpane; + + void printIt( KPrinter &printer, QPainter &painter ); + bool loadAllPages( int &numpages, int ¤tpage ); + +public slots: + + void faxOpen( const KURL & ); + void faxOpen(); + void faxAdd(); + void faxAdd( const KURL & ); + void faxClose(); + void print(); + void zoomin(); + void zoomout(); + void actualSize(); + void resizeView(); + void faxSave(); + void faxSaveAs(); + + void faxoptions(); + void rotatePage(); + void mirrorPage(); + void flipPage(); + void nextPage(); + void prevPage(); + void newPage(); + void firstPage(); + void lastPage(); + void uiUpdate(); + + void openadd(QString filename); + void FreeFax(); + void scrollHorz(int); + void scrollVert(int); +}; + +void kfaxerror(const QString&, const QString&); +void loadfile(QString filename); + +#endif // _KFAX_H_ + diff --git a/kfax/kfax.tif b/kfax/kfax.tif Binary files differnew file mode 100644 index 00000000..85eec6bb --- /dev/null +++ b/kfax/kfax.tif diff --git a/kfax/kfax_printsettings.cpp b/kfax/kfax_printsettings.cpp new file mode 100644 index 00000000..02aa4050 --- /dev/null +++ b/kfax/kfax_printsettings.cpp @@ -0,0 +1,98 @@ +/* + * This file is part of the KDE libraries + * 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. + **/ + +#include "kfax_printsettings.h" + +#include <klocale.h> +#include <qcheckbox.h> +#include <qlayout.h> +#include <qwhatsthis.h> + +KFAXPrintSettings::KFAXPrintSettings(QWidget *parent, const char *name) +: KPrintDialogPage(parent, name) +{ + QString whatsThisScaleFullPage = i18n( "<qt>" + "<p><strong>'Ignore Paper Margins'</strong></p>" + "<p>" + "If this checkbox is enabled, the paper margins will be ignored " + "and the fax will be printed on the full paper size." + "</p>" + "<p>" + "If this checkbox is disabled, KFax will respect the standard paper " + "margins and print the fax inside this printable area." + "</p>" + " </qt>" ); + QString whatsThisCenterHorz = i18n( "<qt>" + "<p><strong>'Horizontal centered'</strong></p>" + "<p>" + "If this checkbox is enabled, the fax will be centered horizontally " + "on the page." + "</p>" + "<p>" + "If this checkbox is disabled, the fax will be printed at the left " + "side of the page." + "</p>" + " </qt>" ); + QString whatsThisCenterVert = i18n( "<qt>" + "<p><strong>'Vertical centered'</strong></p>" + "<p>" + "If this checkbox is enabled, the fax will be centered vertically " + "on the page." + "</p>" + "<p>" + "If this checkbox is disabled, the fax will be printed at the top " + "of the page." + "</p>" + " </qt>" ); + + setTitle(i18n("&Layout")); + + m_scaleFullPage = new QCheckBox(i18n("Ignore paper margins"), this); + QWhatsThis::add(m_scaleFullPage, whatsThisScaleFullPage); + m_center_horz = new QCheckBox(i18n("Horizontal centered"), this); + QWhatsThis::add(m_center_horz, whatsThisCenterHorz); + m_center_vert = new QCheckBox(i18n("Vertical centered"), this); + QWhatsThis::add(m_center_vert, whatsThisCenterVert); + + QVBoxLayout *l0 = new QVBoxLayout(this, 0, 10); + l0->addWidget(m_scaleFullPage); + l0->addWidget(m_center_horz); + l0->addWidget(m_center_vert); + l0->addStretch(1); +} + +KFAXPrintSettings::~KFAXPrintSettings() +{ +} + +void KFAXPrintSettings::getOptions(QMap<QString,QString>& opts, bool /*incldef*/) +{ + opts[APP_KFAX_SCALE_FULLPAGE] = (m_scaleFullPage->isChecked() ? "true" : "false"); + opts[APP_KFAX_CENTER_HORZ] = (m_center_horz->isChecked() ? "true" : "false"); + opts[APP_KFAX_CENTER_VERT] = (m_center_vert->isChecked() ? "true" : "false"); +} + +void KFAXPrintSettings::setOptions(const QMap<QString,QString>& opts) +{ + m_scaleFullPage->setChecked(opts[APP_KFAX_SCALE_FULLPAGE] == "true"); + m_center_horz->setChecked(opts[APP_KFAX_CENTER_HORZ] != "false"); + m_center_vert->setChecked(opts[APP_KFAX_CENTER_VERT] == "true"); +} + +#include "kfax_printsettings.moc" diff --git a/kfax/kfax_printsettings.h b/kfax/kfax_printsettings.h new file mode 100644 index 00000000..e43e3530 --- /dev/null +++ b/kfax/kfax_printsettings.h @@ -0,0 +1,47 @@ +/* + * This file is part of the KDE libraries + * 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 KFAX_PRINTSETTINGS_H +#define KFAX_PRINTSETTINGS_H + +#include <kdeprint/kprintdialogpage.h> + +class QCheckBox; + +#define APP_KFAX_SCALE_FULLPAGE "app-kfax-scalefullpage" +#define APP_KFAX_CENTER_HORZ "app-kfax-center-horz" +#define APP_KFAX_CENTER_VERT "app-kfax-center-vert" + +class KFAXPrintSettings : public KPrintDialogPage +{ + Q_OBJECT +public: + KFAXPrintSettings(QWidget *parent = 0, const char *name = 0); + ~KFAXPrintSettings(); + + void getOptions(QMap<QString,QString>& opts, bool incldef = false); + void setOptions(const QMap<QString,QString>& opts); + +private: + QCheckBox *m_scaleFullPage; + QCheckBox *m_center_horz; + QCheckBox *m_center_vert; +}; + +#endif diff --git a/kfax/kfaxlogo.xpm b/kfax/kfaxlogo.xpm new file mode 100644 index 00000000..8adb7087 --- /dev/null +++ b/kfax/kfaxlogo.xpm @@ -0,0 +1,134 @@ +/* XPM */ +static char *magick[] = { +/* columns rows colors chars-per-pixel */ +"90 120 8 1", +" c #ffffff", +". c #595959", +"X c #808080", +"o c #c0c0c0", +"O c #000000", +"+ c #dfdfdf", +"@ c #303030", +"# c #a0a0a4", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" .....X ...... o....o ", +" OOOOO. oOOOOOX +@OOOOOO@+ ", +" OOOOO. .OOOO@ +@OOOOOOOO@+ ", +" OOOOO. XOOOOO# @OOOOOOOOOO# ", +" OOOOO. @OOOO@ #OOOOOOOOO@+ ", +" OOOOO. XOOOOOo .OOOOO.@O. o...X+ o..... ..... ", +" OOOOO.+@OOOO. OOOOO. o #.OOOOOO. #OOOOO OOOOO ", +" OOOOO..OOOOO+ OOOOO. #OOOOOOOOO@+ #OOOOO OOOOO ", +" OOOOO@OOOOO. OOOOO. +OOOOOOOOOOO. #OOOOO OOOOO ", +" OOOOO@OOOOO# OOOOO@.o @OOOOOOOOOOOOo OOOOO++OOOOO ", +" OOOOO.@OOOO. OOOOOOO# OOOOOO..OOOOO. .OOOO@@OOOO. ", +" OOOOO.#OOOOOo OOOOOOO# #OOOOO# @OOOOO +.OOOOOOOO@+ ", +" OOOOO. OOOOO@ OOOOOOO# #OOOO. #OOOOO .OOOOOOOO. ", +" OOOOO. .OOOOOo OOOOOOO# oOOOO@ #OOOOO .OOOO@@OOOO. ", +" OOOOO. +OOOOO@ OOOOO.#+ OOOOO@###OOOOO OOOOO++OOOO@ ", +" OOOOO. @OOOOOo OOOOO. .OOOOOOO#OOOOO oOOOOO OOOOO ", +" OOOOO. #OOOOO@ OOOOO. +@OOOOOO#OOOOO #OOOOO OOOOO ", +" OOOOO. @OOOOOoOOOOO. o@OOOOO#OOOOO #OOOOO OOOOO ", +" OOOOO. .OOOOO.OOOOO. +@OOOO#OOOOO #OOOOO OOOOO ", +" #####o +####o######o o#.. ##### +##### ##### ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/kfax/kfaxui.rc b/kfax/kfaxui.rc new file mode 100644 index 00000000..35daf9f3 --- /dev/null +++ b/kfax/kfaxui.rc @@ -0,0 +1,28 @@ +<!DOCTYPE kpartgui> +<kpartgui version="2" name="kfax"> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="file_add_fax" append="open_merge"/> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="view_rotate"/> + <Action name="view_mirror"/> + <Action name="view_flip"/> + </Menu> +</MenuBar> + <ToolBar noMerge="1" name="mainToolBar" > + <text>Main Toolbar</text> + <Action name="file_open" /> + <Action name="file_save" /> + <Action name="file_print" /> + <Separator name="separator_2" /> + <Action name="go_previous" /> + <Action name="go_next" /> + <Separator name="separator_1" /> + <Action name="go_first" /> + <Action name="go_last" /> + <Separator name="separator_0" /> + <Action name="view_zoom_in" /> + <Action name="view_zoom_out" /> + </ToolBar> +</kpartgui> diff --git a/kfax/options.cpp b/kfax/options.cpp new file mode 100644 index 00000000..b8bf8067 --- /dev/null +++ b/kfax/options.cpp @@ -0,0 +1,374 @@ +/* + $Id$ + + Requires the Qt widget libraries, available at no cost at + http://www.troll.no + + Copyright (C) 1996 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + This program 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 <stdio.h> + +#include <qlayout.h> +#include <klocale.h> +#include <knuminput.h> +#include <qdir.h> +#include <qprinter.h> +#include <qframe.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qscrollbar.h> +#include <qtooltip.h> + +#include "kfax.h" +#include "options.h" + +OptionsDialog::OptionsDialog( QWidget *parent, const char *name) + : KDialogBase( parent, name, true, i18n("Configure"), Ok|Cancel) +{ + QWidget *mainWidget = new QWidget(this); + setMainWidget(mainWidget); + + QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget, 0, spacingHint()); + + bg = new QGroupBox(mainWidget,"bg"); + bg->setColumnLayout( 0, Qt::Horizontal ); + mainLayout->addWidget( bg ); + + QVBoxLayout *vbl = new QVBoxLayout(bg->layout()); + + QHBoxLayout *hbl1 = new QHBoxLayout(); + + vbl->addLayout( hbl1 ); + + displaylabel = new QLabel(i18n("Display options:"), bg,"displaylabel"); + displaylabel->setFixedSize( displaylabel->sizeHint() ); + hbl1->addWidget( displaylabel ); + + landscape = new QCheckBox(i18n("Landscape"), bg,"Landscape"); + landscape->setFixedSize( landscape->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( landscape ); + + flip = new QCheckBox(i18n("Upside down"), bg,"upsidedown"); + flip->setFixedSize( flip->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( flip ); + + invert = new QCheckBox(i18n("Invert"), bg,"invert"); + invert->setFixedSize( invert->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( invert ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl8 = new QHBoxLayout(); + vbl->addLayout( hbl8 ); + hbl8->addSpacing( 10 ); + + resgroup = new QButtonGroup(bg,"resgroup"); + resgroup->setFrameStyle(QFrame::NoFrame); + hbl8->addWidget( resgroup ); + + QHBoxLayout *hbl2 = new QHBoxLayout(resgroup); + + reslabel = new QLabel(i18n("Raw fax resolution:"),resgroup,"relabel"); + hbl2->addWidget( reslabel ); + + resauto = new QRadioButton(i18n("Auto"),resgroup,"resauto"); + hbl2->addSpacing( 20 ); + hbl2->addWidget( resauto ); + + fine = new QRadioButton(i18n("Fine"),resgroup,"fine"); + hbl2->addSpacing( 30 ); + hbl2->addWidget( fine ); + + normal = new QRadioButton(i18n("Normal"),resgroup,"normal"); + hbl2->addSpacing( 30 ); + hbl2->addWidget( normal ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl3 = new QHBoxLayout(); + vbl->addLayout( hbl3 ); + + lsblabel = new QLabel(i18n("Raw fax data are:"), bg,"lsblabel"); + hbl3->addSpacing( 10 ); + hbl3->addWidget( lsblabel ); + + lsb = new QCheckBox(i18n("LS-Bit first"), bg,"lsbitfirst"); + hbl3->addSpacing( 10 ); + hbl3->addWidget( lsb ); + + vbl->addSpacing( 15 ); + + QHBoxLayout *hbl9 = new QHBoxLayout(); + vbl->addLayout( hbl9 ); + hbl9->addSpacing( 10 ); + + rawgroup = new QButtonGroup(bg,"rawgroup"); + hbl9->addWidget( rawgroup ); + + QHBoxLayout *hbl4 = new QHBoxLayout( rawgroup ); + + rawgroup->setFrameStyle(QFrame::NoFrame); + + rawlabel = new QLabel(i18n("Raw fax format:"),rawgroup,"rawlabel"); + rawlabel->setFixedSize( rawlabel->sizeHint() ); + hbl4->addWidget( rawlabel ); + + g3 = new QRadioButton("G3",rawgroup,"g3"); + connect(g3,SIGNAL(clicked()), this, SLOT(g3toggled())); + hbl4->addSpacing( 20 ); + hbl4->addWidget( g3 ); + + g32d = new QRadioButton("G32d",rawgroup,"g32d"); + connect(g32d,SIGNAL(clicked()), this,SLOT(g32toggled())); + hbl4->addSpacing( 30 ); + hbl4->addWidget( g32d ); + + g4 = new QRadioButton("G4",rawgroup,"g4"); + connect(g4,SIGNAL(clicked()), this, SLOT(g4toggled())); + hbl4->addSpacing( 30 ); + hbl4->addWidget( g4 ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl5 = new QHBoxLayout(); + vbl->addLayout( hbl5 ); + + widthlabel = new QLabel(i18n("Raw fax width:"),bg,"widthlabel"); + hbl5->addSpacing( 10 ); + hbl5->addWidget( widthlabel ); + + widthedit = new KIntNumInput(1, bg); + widthedit->setRange(1, 10000, 1, false); + hbl5->addWidget( widthedit ); + + heightlabel = new QLabel(i18n("Height:"),bg,"heightlabel"); + hbl5->addSpacing( 10 ); + hbl5->addWidget( heightlabel ); + + heightedit = new KIntNumInput(1, bg); + heightedit->setRange(0, 100000, 1, false); + hbl5->addWidget( heightedit ); + + geomauto = new QCheckBox(i18n("Auto"),bg,"geomauto"); + connect(geomauto,SIGNAL(clicked()),this,SLOT(geomtoggled())); + hbl5->addSpacing( 10 ); + hbl5->addWidget( geomauto ); +} + + +struct optionsinfo * OptionsDialog::getInfo(){ + + if(resauto->isChecked()) + oi.resauto = 1; + + if(fine->isChecked()) + oi.fine = 1; + else + oi.fine = 0; + + if(landscape->isChecked()) + oi.landscape = 1; + else + oi.landscape = 0; + + if(flip->isChecked()) + oi.flip = 1; + else + oi.flip = 0; + + if(invert->isChecked()) + oi.invert = 1; + else + oi.invert = 0; + + if(lsb->isChecked()) + oi.lsbfirst = 1; + else + oi.lsbfirst = 0; + + if(geomauto->isChecked()) + oi.geomauto = 1; + + + if(g3->isChecked()){ + oi.raw = 3; + } + + if(g32d->isChecked()){ + oi.raw = 2; + oi.geomauto = 0; + + } + + if(g4->isChecked()){ + oi.raw = 4; + oi.geomauto = 0; + } + + oi.height = heightedit->value(); + oi.width = widthedit->value(); + + + + return &oi; + +} + +void OptionsDialog::setWidgets(struct optionsinfo* newoi ){ + + if(!newoi) + return; + + if(newoi->resauto == 1){ + resauto->setChecked(newoi->resauto); + fine->setChecked(!newoi->resauto); + normal->setChecked(!newoi->resauto); + } + else{ + if(newoi->fine == 1){ + resauto->setChecked(FALSE); + fine->setChecked(TRUE); + normal->setChecked(FALSE); + } + else{ + resauto->setChecked(FALSE); + fine->setChecked(FALSE); + normal->setChecked(TRUE); + } + } + + if(newoi->landscape == 1) + landscape->setChecked(TRUE); + else + landscape->setChecked(FALSE); + + if(newoi->flip == 1) + flip->setChecked(TRUE); + else + flip->setChecked(FALSE); + + if(newoi->invert == 1) + invert->setChecked(TRUE); + else + invert->setChecked(FALSE); + + if(newoi->lsbfirst == 1) + lsb->setChecked(TRUE); + else + lsb->setChecked(FALSE); + + if(newoi->raw == 3){ + geomauto->setEnabled(TRUE); + g3->setChecked(TRUE); + } + + if(newoi->raw == 2){ + geomauto->setEnabled(FALSE); + g32d->setChecked(TRUE); + } + + if(newoi->raw == 4){ + geomauto->setEnabled(FALSE); + g4->setChecked(TRUE); + } + widthedit->setValue(newoi->width); + heightedit->setValue(newoi->height); + + // auto height and width can only work with g3 faxes + if(newoi->geomauto == 1 && newoi->raw != 4 && newoi->raw != 2){ + geomauto->setChecked(TRUE); + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + } + else{ + geomauto->setChecked(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + } + +} + + +void OptionsDialog::g32toggled(){ + + geomauto->setChecked(FALSE); + geomauto->setEnabled(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + +} + +void OptionsDialog::g4toggled(){ + + geomauto->setChecked(FALSE); + geomauto->setEnabled(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + +} + + +void OptionsDialog::g3toggled(){ + + geomauto->setEnabled(TRUE); + geomauto->setChecked(TRUE); + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + + +} + +void OptionsDialog::geomtoggled(){ + + if(geomauto->isChecked()){ + + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + + } + else{ + + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + } + +} + +void OptionsDialog::slotHelp(){ + kapp->invokeHelp(); +} + + +#include "options.moc" diff --git a/kfax/options.h b/kfax/options.h new file mode 100644 index 00000000..fa9c61c9 --- /dev/null +++ b/kfax/options.h @@ -0,0 +1,112 @@ +/* + $Id$ + + + Copyright (C) 1996 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + This program 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 _OPTIONS_DIALOG_H_ +#define _OPTIONS_DIALOG_H_ + +#include <qapplication.h> +#include <qfiledialog.h> +#include <kdialogbase.h> +#include <qstring.h> + +class QGroupBox; +class QLabel; +class QButtonGroup; +class QRadioButton; +class QCheckBox; +class QRadioButton; + + +struct optionsinfo { + int geomauto; + int resauto; + int width ; + int height; + int fine; + int landscape; + int flip; + int invert; + int lsbfirst; + int raw; +}; + +class KIntNumInput; + +class OptionsDialog : public KDialogBase { + + Q_OBJECT + +public: + OptionsDialog( QWidget *parent = 0, const char *name = 0); + + struct optionsinfo* getInfo(); + void setWidgets(struct optionsinfo *oi); + +signals: + +public slots: + void slotHelp(); + void geomtoggled(); + void g32toggled(); + void g4toggled(); + void g3toggled(); + +private: + + QGroupBox *bg; + QLabel *reslabel; + QButtonGroup *resgroup; + QRadioButton *fine; + QRadioButton *resauto; + QRadioButton *normal; + QLabel *displaylabel; + QButtonGroup *displaygroup; + QCheckBox *landscape; + QCheckBox *geomauto; + QCheckBox *flip; + QCheckBox *invert; + + QButtonGroup *lsbgroup; + QLabel *lsblabel; + QCheckBox *lsb; + QButtonGroup *rawgroup; + QRadioButton *g3; + QRadioButton *g32d; + QRadioButton *g4; + + QLabel *rawlabel; + + QLabel *widthlabel; + QLabel *heightlabel; + KIntNumInput *widthedit; + KIntNumInput *heightedit; + + struct optionsinfo oi; + +}; + + +#endif diff --git a/kfax/version.h b/kfax/version.h new file mode 100644 index 00000000..ca6653cf --- /dev/null +++ b/kfax/version.h @@ -0,0 +1 @@ +#define KFAXVERSION "3.3.6" diff --git a/kfax/viewfax.cpp b/kfax/viewfax.cpp new file mode 100644 index 00000000..fe1e4246 --- /dev/null +++ b/kfax/viewfax.cpp @@ -0,0 +1,770 @@ +/* + + KFax -- A G3/G4 Fax Viewer + + Copyrigh (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + wuebben@kde.org + + Based on: + + viewfax - g3/g4 fax processing software. + 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> + +#include <qglobal.h> +#include <qdir.h> +#include <qfile.h> +#include <qevent.h> +#include <qprinter.h> +#include <qstring.h> + +#include <kcmdlineargs.h> +#include <klocale.h> + +#include "kfax.h" +#include "faxexpand.h" +#include "version.h" +#include "viewfax.h" + +/* NewImage() needs to fiddle with the Display structure */ +#define XLIB_ILLEGAL_ACCESS +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/keysymdef.h> +#include <X11/cursorfont.h> + + +#define VIEWFAXVERSION "2.3" + + +/* If moving the image around with the middle mouse button is jerky or + slow, try defining USE_MOTIONHINT. It may help (it may also make + things worse - it depends on the server implementation) */ +#undef USE_MOTIONHINT + + + +/* access the 'extra' field in a pagenode */ + +#define Pimage(p) ((XImage *)(p)->extra) + + +/* forward declarations */ + +XImage *FlipImage(XImage *xi); +XImage *MirrorImage(XImage *xi); +XImage *NewImage(int w, int h, char *data, int bit_order); +XImage *RotImage(XImage *Image); +XImage *ZoomImage(XImage *Big); + +void FreeImage(XImage *Image); + +static int release(int quit); + + +/* X variables */ + +extern Cursor WorkCursor; +extern Cursor ReadyCursor; +extern Cursor MoveCursor; +extern Cursor LRCursor; +extern Cursor UDCursor; + +extern bool have_no_fax; +extern Display* qtdisplay ; +extern Window qtwin; +extern Window Win; +extern int qwindow_width; +extern int qwindow_height; + +struct pagenode *firstpage, *lastpage, *thispage, *helppage, *auxpage; +struct pagenode defaultpage; + +Display *Disp; + +int Default_Screen; +int verbose = 0; + +int abell = 1; /* audio bell */ +int vbell = 0; /* visual bell */ +bool have_cmd_opt = FALSE; + +size_t Memused = 0; /* image memory usage */ +static size_t Memlimit = 8*1024*1024; /* try not to exceed */ + +#undef min +#undef max +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +/* OK, OK - this is a dreadful hack. But it adequately distinguishes + modern big- and little- endian hosts. We only need this to set the + byte order in XImage structures */ + +static union { t32bits i; unsigned char b[4]; } bo; +#define ByteOrder bo.b[3] + +static char Banner[] = +"KFax version " KFAXVERSION "\tCopyright (C) 1997, Bernd Johannes Wuebben\n"; + +/*"KFax is based on:\n" +"viewfax " VERSION ":\t\tCopyright (c) 1990, 1995 Frank D. Cringle.\n" +"libtiff v 3.4beta:\tCopyright (c) 1988 - 1955 Sam Leffler\n" +" \tCopyright (c) 1991 - 1995 Silicon Graphics, Inc.\n\n" +"KFax comes with ABSOLUTELY NO WARRANTY; for details see the\n" +"file \"COPYING\" in the distribution directory.\n";*/ + +XEvent Event; +XImage *Image, *Images[MAXZOOM]; +XSizeHints size_hints; + +Time Lasttime = 0; + +struct pagenode *viewpage = 0; + +int viewfaxmain() +{ + int banner = 0; + int have_height = 0; + + bo.i = 1; + defaultpage.vres = -1; + have_no_fax = TRUE; + + /* TODO Do I need to know this: */ + defaultpage.expander = g31expand; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("height")) + { + have_height = 1; + defaultpage.height = args->getOption("height").toInt(); + } + + if (args->isSet("2")) + { + defaultpage.expander = g32expand; + if(!have_height) + defaultpage.height = 2339; + } + + if (args->isSet("4")) + { + defaultpage.expander = g4expand; + if(!have_height) + defaultpage.height = 2155; + } + + if (args->isSet("invert")) + { + defaultpage.inverse = 1; + } + + if (args->isSet("landscape")) + { + defaultpage.orient |= TURN_L; + } + + if (args->isSet("fine")) + { + defaultpage.vres = 1; + } + + if (!args->isSet("rmal")) // "normal" is interpreted as "no"+"rmal" :-) + { + defaultpage.vres = 0; + } + + if (args->isSet("reverse")) + { + defaultpage.lsbfirst = 1; + } + + if (args->isSet("upsidedown")) + { + defaultpage.orient |= TURN_U; + } + + if (args->isSet("width")) + { + defaultpage.width = args->getOption("width").toInt(); + } + + QCString mem = args->getOption("mem"); + Memlimit = atoi(mem.data()); + switch(mem[mem.length()-1]) { + case 'M': + case 'm': + Memlimit *= 1024; + case 'K': + case 'k': + Memlimit *= 1024; + } + + if (defaultpage.expander == g4expand && defaultpage.height == 0) { + KCmdLineArgs::usage("--height value is required to interpret raw g4 faxes\n"); + } + + firstpage = lastpage = thispage = helppage = auxpage = 0; + + for (int i = 0; i < args->count(); i++){ + loadfile(QFile::decodeName(args->arg(i))); + } + args->clear(); + + if (banner ) { + fputs(Banner, stderr); + exit(1); + } + + have_no_fax = (firstpage == 0); + + Disp = qtdisplay; + Default_Screen = XDefaultScreen(qtdisplay); + + return 1; +} + + +/* Change orientation of all following pages */ +void TurnFollowing(int How, struct pagenode *pn) +{ + while (pn) { + if (Pimage(pn)) { + FreeImage(Pimage(pn)); + pn->extra = 0; + } + pn->orient ^= How; + pn = pn->next; + } +} + +static void +drawline(pixnum *run, int LineNum, struct 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->height) { + if (verbose && LineNum == pn->height) + fputs("Height exceeded\n", stderr); + return; + } + + p = (t32bits *) (Pimage(pn)->data + LineNum*(2-pn->vres)*Pimage(pn)->bytes_per_line); + p1 =(t32bits *)( pn->vres ? 0 : p + Pimage(pn)->bytes_per_line/sizeof(*p)); + r = run; + acc = 0; + nacc = 0; + pix = pn->inverse ? ~0 : 0; + tot = 0; + while (tot < pn->width) { + n = *r++; + tot += n; + /* Watch out for buffer overruns, e.g. when n == 65535. */ + if (tot > pn->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; + } +} + +static int +GetPartImage(struct 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 GetImage(struct pagenode *pn){ + int i; + + if (pn->strips == 0) { + + /*printf("RAW fax file\n");*/ + + /* raw file; maybe we don't have the height yet */ + unsigned char *Data = getstrip(pn, 0); + if (Data == 0){ + + return 0; + } + pn->extra = NewImage(pn->width, pn->vres ? + pn->height : 2*pn->height, 0, 1); + +//printf("height = %d\n",pn->height); +//printf("setting height to %d\n", pn->vres ? pn->height : 2*pn->height); + + if(pn->extra == 0) + return 0; + + (*pn->expander)(pn, drawline); + } + else { + /* multi-strip tiff */ + /*printf("MULTI STRIP TIFF fax file\n");*/ + + pn->extra = NewImage(pn->width, pn->vres ? + pn->height : 2*pn->height, 0, 1); + + if(pn->extra == 0) + return 0; + pn->stripnum = 0; + for (i = 0; i < pn->nstrips; i++){ + + int k =GetPartImage(pn, i); + + if ( k == 3 ){ + FreeImage(Pimage(pn)); + return k; + } + + } + } + if (pn->orient & TURN_U) + pn->extra = FlipImage(Pimage(pn)); + if (pn->orient & TURN_M) + pn->extra = MirrorImage(Pimage(pn)); + if (pn->orient & TURN_L) + pn->extra = RotImage(Pimage(pn)); + if (verbose) printf("\tmemused = %d\n", Memused); + +/* +if(pn->extra) + printf("pn->extra !=0 %s\n",pn->name); +else + printf("pn->extra ==0 %s\n",pn->name); + */ + + return 1; +} + + + +/* run this region through perl to generate the zoom table: +$lim = 1; +@c = ("0", "1", "1", "2"); +print "static unsigned char Z[] = {\n"; +for ($i = 0; $i < 16; $i++) { + for ($j = 0; $j < 16; $j++) { + $b1 = ($c[$j&3]+$c[$i&3]) > $lim; + $b2 = ($c[($j>>2)&3]+$c[($i>>2)&3]) > $lim; + printf " %X,", ($b2 << 1) | $b1; + } + print "\n"; +} +print "};\n"; +*/ + +static unsigned char Z[] = { + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +#define nib(n,w) (((w)>>((n)<<2))&15) +#define zak(a,b) Z[(a<<4)|b] + +/* 2 -> 1 zoom, 4 pixels -> 1 pixel + if #pixels <= $lim (see above), new pixel is white, + else black. +*/ + +XImage *ZoomImage(XImage *Big){ + + XImage *Small; + int w, h; + int i, j; + + XDefineCursor(Disp, Win, WorkCursor); + XFlush(Disp); + w = (Big->width+1) / 2; + h = (Big->height+1) / 2; + Small = NewImage(w, h, 0, Big->bitmap_bit_order); + if(Small == 0) + return 0; + + Small->xoffset = (Big->xoffset+1)/2; + for (i = 0; i < Big->height; i += 2) { + t32bits *pb0 = (t32bits *) (Big->data + i * Big->bytes_per_line); + t32bits *pb1 = pb0 + ((i == Big->height-1) ? 0 : Big->bytes_per_line/4); + t32bits *ps = (t32bits *) (Small->data + i * Small->bytes_per_line / 2); + for (j = 0; j < Big->bytes_per_line/8; j++) { + t32bits r1, r2; + t32bits t0 = *pb0++; + t32bits t1 = *pb1++; + r1 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + t0 = *pb0++; + t1 = *pb1++; + r2 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + *ps++ = (Big->bitmap_bit_order) ? + (r1<<16)|r2 : (r2<<16)|r1; + } + for ( ; j < Small->bytes_per_line/4; j++) { + t32bits r1; + t32bits t0 = *pb0++; + t32bits t1 = *pb1++; + r1 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + *ps++ = (Big->bitmap_bit_order) ? + (r1<<16) : r1; + } + } + XDefineCursor(Disp, Win, ReadyCursor); + return Small; +} + +XImage *FlipImage(XImage *Image){ + + XImage *New = NewImage(Image->width, Image->height, + Image->data, !Image->bitmap_bit_order); + if(New == 0) + return 0; + + t32bits *p1 = (t32bits *) Image->data; + t32bits *p2 = (t32bits *) (Image->data + Image->height * + Image->bytes_per_line - 4); + + /* the first shall be last ... */ + while (p1 < p2) { + t32bits t = *p1; + *p1++ = *p2; + *p2-- = t; + } + + /* let Xlib twiddle the bits */ + New->xoffset = 32 - (Image->width & 31) - Image->xoffset; + New->xoffset &= 31; + + Image->data = 0; + FreeImage(Image); + return New; +} + +XImage *MirrorImage(XImage *Image){ + + int i; + XImage *New = NewImage(Image->width, Image->height, + Image->data, !Image->bitmap_bit_order); + if(New == 0) + return 0; + + /* reverse order of 32-bit words in each line */ + for (i = 0; i < Image->height; i++) { + t32bits *p1 = (t32bits *) (Image->data + Image->bytes_per_line * i); + t32bits *p2 = p1 + Image->bytes_per_line/4 - 1; + while (p1 < p2) { + t32bits t = *p1; + *p1++ = *p2; + *p2-- = t; + } + } + + /* let Xlib twiddle the bits */ + New->xoffset = 32 - (Image->width & 31) - Image->xoffset; + New->xoffset &= 31; + + Image->data = 0; + FreeImage(Image); + return New; +} + +XImage *RotImage(XImage *Image){ + + XImage *New; + int w = Image->height; + int h = Image->width; + int i, j, k, shift; + int order = Image->bitmap_bit_order; + int offs = h+Image->xoffset-1; + + New = NewImage(w, h, 0, 1); + if (New == 0) + return 0; + + k = (32 - Image->xoffset) & 3; + for (i = h - 1; i && k; i--, k--) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits d0 =0; + shift = (offs-i)&31; + if (order) shift = 31-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp; + sp += Image->bytes_per_line/4; + d0 |= ((t >> shift) & 1); + if ((j & 31) == 31) + *dp++ = d0; + d0 <<= 1;; + } + if (j & 31) + *dp++ = d0<<(31-j); + } + for ( ; i >= 3; i-=4) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp0 = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits *dp1 = dp0 - New->bytes_per_line/4; + t32bits *dp2 = dp1 - New->bytes_per_line/4; + t32bits *dp3 = dp2 - New->bytes_per_line/4; + t32bits d0=0 , d1=0, d2 =0, d3 =0; + shift = (offs-i)&31; + if (order) shift = 28-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp >> shift; + sp += Image->bytes_per_line/4; + d0 |= t & 1; t >>= 1; + d1 |= t & 1; t >>= 1; + d2 |= t & 1; t >>= 1; + d3 |= t & 1; t >>= 1; + if ((j & 31) == 31) { + if (order) { + *dp0++ = d3; + *dp1++ = d2; + *dp2++ = d1; + *dp3++ = d0; + } + else { + *dp0++ = d0; + *dp1++ = d1; + *dp2++ = d2; + *dp3++ = d3; + } + } + d0 <<= 1; d1 <<= 1; d2 <<= 1; d3 <<= 1; + } + if (j & 31) { + if (order) { + *dp0++ = d3<<(31-j); + *dp1++ = d2<<(31-j); + *dp2++ = d1<<(31-j); + *dp3++ = d0<<(31-j); + } + else { + *dp0++ = d0<<(31-j); + *dp1++ = d1<<(31-j); + *dp2++ = d2<<(31-j); + *dp3++ = d3<<(31-j); + } + } + } + for (; i >= 0; i--) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits d0=0; + shift = (offs-i)&31; + if (order) shift = 31-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp; + sp += Image->bytes_per_line/4; + d0 |= ((t >> shift) & 1); + if ((j & 31) == 31) + *dp++ = d0; + d0 <<= 1;; + } + if (j & 31) + *dp++ = d0<<(31-j); + } + FreeImage(Image); + return New; +} + +/* release some non-essential memory or abort */ +#define Try(n) \ + if (n && n != thispage && n->extra) { \ + FreeImage((XImage*)n->extra); \ + n->extra = 0; \ + return 1; \ + } + +static int +release(int quit) +{ + (void) quit; + + struct pagenode *pn; + + if (thispage) { + /* first consider "uninteresting" pages */ + for (pn = firstpage->next; pn; pn = pn->next) + if (pn->extra && pn != thispage && pn != thispage->prev && + pn != thispage->next && pn != lastpage) { + FreeImage(Pimage(pn)); + pn->extra = 0; + return 1; + } + Try(lastpage); + Try(firstpage); + Try(thispage->prev); + Try(thispage->next); + } + + return 0; + +} + +XImage *NewImage(int w, int h, char *data, int bit_order){ + + XImage *newimage; + /* This idea is taken from xwud/xpr. Use a fake display with the + desired bit/byte order to get the image routines initialised + correctly */ + Display fake; + + fake = *Disp; + if (data == 0) + data = xmalloc(((w + 31) & ~31) * h / 8); + fake.byte_order = ByteOrder; + fake.bitmap_unit = 32; + fake.bitmap_bit_order = bit_order; + + int returncode = -1; + while ((newimage = XCreateImage(&fake, DefaultVisual(Disp, Default_Screen), + 1, XYBitmap, 0, data, w, h, 32, 0)) == 0 ){ + + returncode = release(1); + if (returncode == 0) + break; + } + + if (returncode == 0){ + kfaxerror("Sorry","Can not allocate Memory for a new Fax Image\n"); + return 0; + } + + Memused += newimage->bytes_per_line * newimage->height; + /*printf("allocating %d bytes for %ld\n", + newimage->bytes_per_line * newimage->height, + newimage);*/ + + + return newimage; +} + +void FreeImage(XImage *Image){ + + if (Image->data){ + Memused -= Image->bytes_per_line * Image->height; +/*printf("deallocating %d bytes for %ld\n", + Image->bytes_per_line * Image->height, + Image);*/ + } + XDestroyImage(Image); +} + +#ifndef xmalloc +char * +xmalloc(unsigned int size) +{ + char *p; + + while (Memused + size > Memlimit && release(0)) + ; + while ((p = (char*) malloc(size)) == 0) + (void) release(1); + return p; +} +#endif diff --git a/kfax/viewfax.h b/kfax/viewfax.h new file mode 100644 index 00000000..92ffbd70 --- /dev/null +++ b/kfax/viewfax.h @@ -0,0 +1,27 @@ +/* + This file is part of KFAX + Copyright (c) 1999 Waldo Bastian <bastian@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 _VIEWFAX_H_ +#define _VIEWFAX_H_ + +#define MAXZOOM 4 + +int viewfaxmain(); + +#endif |