windows-nt/Source/XPSP1/NT/printscan/fax/print/faxprint/faxdrv/faxtiff.c

1475 lines
31 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
faxtiff.c
Abstract:
Functions to compress the bitmap bits using CCITT Group3 2-dimensional coding
and output the resulting data as TIFF-F file.
Environment:
Windows NT fax driver, kernel mode
Revision History:
01/23/96 -davidx-
Created it.
mm/dd/yy -author-
description
NOTE:
Please refer to faxtiff.h for a description of
the structure of our TIFF output file.
--*/
#include "faxdrv.h"
#include "faxtiff.h"
#include "faxtable.h"
BOOL
WriteData(
PDEVDATA pdev,
PVOID pbuf,
DWORD cbbuf
)
/*++
Routine Description:
Output a buffer of data to the spooler
Arguments:
pdev - Points to our DEVDATA structure
pbuf - Points to data buffer
cbbuf - Number of bytes in the buffer
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{
DWORD cbwritten;
//
// Stop if the document has been cancelled.
//
if (pdev->flags & PDEV_CANCELLED)
return FALSE;
//
// Send output to spooler directly
//
if (! WritePrinter(pdev->hPrinter, pbuf, cbbuf, &cbwritten) || cbbuf != cbwritten) {
Error(("WritePrinter failed\n"));
pdev->flags |= PDEV_CANCELLED;
return FALSE;
}
pdev->fileOffset += cbbuf;
return TRUE;
}
PDWORD
CalcXposeMatrix(
VOID
)
/*++
Routine Description:
Generate the transpose matrix for rotating landscape bitmaps
Arguments:
NONE
Return Value:
Pointer to the generated transpose matrix
NULL if there is an error
--*/
{
static DWORD templateData[16] = {
/* 0000 */ 0x00000000,
/* 0001 */ 0x00000001,
/* 0010 */ 0x00000100,
/* 0011 */ 0x00000101,
/* 0100 */ 0x00010000,
/* 0101 */ 0x00010001,
/* 0110 */ 0x00010100,
/* 0111 */ 0x00010101,
/* 1000 */ 0x01000000,
/* 1001 */ 0x01000001,
/* 1010 */ 0x01000100,
/* 1011 */ 0x01000101,
/* 1100 */ 0x01010000,
/* 1101 */ 0x01010001,
/* 1110 */ 0x01010100,
/* 1111 */ 0x01010101
};
PDWORD pdwXpose, pTemp;
INT index;
//
// First check if the transpose matrix has been generated already
//
if (pdwXpose = MemAlloc(sizeof(DWORD) * 2 * (1 << BYTEBITS))) {
for (index=0, pTemp=pdwXpose; index < (1 << BYTEBITS); index++, pTemp++) {
pTemp[0] = templateData[index >> 4];
pTemp[1 << BYTEBITS] = templateData[index & 0xf];
}
}
return pdwXpose;
}
BOOL
OutputPageBitmap(
PDEVDATA pdev,
PBYTE pBitmapData
)
/*++
Routine Description:
Output a completed page bitmap to the spooler
Arguments:
pdev - Points to our DEVDATA structure
pBitmapData - Points to bitmap data
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
LONG bmpWidth, bmpHeight;
BOOL result;
DWORD compressedBytes;
Verbose(("Sending page %d...\n", pdev->pageCount));
Assert(pdev->pCompBits == NULL);
//
// For portrait output, encode the entire bitmap in one shot
// For landscape output, we need to rotate the bitmap here:
// Generate the transpose matrix and allocate a
// temporary buffer large enough to hold 8 scanlines
//
if (IsLandscapeMode(pdev)) {
bmpWidth = pdev->imageSize.cy;
bmpHeight = pdev->imageSize.cx;
} else {
bmpWidth = pdev->imageSize.cx;
bmpHeight = pdev->imageSize.cy;
}
//
// Initialize fax encodier
//
if (! InitFaxEncoder(pdev, bmpWidth, bmpHeight))
return FALSE;
if (! IsLandscapeMode(pdev)) {
LONG dwordCount;
PDWORD pBits;
//
// Invert the entire page bitmap in memory
//
Assert(bmpWidth % DWORDBITS == 0);
dwordCount = (bmpWidth * bmpHeight) / DWORDBITS;
pBits = (PDWORD) pBitmapData;
while (dwordCount--)
*pBits++ ^= 0xffffffff;
//
// Compress the page bitmap
//
result = EncodeFaxData(pdev, pBitmapData, bmpWidth, bmpHeight);
//
// Restore the original page bitmap
//
dwordCount = (bmpWidth * bmpHeight) / DWORDBITS;
pBits = (PDWORD) pBitmapData;
while (dwordCount--)
*pBits++ ^= 0xffffffff;
if (! result) {
FreeCompBitsBuffer(pdev);
return FALSE;
}
} else {
register PDWORD pdwXposeHigh, pdwXposeLow;
register DWORD dwHigh, dwLow;
PBYTE pBuffer, pbCol;
LONG deltaNew;
//
// Calculate the transpose matrix for fast bitmap rotation
//
if (!(pdwXposeHigh = CalcXposeMatrix()) || !(pBuffer = MemAllocZ(bmpWidth))) {
MemFree(pdwXposeHigh);
FreeCompBitsBuffer(pdev);
return FALSE;
}
pdwXposeLow = pdwXposeHigh + (1 << BYTEBITS);
//
// During each iteration thru the following loop, we will process
// one byte column and generate 8 rotated scanlines.
//
Assert(bmpHeight % BYTEBITS == 0);
Assert(bmpWidth % DWORDBITS == 0);
deltaNew = bmpWidth / BYTEBITS;
pbCol = pBitmapData + (bmpHeight / BYTEBITS - 1);
do {
PBYTE pbWrite = pBuffer;
PBYTE pbTemp = pbCol;
LONG loopCount = deltaNew;
while (loopCount--) {
//
// Rotate the next 8 bytes in the current column
// Unroll the loop here in hopes of faster execution
//
dwHigh = pdwXposeHigh[*pbTemp];
dwLow = pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
dwHigh = (dwHigh << 1) | pdwXposeHigh[*pbTemp];
dwLow = (dwLow << 1) | pdwXposeLow[*pbTemp];
pbTemp += pdev->lineOffset;
//
// Invert black and white pixel polarity
//
dwHigh ^= 0xffffffff;
dwLow ^= 0xffffffff;
//
// Distribute the resulting byte to 8 separate scanlines
//
*pbWrite = (BYTE) dwLow;
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwLow >> BYTEBITS);
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwLow >> BYTEBITS*2);
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwLow >> BYTEBITS*3);
pbWrite += deltaNew;
*pbWrite = (BYTE) dwHigh;
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwHigh >> BYTEBITS);
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwHigh >> BYTEBITS*2);
pbWrite += deltaNew;
*pbWrite = (BYTE) (dwHigh >> BYTEBITS*3);
pbWrite -= (deltaNew * BYTEBITS - deltaNew - 1);
}
//
// Encode the next band of scanlines
//
if (! EncodeFaxData(pdev, pBuffer, bmpWidth, BYTEBITS)) {
MemFree(pdwXposeHigh);
MemFree(pBuffer);
FreeCompBitsBuffer(pdev);
return FALSE;
}
} while (pbCol-- != pBitmapData);
MemFree(pdwXposeHigh);
MemFree(pBuffer);
}
//
// Output EOB (two EOLs) after the last scanline
// and make sure the compressed data is WORD aligned
//
OutputBits(pdev, EOL_LENGTH, EOL_CODE);
OutputBits(pdev, EOL_LENGTH, EOL_CODE);
FlushBits(pdev);
if ((compressedBytes = (DWORD)(pdev->pCompBufPtr - pdev->pCompBits)) & 1) {
*pdev->pCompBufPtr++ = 0;
compressedBytes++;
}
//
// Output the IFD for the previous page and generate the IFD for the current page
// Output the compressed bitmap data
//
result = WriteTiffIFD(pdev, bmpWidth, bmpHeight, compressedBytes) &&
WriteTiffBits(pdev, pdev->pCompBits, compressedBytes);
FreeCompBitsBuffer(pdev);
return result;
}
INT
FindWhiteRun(
PBYTE pbuf,
INT startBit,
INT stopBit
)
/*++
Routine Description:
Find the next span of white pixels on the specified line
Arguments:
pbuf - Points to uncompressed pixel data for the current line
startBit - Starting bit index
stopBit - Last bit index
Return Value:
Length of the next run of white pixels
--*/
{
static const BYTE 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;
pbuf += (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[(*pbuf << n) & 0xff];
if (run > BYTEBITS-n)
run = BYTEBITS-n;
if (n+run < BYTEBITS)
return run;
bits -= run;
pbuf++;
} else
run = 0;
//
// Look for consecutive DWORD value = 0
//
if (bits >= DWORDBITS * 2) {
PDWORD pdw;
//
// Align to a DWORD boundary first
//
while ((ULONG_PTR) pbuf & 3) {
if (*pbuf != 0)
return run + WhiteRuns[*pbuf];
run += BYTEBITS;
bits -= BYTEBITS;
pbuf++;
}
pdw = (PDWORD) pbuf;
while (bits >= DWORDBITS && *pdw == 0) {
pdw++;
run += DWORDBITS;
bits -= DWORDBITS;
}
pbuf = (PBYTE) pdw;
}
//
// Look for consecutive BYTE value = 0
//
while (bits >= BYTEBITS) {
if (*pbuf != 0)
return run + WhiteRuns[*pbuf];
pbuf++;
run += BYTEBITS;
bits -= BYTEBITS;
}
//
// Count the number of white pixels in the last byte
//
if (bits > 0)
run += WhiteRuns[*pbuf];
return run;
}
INT
FindBlackRun(
PBYTE pbuf,
INT startBit,
INT stopBit
)
/*++
Routine Description:
Find the next span of black pixels on the specified line
Arguments:
pbuf - Points to uncompressed pixel data for the current line
startBit - Starting bit index
stopBit - Last bit index
Return Value:
Length of the next run of black pixels
--*/
{
static const BYTE 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;
pbuf += (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[(*pbuf << n) & 0xff];
if (run > BYTEBITS-n)
run = BYTEBITS-n;
if (n+run < BYTEBITS)
return run;
bits -= run;
pbuf++;
} else
run = 0;
//
// Look for consecutive DWORD value = 0xffffffff
//
if (bits >= DWORDBITS * 2) {
PDWORD pdw;
//
// Align to a DWORD boundary first
//
while ((ULONG_PTR) pbuf & 3) {
if (*pbuf != 0xff)
return run + BlackRuns[*pbuf];
run += BYTEBITS;
bits -= BYTEBITS;
pbuf++;
}
pdw = (PDWORD) pbuf;
while (bits >= DWORDBITS && *pdw == 0xffffffff) {
pdw++;
run += DWORDBITS;
bits -= DWORDBITS;
}
pbuf = (PBYTE) pdw;
}
//
// Look for consecutive BYTE value = 0xff
//
while (bits >= BYTEBITS) {
if (*pbuf != 0xff)
return run + BlackRuns[*pbuf];
pbuf++;
run += BYTEBITS;
bits -= BYTEBITS;
}
//
// Count the number of white pixels in the last byte
//
if (bits > 0)
run += BlackRuns[*pbuf];
return run;
}
VOID
OutputRun(
PDEVDATA pdev,
INT run,
PCODETABLE pCodeTable
)
/*++
Routine Description:
Output a single run (black or white) using the specified code table
Arguments:
pdev - Points to our DEVDATA structure
run - Specifies the length of the run
pCodeTable - Specifies the code table to use
Return Value:
NONE
--*/
{
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(pdev, 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(pdev, pTableEntry->length, pTableEntry->code);
run &= 0x3f;
}
//
// Output terminating code word
//
OutputBits(pdev, pCodeTable[run].length, pCodeTable[run].code);
}
#ifdef USE1D
VOID
OutputEOL(
PDEVDATA pdev
)
/*++
Routine Description:
Output EOL code at the beginning of each scanline
Arguments:
pdev - Points to our DEVDATA structure
Return Value:
NONE
--*/
{
DWORD length, code;
//
// EOL code word always ends on a byte boundary
//
code = EOL_CODE;
length = EOL_LENGTH + ((pdev->bitcnt - EOL_LENGTH) & 7);
OutputBits(pdev, length, code);
}
BOOL
EncodeFaxData(
PDEVDATA pdev,
PBYTE plinebuf,
INT lineWidth,
INT lineCount
)
/*++
Routine Description:
Compress the specified number of scanlines
Arguments:
pdev - Points to our DEVDATA structure
plinebuf - Points to scanline data to be compressed
lineWidth - Scanline width in pixels
lineCount - Number of scanlines
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
INT delta = lineWidth / BYTEBITS;
INT bitIndex, run;
while (lineCount--) {
//
// Make sure the compressed bitmap buffer doesn't overflow
//
if ((pdev->pCompBufPtr >= pdev->pCompBufMark) && !GrowCompBitsBuffer(pdev, delta))
return FALSE;
//
// Output byte-aligned EOL code
//
OutputEOL(pdev);
//
// Use 1-dimensional encoding scheme
//
bitIndex = 0;
while (TRUE) {
//
// Code white run
//
run = FindWhiteRun(plinebuf, bitIndex, lineWidth);
OutputRun(pdev, run, WhiteRunCodes);
if ((bitIndex += run) >= lineWidth)
break;
//
// Code black run
//
run = FindBlackRun(plinebuf, bitIndex, lineWidth);
OutputRun(pdev, run, BlackRunCodes);
if ((bitIndex += run) >= lineWidth)
break;
}
//
// Move on to the next scanline
//
plinebuf += delta;
}
return TRUE;
}
#else //!USE1D
BOOL
EncodeFaxData(
PDEVDATA pdev,
PBYTE plinebuf,
INT lineWidth,
INT lineCount
)
/*++
Routine Description:
Compress the specified number of scanlines
Arguments:
pdev - Points to our DEVDATA structure
plinebuf - Points to scanline data to be compressed
lineWidth - Scanline width in pixels
lineCount - Number of scanlines
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
INT delta = lineWidth / BYTEBITS;
INT a0, a1, a2, b1, b2, distance;
PBYTE prefline = pdev->prefline;
Assert(lineWidth % BYTEBITS == 0);
while (lineCount--) {
//
// Make sure the compressed bitmap buffer doesn't overflow
//
if ((pdev->pCompBufPtr >= pdev->pCompBufMark) && !GrowCompBitsBuffer(pdev, delta))
return FALSE;
//
// Use 2-dimensional encoding scheme
//
a0 = 0;
a1 = GetBit(plinebuf, 0) ? 0 : NextChangingElement(plinebuf, 0, lineWidth, 0);
b1 = GetBit(prefline, 0) ? 0 : NextChangingElement(prefline, 0, lineWidth, 0);
while (TRUE) {
b2 = (b1 >= lineWidth) ? lineWidth :
NextChangingElement(prefline, b1, lineWidth, GetBit(prefline, b1));
if (b2 < a1) {
//
// Pass mode
//
OutputBits(pdev, PASSCODE_LENGTH, PASSCODE);
a0 = b2;
} else if ((distance = a1 - b1) <= 3 && distance >= -3) {
//
// Vertical mode
//
OutputBits(pdev, VertCodes[distance+3].length, VertCodes[distance+3].code);
a0 = a1;
} else {
//
// Horizontal mode
//
a2 = (a1 >= lineWidth) ? lineWidth :
NextChangingElement(plinebuf, a1, lineWidth, GetBit(plinebuf, a1));
OutputBits(pdev, HORZCODE_LENGTH, HORZCODE);
if (a1 != 0 && GetBit(plinebuf, a0)) {
OutputRun(pdev, a1-a0, BlackRunCodes);
OutputRun(pdev, a2-a1, WhiteRunCodes);
} else {
OutputRun(pdev, a1-a0, WhiteRunCodes);
OutputRun(pdev, a2-a1, BlackRunCodes);
}
a0 = a2;
}
if (a0 >= lineWidth)
break;
a1 = NextChangingElement(plinebuf, a0, lineWidth, GetBit(plinebuf, a0));
b1 = NextChangingElement(prefline, a0, lineWidth, !GetBit(plinebuf, a0));
b1 = NextChangingElement(prefline, b1, lineWidth, GetBit(plinebuf, a0));
}
//
// Move on to the next scanline
//
prefline = plinebuf;
plinebuf += delta;
}
//
// Remember the last line as a reference
//
CopyMemory(pdev->prefline, prefline, delta);
return TRUE;
}
#endif //!USE1D
//
// IFD entries we generate for each page
//
WORD FaxIFDTags[NUM_IFD_ENTRIES] = {
TIFFTAG_NEWSUBFILETYPE,
TIFFTAG_IMAGEWIDTH,
TIFFTAG_IMAGEHEIGHT,
TIFFTAG_BITSPERSAMPLE,
TIFFTAG_COMPRESSION,
TIFFTAG_PHOTOMETRIC,
TIFFTAG_FILLORDER,
TIFFTAG_STRIPOFFSETS,
TIFFTAG_SAMPLESPERPIXEL,
TIFFTAG_ROWSPERSTRIP,
TIFFTAG_STRIPBYTECOUNTS,
TIFFTAG_XRESOLUTION,
TIFFTAG_YRESOLUTION,
#ifdef USE1D
TIFFTAG_G3OPTIONS,
#else
TIFFTAG_G4OPTIONS,
#endif
TIFFTAG_RESUNIT,
TIFFTAG_PAGENUMBER,
TIFFTAG_SOFTWARE,
TIFFTAG_CLEANFAXDATA,
};
#define SoftwareStr "Windows NT Fax Driver"
static FAXIFD FaxIFDTemplate = {
0,
NUM_IFD_ENTRIES,
{
{ 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 },
#ifdef USE1D
{ TIFFTAG_COMPRESSION, TIFFTYPE_SHORT, 1, COMPRESSION_G3FAX },
#else
{ TIFFTAG_COMPRESSION, TIFFTYPE_SHORT, 1, COMPRESSION_G4FAX },
#endif
{ TIFFTAG_PHOTOMETRIC, TIFFTYPE_SHORT, 1, PHOTOMETRIC_WHITEIS0 },
#ifdef USELSB
{ TIFFTAG_FILLORDER, TIFFTYPE_SHORT, 1, FILLORDER_LSB },
#else
{ TIFFTAG_FILLORDER, TIFFTYPE_SHORT, 1, FILLORDER_MSB },
#endif
{ 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 },
#ifdef USE1D
{ TIFFTAG_G3OPTIONS, TIFFTYPE_LONG, 1, G3_ALIGNEOL },
#else
{ TIFFTAG_G4OPTIONS, TIFFTYPE_LONG, 1, 0 },
#endif
{ TIFFTAG_RESUNIT, TIFFTYPE_SHORT, 1, RESUNIT_INCH },
{ TIFFTAG_PAGENUMBER, TIFFTYPE_SHORT, 2, 0 },
{ TIFFTAG_SOFTWARE, TIFFTYPE_ASCII, sizeof(SoftwareStr)+1, 0 },
{ TIFFTAG_CLEANFAXDATA, TIFFTYPE_SHORT, 1, 0 },
},
0,
DRIVER_SIGNATURE,
TIFFF_RES_X,
1,
TIFFF_RES_Y,
1,
SoftwareStr
};
BOOL
OutputDocTrailer(
PDEVDATA pdev
)
/*++
Routine Description:
Output document trailer information to the spooler
Arguments:
pdev - Points to our DEVDATA structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAXIFD pFaxIFD = pdev->pFaxIFD;
if (pFaxIFD == NULL || pdev->pageCount == 0)
return TRUE;
//
// Output the IFD for the last page of the document
//
pFaxIFD->nextIFDOffset = pFaxIFD->filler = 0;
return WriteData(pdev, pFaxIFD, sizeof(FAXIFD));
}
BOOL
WriteTiffIFD(
PDEVDATA pdev,
LONG bmpWidth,
LONG bmpHeight,
DWORD compressedBytes
)
/*++
Routine Description:
Output the IFD for the previous page and generate the IFD for the current page
Arguments:
pdev - Points to our DEVDATA structure
bmpWidth, bmpHeight - Width and height of the bitmap image
compressedBytes - Size of compressed bitmap data
Return Value:
TRUE if successful, FALSE otherwise
NOTE:
Please refer to faxtiff.h for a description of
the structure of our TIFF output file.
--*/
{
PFAXIFD pFaxIFD = pdev->pFaxIFD;
ULONG_PTR offset;
BOOL result = TRUE;
//
// Create the IFD data structure if necessary
//
if (pFaxIFD == NULL) {
if (! (pFaxIFD = MemAlloc(sizeof(FAXIFD))))
return FALSE;
pdev->pFaxIFD = pFaxIFD;
memcpy(pFaxIFD, &FaxIFDTemplate, sizeof(FAXIFD));
#if DBG
for (offset=0; offset < NUM_IFD_ENTRIES; offset++) {
Assert(pFaxIFD->ifd[offset].tag == FaxIFDTags[offset]);
}
#endif
}
if (pdev->pageCount <= 1) {
//
// If this is the very first page, there is no previous IFD.
// Output the TIFF file header instead.
//
TIFFFILEHEADER *pTiffFileHeader;
pdev->fileOffset = 0;
if (pTiffFileHeader = MemAlloc(sizeof(TIFFFILEHEADER))) {
pTiffFileHeader->magic1 = TIFF_MAGIC1;
pTiffFileHeader->magic2 = TIFF_MAGIC2;
pTiffFileHeader->signature = DRIVER_SIGNATURE;
pTiffFileHeader->firstIFD = sizeof(TIFFFILEHEADER) +
compressedBytes +
offsetof(FAXIFD, wIFDEntries);
result = WriteData(pdev, pTiffFileHeader, sizeof(TIFFFILEHEADER));
MemFree(pTiffFileHeader);
} else {
Error(("Memory allocation failed\n"));
result = FALSE;
}
} else {
//
// Not the first page of the document
// Output the IFD for the previous page
//
pFaxIFD->nextIFDOffset = pdev->fileOffset + compressedBytes + sizeof(FAXIFD) +
offsetof(FAXIFD, wIFDEntries);
result = WriteData(pdev, pFaxIFD, sizeof(FAXIFD));
}
//
// Generate the IFD for the current page
//
offset = pdev->fileOffset;
pFaxIFD->ifd[IFD_PAGENUMBER].value = MAKELONG(pdev->pageCount-1, 0);
pFaxIFD->ifd[IFD_IMAGEWIDTH].value = bmpWidth;
pFaxIFD->ifd[IFD_IMAGEHEIGHT].value = bmpHeight;
pFaxIFD->ifd[IFD_ROWSPERSTRIP].value = bmpHeight;
pFaxIFD->ifd[IFD_STRIPBYTECOUNTS].value = compressedBytes;
pFaxIFD->ifd[IFD_STRIPOFFSETS].value = (ULONG)offset;
offset += compressedBytes;
pFaxIFD->ifd[IFD_XRESOLUTION].value = (ULONG)offset + offsetof(FAXIFD, xresNum);
pFaxIFD->ifd[IFD_YRESOLUTION].value = (ULONG)offset + offsetof(FAXIFD, yresNum);
pFaxIFD->ifd[IFD_SOFTWARE].value = (ULONG)offset + offsetof(FAXIFD, software);
pFaxIFD->yresNum = (pdev->dm.dmPublic.dmYResolution == FAXRES_VERTDRAFT) ?
TIFFF_RES_Y_DRAFT :
TIFFF_RES_Y;
return result;
}
BOOL
WriteTiffBits(
PDEVDATA pdev,
PBYTE pCompBits,
DWORD compressedBytes
)
/*++
Routine Description:
Output the compressed bitmap data to the spooler
Arguments:
pdev - Points to our DEVDATA structure
pCompBits - Points to a buffer containing compressed bitmap data
compressedBytes - Size of compressed bitmap data
Return Value:
TRUE if successful, FALSE if there is an error
--*/
#define OUTPUT_BUFFER_SIZE 4096
{
PBYTE pBuffer;
DWORD bytesToWrite;
#ifndef USERMODE_DRIVER
//
// Since we allocated the compressed bitmap data buffer from
// the user mode memory space, we couldn't passed it directly
// to EngWritePrinter.
//
// Here we allocate a temporary buffer from kernel mode memory
// space and output the compressed data one buffer at a time.
//
if (! (pBuffer = MemAlloc(OUTPUT_BUFFER_SIZE))) {
Error(("Memory allocation failed\n"));
return FALSE;
}
while (compressedBytes > 0) {
bytesToWrite = min(compressedBytes, OUTPUT_BUFFER_SIZE);
CopyMemory(pBuffer, pCompBits, bytesToWrite);
if (! WriteData(pdev, pBuffer, bytesToWrite)) {
MemFree(pBuffer);
return FALSE;
}
pCompBits += bytesToWrite;
compressedBytes -= bytesToWrite;
}
MemFree(pBuffer);
return TRUE;
#else
//
// just dump the data in OUTPUT_BUFFER_SIZE increments
//
pBuffer = pCompBits;
while (compressedBytes > 0) {
bytesToWrite = min(compressedBytes, OUTPUT_BUFFER_SIZE);
if (! WriteData(pdev, pBuffer, bytesToWrite) ) {
return FALSE;
}
pBuffer += bytesToWrite;
compressedBytes -= bytesToWrite;
}
return TRUE;
#endif
}
BOOL
GrowCompBitsBuffer(
PDEVDATA pdev,
LONG scanlineSize
)
/*++
Routine Description:
Enlarge the buffer for holding the compressed bitmap data
Arguments:
pdev - Points to our DEVDATA structure
scanlineSize - Number of uncompressed bytes per scanline
Return Value:
TRUE if successful, FALSE if memory allocation fails
--*/
{
DWORD oldBufferSize;
PBYTE pNewBuffer;
//
// Allocate a new buffer which is one increment larger than existing one
//
oldBufferSize = pdev->pCompBits ? pdev->compBufSize : 0;
pdev->compBufSize = oldBufferSize + pdev->compBufInc;
if (! (pNewBuffer = MemAlloc(pdev->compBufSize))) {
Error(("MemAlloc failed\n"));
FreeCompBitsBuffer(pdev);
return FALSE;
}
if (pdev->pCompBits) {
//
// Growing an existing buffer
//
Warning(("Growing compressed bitmap buffer: %d -> %d\n", oldBufferSize, pdev->compBufSize));
memcpy(pNewBuffer, pdev->pCompBits, oldBufferSize);
pdev->pCompBufPtr = pNewBuffer + (pdev->pCompBufPtr - pdev->pCompBits);
MemFree(pdev->pCompBits);
pdev->pCompBits = pNewBuffer;
} else {
//
// First time allocation
//
pdev->pCompBufPtr = pdev->pCompBits = pNewBuffer;
}
//
// Set a high-water mark to about 4 scanlines before the end of the buffer
//
pdev->pCompBufMark = pdev->pCompBits + (pdev->compBufSize - 4*scanlineSize);
return TRUE;
}
VOID
FreeCompBitsBuffer(
PDEVDATA pdev
)
/*++
Routine Description:
Free the buffer for holding the compressed bitmap data
Arguments:
pdev - Points to our DEVDATA structure
Return Value:
NONE
--*/
{
if (pdev->pCompBits) {
MemFree(pdev->prefline);
MemFree(pdev->pCompBits);
pdev->pCompBits = pdev->pCompBufPtr = NULL;
pdev->compBufSize = 0;
}
}
BOOL
InitFaxEncoder(
PDEVDATA pdev,
LONG bmpWidth,
LONG bmpHeight
)
/*++
Routine Description:
Initialize the fax encoder
Arguments:
pdev - Points to our DEVDATA structure
bmpWidth, bmpHeight - Width and height of the bitmap
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
//
// Calculate the increment in which to enlarge the compressed bits buffer:
// about 1/4 of the uncompressed bitmap buffer
//
bmpWidth /= BYTEBITS;
pdev->compBufInc = bmpWidth * bmpHeight / 4;
//
// Allocate the initial buffer
//
if (! (pdev->prefline = MemAllocZ(bmpWidth)) ||
! GrowCompBitsBuffer(pdev, bmpWidth))
{
MemFree(pdev->prefline);
return FALSE;
}
//
// Perform other initialization of fax encoder
//
pdev->bitdata = 0;
pdev->bitcnt = DWORDBITS;
return TRUE;
}