2025-04-27 07:49:33 -04:00

787 lines
24 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
tiffcomp.c
Abstract:
Implement CCITT group 4 compression scheme
Revision History:
12/30/96 -davidx-
Created it.
--*/
// converting the bitmap from CPSI to a TIFF file
// implementation of CCITT group 4 compression algorithm
// TIFF field tag and type constants
#define TIFFTYPE_ASCII 2
#define TIFFTYPE_SHORT 3
#define TIFFTYPE_LONG 4
#define TIFFTYPE_RATIONAL 5
#define TIFFTAG_NEWSUBFILETYPE 254
#define SUBFILETYPE_PAGE 2
#define TIFFTAG_IMAGEWIDTH 256
#define TIFFTAG_IMAGEHEIGHT 257
#define TIFFTAG_BITSPERSAMPLE 258
#define TIFFTAG_COMPRESSION 259
#define COMPRESSION_G3FAX 3
#define COMPRESSION_G4FAX 4
#define TIFFTAG_PHOTOMETRIC 262
#define PHOTOMETRIC_WHITEIS0 0
#define PHOTOMETRIC_BLACKIS0 1
#define TIFFTAG_FILLORDER 266
#define FILLORDER_MSB 1
#define FILLORDER_LSB 2
#define TIFFTAG_STRIPOFFSETS 273
#define TIFFTAG_SAMPLESPERPIXEL 277
#define TIFFTAG_ROWSPERSTRIP 278
#define TIFFTAG_STRIPBYTECOUNTS 279
#define TIFFTAG_XRESOLUTION 282
#define TIFFF_RES_X 204
#define TIFFTAG_YRESOLUTION 283
#define TIFFF_RES_Y 196
#define TIFFF_RES_Y_DRAFT 98
#define TIFFTAG_G3OPTIONS 292
#define G3_2D 1
#define G3_ALIGNEOL 4
#define TIFFTAG_G4OPTIONS 293
#define TIFFTAG_RESUNIT 296
#define RESUNIT_INCH 2
#define TIFFTAG_PAGENUMBER 297
#define TIFFTAG_SOFTWARE 305
#define TIFFTAG_CLEANFAXDATA 327
// Data structure for representing our TIFF output file header information
typedef struct {
INT16 magic1; // II
INT16 magic2; // 42
INT32 firstIFDOffset; // offset to first IFD
} TIFF_FILEHEADER;
static TIFF_FILEHEADER tiffFileHeader = { 'II', 42, 0 };
// Data structure for representing a single IFD entry
typedef struct {
INT16 tag; // field tag
INT16 type; // field type
INT32 count; // number of values
INT32 value; // value or value offset
} IFDENTRY;
typedef struct {
IFDENTRY ifdNewSubFileType;
IFDENTRY ifdImageWidth;
IFDENTRY ifdImageHeight;
IFDENTRY ifdBitsPerSample;
IFDENTRY ifdCompression;
IFDENTRY ifdPhotometric;
IFDENTRY ifdFillOrder;
IFDENTRY ifdStripOffsets;
IFDENTRY ifdSamplesPerPixel;
IFDENTRY ifdRowsPerStrip;
IFDENTRY ifdStripByteCounts;
IFDENTRY ifdXResolution;
IFDENTRY ifdYResolution;
IFDENTRY ifdG4Options;
IFDENTRY ifdResolutionUnit;
IFDENTRY ifdPageNumber;
IFDENTRY ifdSoftware;
IFDENTRY ifdCleanFaxData;
INT32 nextIFDOffset;
INT32 reserved;
INT32 xresNum;
INT32 xresDenom;
INT32 yresNum;
INT32 yresDenom;
char software[32];
} IFD;
#define IFD_COUNT (offsetof(IFD, nextIFDOffset) / sizeof(IFDENTRY))
#define tiffCopyright "Microsoft"
static IFD ifdTemplate = {
{ TIFFTAG_NEWSUBFILETYPE, TIFFTYPE_LONG, 1, SUBFILETYPE_PAGE },
{ TIFFTAG_IMAGEWIDTH, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_IMAGEHEIGHT, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_BITSPERSAMPLE, TIFFTYPE_SHORT, 1, 1 },
{ TIFFTAG_COMPRESSION, TIFFTYPE_SHORT, 1, COMPRESSION_G4FAX },
{ TIFFTAG_PHOTOMETRIC, TIFFTYPE_SHORT, 1, PHOTOMETRIC_WHITEIS0 },
{ TIFFTAG_FILLORDER, TIFFTYPE_SHORT, 1, FILLORDER_MSB },
{ TIFFTAG_STRIPOFFSETS, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_SAMPLESPERPIXEL, TIFFTYPE_SHORT, 1, 1 },
{ TIFFTAG_ROWSPERSTRIP, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_STRIPBYTECOUNTS, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_XRESOLUTION, TIFFTYPE_RATIONAL, 1, 0 },
{ TIFFTAG_YRESOLUTION, TIFFTYPE_RATIONAL, 1, 0 },
{ TIFFTAG_G4OPTIONS, TIFFTYPE_LONG, 1, 0 },
{ TIFFTAG_RESUNIT, TIFFTYPE_SHORT, 1, RESUNIT_INCH },
{ TIFFTAG_PAGENUMBER, TIFFTYPE_SHORT, 2, 0 },
{ TIFFTAG_SOFTWARE, TIFFTYPE_ASCII, sizeof(tiffCopyright), 0 },
{ TIFFTAG_CLEANFAXDATA, TIFFTYPE_SHORT, 1, 0 },
0,
0,
0,
1,
0,
1,
tiffCopyright
};
// Find the next pixel on the scanline whose color is opposite of
// the specified color, starting from the specified starting point
#define NextChangingElement(buf, startBit, stopBit, isBlack) \
((startBit) + ((isBlack) ? FindBlackRun((buf), (startBit), (stopBit)) : \
FindWhiteRun((buf), (startBit), (stopBit))))
// Check if the specified pixel on the scanline is black or white
// 1 - the specified pixel is black
// 0 - the specified pixel is white
#define GetBit(buf, bit) (((buf)[(bit) >> 3] >> (((bit) ^ 7) & 7)) & 1)
// Write a single byte of compressed data to the output
#define OutputByte(data) { \
fputc((data), fout); \
outputByteCnt++; \
}
// Output a sequence of compressed bits
#define OutputBits(length, code) { \
tiffData |= ((UINT32) (code) << (tiffDataBits - (length))); \
if ((tiffDataBits -= (length)) <= 16) { \
OutputByte(tiffData >> 24); \
OutputByte(tiffData >> 16); \
tiffData <<= 16; \
tiffDataBits += 16; \
} \
}
// Data structure for representing code table entries
typedef struct {
UINT16 length; // code length
UINT16 code; // code word itself
} CODETABLE;
typedef const CODETABLE *PCODETABLE;
// Code word for end-of-line (EOL)
// 000000000001
#define EOL_CODE 1
#define EOL_LENGTH 12
// Code word for 2D encoding - pass mode
// 0001
#define PASSCODE 1
#define PASSCODE_LENGTH 4
// Code word for 2D encoding - horizontal mode prefix
// 001
#define HORZCODE 1
#define HORZCODE_LENGTH 3
// Code word for 2D encoding - vertical mode
static const CODETABLE VertCodes[] = {
{ 7, 0x02 }, // 0000010 VL3
{ 6, 0x02 }, // 000010 VL2
{ 3, 0x02 }, // 010 VL1
{ 1, 0x01 }, // 1 V0
{ 3, 0x03 }, // 011 VR1
{ 6, 0x03 }, // 000011 VR2
{ 7, 0x03 }, // 0000011 VR3
};
// Code table for white runs
static const CODETABLE WhiteRunCodes[] = {
{ 8, 0x35 }, // 00110101 0
{ 6, 0x07 }, // 000111 1
{ 4, 0x07 }, // 0111 2
{ 4, 0x08 }, // 1000 3
{ 4, 0x0b }, // 1011 4
{ 4, 0x0c }, // 1100 5
{ 4, 0x0e }, // 1110 6
{ 4, 0x0f }, // 1111 7
{ 5, 0x13 }, // 10011 8
{ 5, 0x14 }, // 10100 9
{ 5, 0x07 }, // 00111 10
{ 5, 0x08 }, // 01000 11
{ 6, 0x08 }, // 001000 12
{ 6, 0x03 }, // 000011 13
{ 6, 0x34 }, // 110100 14
{ 6, 0x35 }, // 110101 15
{ 6, 0x2a }, // 101010 16
{ 6, 0x2b }, // 101011 17
{ 7, 0x27 }, // 0100111 18
{ 7, 0x0c }, // 0001100 19
{ 7, 0x08 }, // 0001000 20
{ 7, 0x17 }, // 0010111 21
{ 7, 0x03 }, // 0000011 22
{ 7, 0x04 }, // 0000100 23
{ 7, 0x28 }, // 0101000 24
{ 7, 0x2b }, // 0101011 25
{ 7, 0x13 }, // 0010011 26
{ 7, 0x24 }, // 0100100 27
{ 7, 0x18 }, // 0011000 28
{ 8, 0x02 }, // 00000010 29
{ 8, 0x03 }, // 00000011 30
{ 8, 0x1a }, // 00011010 31
{ 8, 0x1b }, // 00011011 32
{ 8, 0x12 }, // 00010010 33
{ 8, 0x13 }, // 00010011 34
{ 8, 0x14 }, // 00010100 35
{ 8, 0x15 }, // 00010101 36
{ 8, 0x16 }, // 00010110 37
{ 8, 0x17 }, // 00010111 38
{ 8, 0x28 }, // 00101000 39
{ 8, 0x29 }, // 00101001 40
{ 8, 0x2a }, // 00101010 41
{ 8, 0x2b }, // 00101011 42
{ 8, 0x2c }, // 00101100 43
{ 8, 0x2d }, // 00101101 44
{ 8, 0x04 }, // 00000100 45
{ 8, 0x05 }, // 00000101 46
{ 8, 0x0a }, // 00001010 47
{ 8, 0x0b }, // 00001011 48
{ 8, 0x52 }, // 01010010 49
{ 8, 0x53 }, // 01010011 50
{ 8, 0x54 }, // 01010100 51
{ 8, 0x55 }, // 01010101 52
{ 8, 0x24 }, // 00100100 53
{ 8, 0x25 }, // 00100101 54
{ 8, 0x58 }, // 01011000 55
{ 8, 0x59 }, // 01011001 56
{ 8, 0x5a }, // 01011010 57
{ 8, 0x5b }, // 01011011 58
{ 8, 0x4a }, // 01001010 59
{ 8, 0x4b }, // 01001011 60
{ 8, 0x32 }, // 00110010 61
{ 8, 0x33 }, // 00110011 62
{ 8, 0x34 }, // 00110100 63
{ 5, 0x1b }, // 11011 64
{ 5, 0x12 }, // 10010 128
{ 6, 0x17 }, // 010111 192
{ 7, 0x37 }, // 0110111 256
{ 8, 0x36 }, // 00110110 320
{ 8, 0x37 }, // 00110111 384
{ 8, 0x64 }, // 01100100 448
{ 8, 0x65 }, // 01100101 512
{ 8, 0x68 }, // 01101000 576
{ 8, 0x67 }, // 01100111 640
{ 9, 0xcc }, // 011001100 704
{ 9, 0xcd }, // 011001101 768
{ 9, 0xd2 }, // 011010010 832
{ 9, 0xd3 }, // 011010011 896
{ 9, 0xd4 }, // 011010100 960
{ 9, 0xd5 }, // 011010101 1024
{ 9, 0xd6 }, // 011010110 1088
{ 9, 0xd7 }, // 011010111 1152
{ 9, 0xd8 }, // 011011000 1216
{ 9, 0xd9 }, // 011011001 1280
{ 9, 0xda }, // 011011010 1344
{ 9, 0xdb }, // 011011011 1408
{ 9, 0x98 }, // 010011000 1472
{ 9, 0x99 }, // 010011001 1536
{ 9, 0x9a }, // 010011010 1600
{ 6, 0x18 }, // 011000 1664
{ 9, 0x9b }, // 010011011 1728
{ 11, 0x08 }, // 00000001000 1792
{ 11, 0x0c }, // 00000001100 1856
{ 11, 0x0d }, // 00000001101 1920
{ 12, 0x12 }, // 000000010010 1984
{ 12, 0x13 }, // 000000010011 2048
{ 12, 0x14 }, // 000000010100 2112
{ 12, 0x15 }, // 000000010101 2176
{ 12, 0x16 }, // 000000010110 2240
{ 12, 0x17 }, // 000000010111 2304
{ 12, 0x1c }, // 000000011100 2368
{ 12, 0x1d }, // 000000011101 2432
{ 12, 0x1e }, // 000000011110 2496
{ 12, 0x1f }, // 000000011111 2560
};
// Code table for black runs
static const CODETABLE BlackRunCodes[] = {
{ 10, 0x37 }, // 0000110111 0
{ 3, 0x02 }, // 010 1
{ 2, 0x03 }, // 11 2
{ 2, 0x02 }, // 10 3
{ 3, 0x03 }, // 011 4
{ 4, 0x03 }, // 0011 5
{ 4, 0x02 }, // 0010 6
{ 5, 0x03 }, // 00011 7
{ 6, 0x05 }, // 000101 8
{ 6, 0x04 }, // 000100 9
{ 7, 0x04 }, // 0000100 10
{ 7, 0x05 }, // 0000101 11
{ 7, 0x07 }, // 0000111 12
{ 8, 0x04 }, // 00000100 13
{ 8, 0x07 }, // 00000111 14
{ 9, 0x18 }, // 000011000 15
{ 10, 0x17 }, // 0000010111 16
{ 10, 0x18 }, // 0000011000 17
{ 10, 0x08 }, // 0000001000 18
{ 11, 0x67 }, // 00001100111 19
{ 11, 0x68 }, // 00001101000 20
{ 11, 0x6c }, // 00001101100 21
{ 11, 0x37 }, // 00000110111 22
{ 11, 0x28 }, // 00000101000 23
{ 11, 0x17 }, // 00000010111 24
{ 11, 0x18 }, // 00000011000 25
{ 12, 0xca }, // 000011001010 26
{ 12, 0xcb }, // 000011001011 27
{ 12, 0xcc }, // 000011001100 28
{ 12, 0xcd }, // 000011001101 29
{ 12, 0x68 }, // 000001101000 30
{ 12, 0x69 }, // 000001101001 31
{ 12, 0x6a }, // 000001101010 32
{ 12, 0x6b }, // 000001101011 33
{ 12, 0xd2 }, // 000011010010 34
{ 12, 0xd3 }, // 000011010011 35
{ 12, 0xd4 }, // 000011010100 36
{ 12, 0xd5 }, // 000011010101 37
{ 12, 0xd6 }, // 000011010110 38
{ 12, 0xd7 }, // 000011010111 39
{ 12, 0x6c }, // 000001101100 40
{ 12, 0x6d }, // 000001101101 41
{ 12, 0xda }, // 000011011010 42
{ 12, 0xdb }, // 000011011011 43
{ 12, 0x54 }, // 000001010100 44
{ 12, 0x55 }, // 000001010101 45
{ 12, 0x56 }, // 000001010110 46
{ 12, 0x57 }, // 000001010111 47
{ 12, 0x64 }, // 000001100100 48
{ 12, 0x65 }, // 000001100101 49
{ 12, 0x52 }, // 000001010010 50
{ 12, 0x53 }, // 000001010011 51
{ 12, 0x24 }, // 000000100100 52
{ 12, 0x37 }, // 000000110111 53
{ 12, 0x38 }, // 000000111000 54
{ 12, 0x27 }, // 000000100111 55
{ 12, 0x28 }, // 000000101000 56
{ 12, 0x58 }, // 000001011000 57
{ 12, 0x59 }, // 000001011001 58
{ 12, 0x2b }, // 000000101011 59
{ 12, 0x2c }, // 000000101100 60
{ 12, 0x5a }, // 000001011010 61
{ 12, 0x66 }, // 000001100110 62
{ 12, 0x67 }, // 000001100111 63
{ 10, 0x0f }, // 0000001111 64
{ 12, 0xc8 }, // 000011001000 128
{ 12, 0xc9 }, // 000011001001 192
{ 12, 0x5b }, // 000001011011 256
{ 12, 0x33 }, // 000000110011 320
{ 12, 0x34 }, // 000000110100 384
{ 12, 0x35 }, // 000000110101 448
{ 13, 0x6c }, // 0000001101100 512
{ 13, 0x6d }, // 0000001101101 576
{ 13, 0x4a }, // 0000001001010 640
{ 13, 0x4b }, // 0000001001011 704
{ 13, 0x4c }, // 0000001001100 768
{ 13, 0x4d }, // 0000001001101 832
{ 13, 0x72 }, // 0000001110010 896
{ 13, 0x73 }, // 0000001110011 960
{ 13, 0x74 }, // 0000001110100 1024
{ 13, 0x75 }, // 0000001110101 1088
{ 13, 0x76 }, // 0000001110110 1152
{ 13, 0x77 }, // 0000001110111 1216
{ 13, 0x52 }, // 0000001010010 1280
{ 13, 0x53 }, // 0000001010011 1344
{ 13, 0x54 }, // 0000001010100 1408
{ 13, 0x55 }, // 0000001010101 1472
{ 13, 0x5a }, // 0000001011010 1536
{ 13, 0x5b }, // 0000001011011 1600
{ 13, 0x64 }, // 0000001100100 1664
{ 13, 0x65 }, // 0000001100101 1728
{ 11, 0x08 }, // 00000001000 1792
{ 11, 0x0c }, // 00000001100 1856
{ 11, 0x0d }, // 00000001101 1920
{ 12, 0x12 }, // 000000010010 1984
{ 12, 0x13 }, // 000000010011 2048
{ 12, 0x14 }, // 000000010100 2112
{ 12, 0x15 }, // 000000010101 2176
{ 12, 0x16 }, // 000000010110 2240
{ 12, 0x17 }, // 000000010111 2304
{ 12, 0x1c }, // 000000011100 2368
{ 12, 0x1d }, // 000000011101 2432
{ 12, 0x1e }, // 000000011110 2496
{ 12, 0x1f }, // 000000011111 2560
};
UINT32 tiffData;
int tiffDataBits;
void
OutputRun(
int run,
PCODETABLE pCodeTable
)
{
PCODETABLE pTableEntry;
// Use make-up code word for 2560 for any runs of at least 2624 pixels
// This is currently not necessary for us since our scanlines always
// have 1728 pixels.
while (run >= 2624) {
pTableEntry = pCodeTable + (63 + (2560 >> 6));
OutputBits(pTableEntry->length, pTableEntry->code);
run -= 2560;
}
// Use appropriate make-up code word if the run is longer than 63 pixels
if (run >= 64) {
pTableEntry = pCodeTable + (63 + (run >> 6));
OutputBits(pTableEntry->length, pTableEntry->code);
run &= 0x3f;
}
// Output terminating code word
OutputBits(pCodeTable[run].length, pCodeTable[run].code);
}
int
FindWhiteRun(
UINT8* buf,
int startBit,
int stopBit
)
{
static const UINT8 WhiteRuns[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int run, bits, n;
buf += (startBit >> 3);
if ((bits = stopBit-startBit) <= 0)
return 0;
// Take care of the case where starting bit index is not a multiple of 8
if (n = (startBit & 7)) {
run = WhiteRuns[(*buf << n) & 0xff];
if (run > 8-n)
run = 8-n;
if (n+run < 8)
return run;
bits -= run;
buf++;
} else
run = 0;
// Look for consecutive UINT32 value = 0
if (bits >= 32 * 2) {
UINT32* pdw;
// Align to a UINT32 boundary first
while ((int) buf & 3) {
if (*buf != 0)
return run + WhiteRuns[*buf];
run += 8;
bits -= 8;
buf++;
}
pdw = (UINT32*) buf;
while (bits >= 32 && *pdw == 0) {
pdw++;
run += 32;
bits -= 32;
}
buf = (UINT8*) pdw;
}
// Look for consecutive UINT8 value = 0
while (bits >= 8) {
if (*buf != 0)
return run + WhiteRuns[*buf];
buf++;
run += 8;
bits -= 8;
}
// Count the number of white pixels in the last byte
if (bits > 0)
run += WhiteRuns[*buf];
return run;
}
int
FindBlackRun(
UINT8* buf,
int startBit,
int stopBit
)
{
static const UINT8 BlackRuns[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8
};
int run, bits, n;
buf += (startBit >> 3);
if ((bits = stopBit-startBit) <= 0)
return 0;
// Take care of the case where starting bit index is not a multiple of 8
if (n = (startBit & 7)) {
run = BlackRuns[(*buf << n) & 0xff];
if (run > 8-n)
run = 8-n;
if (n+run < 8)
return run;
bits -= run;
buf++;
} else
run = 0;
// Look for consecutive UINT32 value = 0xffffffff
if (bits >= 32 * 2) {
UINT32* pdw;
// Align to a UINT32 boundary first
while ((int) buf & 3) {
if (*buf != 0xff)
return run + BlackRuns[*buf];
run += 8;
bits -= 8;
buf++;
}
pdw = (UINT32*) buf;
while (bits >= 32 && *pdw == 0xffffffff) {
pdw++;
run += 32;
bits -= 32;
}
buf = (UINT8*) pdw;
}
// Look for consecutive UINT8 value = 0xff
while (bits >= 8) {
if (*buf != 0xff)
return run + BlackRuns[*buf];
buf++;
run += 8;
bits -= 8;
}
// Count the number of white pixels in the last byte
if (bits > 0)
run += BlackRuns[*buf];
return run;
}
void
init_tiff_encoder(
void
)
{
tiffData = 0;
tiffDataBits = 32;
}
void
cleanup_tiff_encoder(
void
)
{
// Output EOB (two EOLs) after the last scanline
OutputBits(EOL_LENGTH, EOL_CODE);
OutputBits(EOL_LENGTH, EOL_CODE);
while (tiffDataBits < 32)
{
tiffDataBits += 8;
OutputByte(tiffData >> 24);
tiffData <<= 8;
}
tiffData = 0;
tiffDataBits = 32;
}
void
compress_tiff_line(
UINT8* cur_line,
UINT8* ref_line,
int lineWidth
)
{
int a0, a1, a2, b1, b2, distance;
// Use 2-dimensional encoding scheme
a0 = 0;
a1 = GetBit(cur_line, 0) ? 0 : NextChangingElement(cur_line, 0, lineWidth, 0);
b1 = GetBit(ref_line, 0) ? 0 : NextChangingElement(ref_line, 0, lineWidth, 0);
while (1) {
b2 = (b1 >= lineWidth) ?
lineWidth :
NextChangingElement(ref_line, b1, lineWidth, GetBit(ref_line, b1));
if (b2 < a1) {
// Pass mode
OutputBits(PASSCODE_LENGTH, PASSCODE);
a0 = b2;
} else if ((distance = a1 - b1) <= 3 && distance >= -3) {
// Vertical mode
OutputBits(VertCodes[distance+3].length, VertCodes[distance+3].code);
a0 = a1;
} else {
// Horizontal mode
a2 = (a1 >= lineWidth) ?
lineWidth :
NextChangingElement(cur_line, a1, lineWidth, GetBit(cur_line, a1));
OutputBits(HORZCODE_LENGTH, HORZCODE);
if (a1 != 0 && GetBit(cur_line, a0)) {
OutputRun(a1-a0, BlackRunCodes);
OutputRun(a2-a1, WhiteRunCodes);
} else {
OutputRun(a1-a0, WhiteRunCodes);
OutputRun(a2-a1, BlackRunCodes);
}
a0 = a2;
}
if (a0 >= lineWidth)
break;
a1 = NextChangingElement(cur_line, a0, lineWidth, GetBit(cur_line, a0));
b1 = NextChangingElement(ref_line, a0, lineWidth, !GetBit(cur_line, a0));
b1 = NextChangingElement(ref_line, b1, lineWidth, GetBit(cur_line, a0));
}
}