539 lines
16 KiB
C
539 lines
16 KiB
C
/* $Id: tif_fax3.h,v 1.9 2011-03-10 20:23:07 fwarmerdam Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1990-1997 Sam Leffler
|
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that (i) the above copyright notices and this permission notice appear in
|
|
* all copies of the software and related documentation, and (ii) the names of
|
|
* Sam Leffler and Silicon Graphics may not be used in any advertising or
|
|
* publicity relating to the software without the specific, prior written
|
|
* permission of Sam Leffler and Silicon Graphics.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
|
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifndef _FAX3_
|
|
#define _FAX3_
|
|
/*
|
|
* TIFF Library.
|
|
*
|
|
* CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support.
|
|
*
|
|
* Decoder support is derived, with permission, from the code
|
|
* in Frank Cringle's viewfax program;
|
|
* Copyright (C) 1990, 1995 Frank D. Cringle.
|
|
*/
|
|
#include "tiff.h"
|
|
|
|
/*
|
|
* To override the default routine used to image decoded
|
|
* spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC.
|
|
* The routine must have the type signature given below;
|
|
* for example:
|
|
*
|
|
* fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
|
|
*
|
|
* where buf is place to set the bits, runs is the array of b&w run
|
|
* lengths (white then black), erun is the last run in the array, and
|
|
* lastx is the width of the row in pixels. Fill routines can assume
|
|
* the run array has room for at least lastx runs and can overwrite
|
|
* data in the run array as needed (e.g. to append zero runs to bring
|
|
* the count up to a nice multiple).
|
|
*/
|
|
typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32);
|
|
|
|
/*
|
|
* The default run filler; made external for other decoders.
|
|
*/
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32);
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
|
|
/* finite state machine 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
|
|
|
|
typedef struct { /* state table entry */
|
|
unsigned char State; /* see above */
|
|
unsigned char Width; /* width of code in bits */
|
|
uint32 Param; /* unsigned 32-bit run length in bits */
|
|
} TIFFFaxTabEnt;
|
|
|
|
extern const TIFFFaxTabEnt TIFFFaxMainTable[];
|
|
extern const TIFFFaxTabEnt TIFFFaxWhiteTable[];
|
|
extern const TIFFFaxTabEnt TIFFFaxBlackTable[];
|
|
|
|
/*
|
|
* The following macros define the majority of the G3/G4 decoder
|
|
* algorithm using the state tables defined elsewhere. To build
|
|
* a decoder you need some setup code and some glue code. Note
|
|
* that you may also need/want to change the way the NeedBits*
|
|
* macros get input data if, for example, you know the data to be
|
|
* decoded is properly aligned and oriented (doing so before running
|
|
* the decoder can be a big performance win).
|
|
*
|
|
* Consult the decoder in the TIFF library for an idea of what you
|
|
* need to define and setup to make use of these definitions.
|
|
*
|
|
* NB: to enable a debugging version of these macros define FAX3_DEBUG
|
|
* before including this file. Trace output goes to stdout.
|
|
*/
|
|
|
|
#ifndef EndOfData
|
|
#define EndOfData() (cp >= ep)
|
|
#endif
|
|
/*
|
|
* Need <=8 or <=16 bits of input data. Unlike viewfax we
|
|
* cannot use/assume a word-aligned, properly bit swizzled
|
|
* input data set because data may come from an arbitrarily
|
|
* aligned, read-only source such as a memory-mapped file.
|
|
* Note also that the viewfax decoder does not check for
|
|
* running off the end of the input data buffer. This is
|
|
* possible for G3-encoded data because it prescans the input
|
|
* data to count EOL markers, but can cause problems for G4
|
|
* data. In any event, we don't prescan and must watch for
|
|
* running out of data since we can't permit the library to
|
|
* scan past the end of the input data buffer.
|
|
*
|
|
* Finally, note that we must handle remaindered data at the end
|
|
* of a strip specially. The coder asks for a fixed number of
|
|
* bits when scanning for the next code. This may be more bits
|
|
* than are actually present in the data stream. If we appear
|
|
* to run out of data but still have some number of valid bits
|
|
* remaining then we makeup the requested amount with zeros and
|
|
* return successfully. If the returned data is incorrect then
|
|
* we should be called again and get a premature EOF error;
|
|
* otherwise we should get the right answer.
|
|
*/
|
|
#ifndef NeedBits8
|
|
#define NeedBits8(n,eoflab) do { \
|
|
if (BitsAvail < (n)) { \
|
|
if (EndOfData()) { \
|
|
if (BitsAvail == 0) /* no valid bits */ \
|
|
goto eoflab; \
|
|
BitsAvail = (n); /* pad with zeros */ \
|
|
} else { \
|
|
BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
|
|
BitsAvail += 8; \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
#ifndef NeedBits16
|
|
#define NeedBits16(n,eoflab) do { \
|
|
if (BitsAvail < (n)) { \
|
|
if (EndOfData()) { \
|
|
if (BitsAvail == 0) /* no valid bits */ \
|
|
goto eoflab; \
|
|
BitsAvail = (n); /* pad with zeros */ \
|
|
} else { \
|
|
BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
|
|
if ((BitsAvail += 8) < (n)) { \
|
|
if (EndOfData()) { \
|
|
/* NB: we know BitsAvail is non-zero here */ \
|
|
BitsAvail = (n); /* pad with zeros */ \
|
|
} else { \
|
|
BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
|
|
BitsAvail += 8; \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
#define GetBits(n) (BitAcc & ((1<<(n))-1))
|
|
#define ClrBits(n) do { \
|
|
BitsAvail -= (n); \
|
|
BitAcc >>= (n); \
|
|
} while (0)
|
|
|
|
#ifdef FAX3_DEBUG
|
|
static const char* StateNames[] = {
|
|
"Null ",
|
|
"Pass ",
|
|
"Horiz ",
|
|
"V0 ",
|
|
"VR ",
|
|
"VL ",
|
|
"Ext ",
|
|
"TermW ",
|
|
"TermB ",
|
|
"MakeUpW",
|
|
"MakeUpB",
|
|
"MakeUp ",
|
|
"EOL ",
|
|
};
|
|
#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
|
|
#define LOOKUP8(wid,tab,eoflab) do { \
|
|
int t; \
|
|
NeedBits8(wid,eoflab); \
|
|
TabEnt = tab + GetBits(wid); \
|
|
printf("%08lX/%d: %s%5d\t", (long) 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 LOOKUP16(wid,tab,eoflab) do { \
|
|
int t; \
|
|
NeedBits16(wid,eoflab); \
|
|
TabEnt = tab + GetBits(wid); \
|
|
printf("%08lX/%d: %s%5d\t", (long) 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 SETVALUE(x) do { \
|
|
*pa++ = RunLength + (x); \
|
|
printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \
|
|
a0 += x; \
|
|
RunLength = 0; \
|
|
} while (0)
|
|
#else
|
|
#define LOOKUP8(wid,tab,eoflab) do { \
|
|
NeedBits8(wid,eoflab); \
|
|
TabEnt = tab + GetBits(wid); \
|
|
ClrBits(TabEnt->Width); \
|
|
} while (0)
|
|
#define LOOKUP16(wid,tab,eoflab) do { \
|
|
NeedBits16(wid,eoflab); \
|
|
TabEnt = tab + GetBits(wid); \
|
|
ClrBits(TabEnt->Width); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Append a run to the run length array for the
|
|
* current row and reset decoding state.
|
|
*/
|
|
#define SETVALUE(x) do { \
|
|
*pa++ = RunLength + (x); \
|
|
a0 += (x); \
|
|
RunLength = 0; \
|
|
} while (0)
|
|
#endif
|
|
|
|
/*
|
|
* Synchronize input decoding at the start of each
|
|
* row by scanning for an EOL (if appropriate) and
|
|
* skipping any trash data that might be present
|
|
* after a decoding error. Note that the decoding
|
|
* done elsewhere that recognizes an EOL only consumes
|
|
* 11 consecutive zero bits. This means that if EOLcnt
|
|
* is non-zero then we still need to scan for the final flag
|
|
* bit that is part of the EOL code.
|
|
*/
|
|
#define SYNC_EOL(eoflab) do { \
|
|
if (EOLcnt == 0) { \
|
|
for (;;) { \
|
|
NeedBits16(11,eoflab); \
|
|
if (GetBits(11) == 0) \
|
|
break; \
|
|
ClrBits(1); \
|
|
} \
|
|
} \
|
|
for (;;) { \
|
|
NeedBits8(8,eoflab); \
|
|
if (GetBits(8)) \
|
|
break; \
|
|
ClrBits(8); \
|
|
} \
|
|
while (GetBits(1) == 0) \
|
|
ClrBits(1); \
|
|
ClrBits(1); /* EOL bit */ \
|
|
EOLcnt = 0; /* reset EOL counter/flag */ \
|
|
} while (0)
|
|
|
|
/*
|
|
* Cleanup the array of runs after decoding a row.
|
|
* We adjust final runs to insure the user buffer is not
|
|
* overwritten and/or undecoded area is white filled.
|
|
*/
|
|
#define CLEANUP_RUNS() do { \
|
|
if (RunLength) \
|
|
SETVALUE(0); \
|
|
if (a0 != lastx) { \
|
|
badlength(a0, lastx); \
|
|
while (a0 > lastx && pa > thisrun) \
|
|
a0 -= *--pa; \
|
|
if (a0 < lastx) { \
|
|
if (a0 < 0) \
|
|
a0 = 0; \
|
|
if ((pa-thisrun)&1) \
|
|
SETVALUE(0); \
|
|
SETVALUE(lastx - a0); \
|
|
} else if (a0 > lastx) { \
|
|
SETVALUE(lastx); \
|
|
SETVALUE(0); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* Decode a line of 1D-encoded data.
|
|
*
|
|
* The line expanders are written as macros so that they can be reused
|
|
* but still have direct access to the local variables of the "calling"
|
|
* function.
|
|
*
|
|
* Note that unlike the original version we have to explicitly test for
|
|
* a0 >= lastx after each black/white run is decoded. This is because
|
|
* the original code depended on the input data being zero-padded to
|
|
* insure the decoder recognized an EOL before running out of data.
|
|
*/
|
|
#define EXPAND1D(eoflab) do { \
|
|
for (;;) { \
|
|
for (;;) { \
|
|
LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \
|
|
switch (TabEnt->State) { \
|
|
case S_EOL: \
|
|
EOLcnt = 1; \
|
|
goto done1d; \
|
|
case S_TermW: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneWhite1d; \
|
|
case S_MakeUpW: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
unexpected("WhiteTable", a0); \
|
|
goto done1d; \
|
|
} \
|
|
} \
|
|
doneWhite1d: \
|
|
if (a0 >= lastx) \
|
|
goto done1d; \
|
|
for (;;) { \
|
|
LOOKUP16(13, TIFFFaxBlackTable, eof1d); \
|
|
switch (TabEnt->State) { \
|
|
case S_EOL: \
|
|
EOLcnt = 1; \
|
|
goto done1d; \
|
|
case S_TermB: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneBlack1d; \
|
|
case S_MakeUpB: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
unexpected("BlackTable", a0); \
|
|
goto done1d; \
|
|
} \
|
|
} \
|
|
doneBlack1d: \
|
|
if (a0 >= lastx) \
|
|
goto done1d; \
|
|
if( *(pa-1) == 0 && *(pa-2) == 0 ) \
|
|
pa -= 2; \
|
|
} \
|
|
eof1d: \
|
|
prematureEOF(a0); \
|
|
CLEANUP_RUNS(); \
|
|
goto eoflab; \
|
|
done1d: \
|
|
CLEANUP_RUNS(); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Update the value of b1 using the array
|
|
* of runs for the reference line.
|
|
*/
|
|
#define CHECK_b1 do { \
|
|
if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \
|
|
b1 += pb[0] + pb[1]; \
|
|
pb += 2; \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* Expand a row of 2D-encoded data.
|
|
*/
|
|
#define EXPAND2D(eoflab) do { \
|
|
while (a0 < lastx) { \
|
|
LOOKUP8(7, TIFFFaxMainTable, eof2d); \
|
|
switch (TabEnt->State) { \
|
|
case S_Pass: \
|
|
CHECK_b1; \
|
|
b1 += *pb++; \
|
|
RunLength += b1 - a0; \
|
|
a0 = b1; \
|
|
b1 += *pb++; \
|
|
break; \
|
|
case S_Horiz: \
|
|
if ((pa-thisrun)&1) { \
|
|
for (;;) { /* black first */ \
|
|
LOOKUP16(13, TIFFFaxBlackTable, eof2d); \
|
|
switch (TabEnt->State) { \
|
|
case S_TermB: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneWhite2da; \
|
|
case S_MakeUpB: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
goto badBlack2d; \
|
|
} \
|
|
} \
|
|
doneWhite2da:; \
|
|
for (;;) { /* then white */ \
|
|
LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \
|
|
switch (TabEnt->State) { \
|
|
case S_TermW: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneBlack2da; \
|
|
case S_MakeUpW: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
goto badWhite2d; \
|
|
} \
|
|
} \
|
|
doneBlack2da:; \
|
|
} else { \
|
|
for (;;) { /* white first */ \
|
|
LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \
|
|
switch (TabEnt->State) { \
|
|
case S_TermW: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneWhite2db; \
|
|
case S_MakeUpW: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
goto badWhite2d; \
|
|
} \
|
|
} \
|
|
doneWhite2db:; \
|
|
for (;;) { /* then black */ \
|
|
LOOKUP16(13, TIFFFaxBlackTable, eof2d); \
|
|
switch (TabEnt->State) { \
|
|
case S_TermB: \
|
|
SETVALUE(TabEnt->Param); \
|
|
goto doneBlack2db; \
|
|
case S_MakeUpB: \
|
|
case S_MakeUp: \
|
|
a0 += TabEnt->Param; \
|
|
RunLength += TabEnt->Param; \
|
|
break; \
|
|
default: \
|
|
goto badBlack2d; \
|
|
} \
|
|
} \
|
|
doneBlack2db:; \
|
|
} \
|
|
CHECK_b1; \
|
|
break; \
|
|
case S_V0: \
|
|
CHECK_b1; \
|
|
SETVALUE(b1 - a0); \
|
|
b1 += *pb++; \
|
|
break; \
|
|
case S_VR: \
|
|
CHECK_b1; \
|
|
SETVALUE(b1 - a0 + TabEnt->Param); \
|
|
b1 += *pb++; \
|
|
break; \
|
|
case S_VL: \
|
|
CHECK_b1; \
|
|
if (b1 <= (int) (a0 + TabEnt->Param)) { \
|
|
if (b1 < (int) (a0 + TabEnt->Param) || pa != thisrun) { \
|
|
unexpected("VL", a0); \
|
|
goto eol2d; \
|
|
} \
|
|
} \
|
|
SETVALUE(b1 - a0 - TabEnt->Param); \
|
|
b1 -= *--pb; \
|
|
break; \
|
|
case S_Ext: \
|
|
*pa++ = lastx - a0; \
|
|
extension(a0); \
|
|
goto eol2d; \
|
|
case S_EOL: \
|
|
*pa++ = lastx - a0; \
|
|
NeedBits8(4,eof2d); \
|
|
if (GetBits(4)) \
|
|
unexpected("EOL", a0); \
|
|
ClrBits(4); \
|
|
EOLcnt = 1; \
|
|
goto eol2d; \
|
|
default: \
|
|
badMain2d: \
|
|
unexpected("MainTable", a0); \
|
|
goto eol2d; \
|
|
badBlack2d: \
|
|
unexpected("BlackTable", a0); \
|
|
goto eol2d; \
|
|
badWhite2d: \
|
|
unexpected("WhiteTable", a0); \
|
|
goto eol2d; \
|
|
eof2d: \
|
|
prematureEOF(a0); \
|
|
CLEANUP_RUNS(); \
|
|
goto eoflab; \
|
|
} \
|
|
} \
|
|
if (RunLength) { \
|
|
if (RunLength + a0 < lastx) { \
|
|
/* expect a final V0 */ \
|
|
NeedBits8(1,eof2d); \
|
|
if (!GetBits(1)) \
|
|
goto badMain2d; \
|
|
ClrBits(1); \
|
|
} \
|
|
SETVALUE(0); \
|
|
} \
|
|
eol2d: \
|
|
CLEANUP_RUNS(); \
|
|
} while (0)
|
|
#endif /* _FAX3_ */
|
|
/*
|
|
* Local Variables:
|
|
* mode: c
|
|
* c-basic-offset: 8
|
|
* fill-column: 78
|
|
* End:
|
|
*/
|