1475 lines
31 KiB
C
1475 lines
31 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|