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;
|
|||
|
}
|
|||
|
|