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