Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

803 lines
19 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
encode.c
Abstract:
This file contains functions for encoding (compressing)
uncompressed 1 bit per pel data into a TIFF data
stream. The supported compression algorithms are
as follows:
o Uncompressed (raw)
o One dimensional - MH or Modified Huffman
o Two dimensional - MR or Modified Read
Environment:
WIN32 User Mode
Author:
Wesley Witt (wesw) 17-Feb-1996
--*/
#include "tifflibp.h"
#pragma hdrstop
#if TIFFDBG
VOID
PrintRunInfo(
INT Mode,
INT Run,
INT BitLen,
WORD Code
)
/*++
Routine Description:
Prints run information to standard out. This
function is available only if TIFFDBG is TRUE.
Arguments:
Mode - Encoding mode: vertical, horizontal, pass, or raw
Run - Run length
BitLen - Number of bits
Code - The actual bits
Return Value:
None.
--*/
{
TCHAR BitBuf[16];
INT i;
WORD j;
_tprintf( TEXT("\t") );
if (Mode) {
switch( Mode ) {
case 1:
_tprintf( TEXT("pass mode ") );
break;
case 2:
_tprintf( TEXT("vertical mode run=%d, "), Run );
break;
case 3:
_tprintf( TEXT("horizontal mode ") );
break;
}
} else {
_tprintf( TEXT("run=%d, bitlen=%d, "), Run, BitLen );
}
j = Code << (16 - BitLen);
for (i=0; i<BitLen; i++,j<<=1) {
if (j & 0x8000) {
BitBuf[i] = TEXT('1');
} else {
BitBuf[i] = TEXT('0');
}
}
BitBuf[i] = 0;
_tprintf( TEXT("value=%04x, bits=%s\n"), Code << (16 - BitLen), BitBuf );
}
#endif
VOID
OutputEOL(
PTIFF_INSTANCE_DATA TiffInstance,
BOOL OneDimensional
)
/*++
Routine Description:
Output EOL code at the beginning of each scanline
Arguments:
TiffInstance - Pointer to the TIFF instance data
OneDimensional - TRUE for MH encoding
Return Value:
None.
--*/
{
DWORD length, code;
//
// EOL code word always ends on a byte boundary
//
code = EOL_CODE;
length = EOL_LENGTH + ((TiffInstance->bitcnt - EOL_LENGTH) & 7);
OutputBits( TiffInstance, (WORD) length, (WORD) code );
//
// When using MR encoding, append a 1 or 0 depending whether
// we're the line should be MH or MR encoded.
//
if (TiffInstance->CompressionType == TIFF_COMPRESSION_MR) {
OutputBits( TiffInstance, (WORD) 1, (WORD) (OneDimensional ? 1 : 0) );
}
}
VOID
OutputRun(
PTIFF_INSTANCE_DATA TiffInstance,
INT run,
PCODETABLE pCodeTable
)
/*++
Routine Description:
Output a single run (black or white) using the specified code table
Arguments:
TiffInstance - Pointer to the TIFF instance data
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( TiffInstance, pTableEntry->length, pTableEntry->code );
#if TIFFDBG
PrintRunInfo( 0, run, pTableEntry->length, pTableEntry->code );
#endif
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( TiffInstance, pTableEntry->length, pTableEntry->code );
#if TIFFDBG
PrintRunInfo( 0, run, pTableEntry->length, pTableEntry->code );
#endif
run &= 0x3f;
}
//
// Output terminating code word
//
OutputBits( TiffInstance, pCodeTable[run].length, pCodeTable[run].code );
#if TIFFDBG
PrintRunInfo( 0, run, pCodeTable[run].length, pCodeTable[run].code );
#endif
}
BOOL
EncodeFaxDataNoCompression(
PTIFF_INSTANCE_DATA TiffInstance,
PBYTE plinebuf,
INT lineWidth
)
/*++
Routine Description:
Encodes a single line of TIFF data using no compression.
This is basically raw data.
Arguments:
TiffInstance - Pointer to the TIFF instance data
plinebuf - Pointer to the input data
lineWidth - Width of the line in pixels
Return Value:
TRUE for success, FALSE for failure
--*/
{
DWORD Bytes;
#if TIFFDBG
_tprintf( TEXT("encoding(raw) line #%d\n"), TiffInstance->Lines );
#endif
WriteFile(
TiffInstance->hFile,
plinebuf,
lineWidth / 8,
&Bytes,
NULL
);
TiffInstance->Bytes += Bytes;
return TRUE;
}
BOOL
EncodeFaxDataMhCompression(
PTIFF_INSTANCE_DATA TiffInstance,
PBYTE plinebuf,
INT lineWidth
)
/*++
Routine Description:
Encodes a single line of TIFF data using 1 dimensional
TIFF compression.
Arguments:
TiffInstance - Pointer to the TIFF instance data
plinebuf - Pointer to the input data
lineWidth - Width of the line in pixels
Return Value:
TRUE for success, FALSE for failure
--*/
{
INT bitIndex, run, runLength;
#if TIFFDBG
_tprintf( TEXT("encoding line #%d\n"), TiffInstance->Lines );
#endif
bitIndex = 0;
runLength = 0;
OutputEOL( TiffInstance, TRUE );
while (TRUE) {
//
// Code white run
//
run = FindWhiteRun( plinebuf, bitIndex, lineWidth );
runLength += run;
OutputRun( TiffInstance, run, WhiteRunCodes );
if ((bitIndex += run) >= lineWidth)
break;
//
// Code black run
//
run = FindBlackRun(plinebuf, bitIndex, lineWidth);
runLength += run;
OutputRun( TiffInstance, run, BlackRunCodes );
if ((bitIndex += run) >= lineWidth)
break;
}
CopyMemory( TiffInstance->RefLine, plinebuf, lineWidth/8 );
return TRUE;
}
BOOL
EncodeFaxDataMmrCompression(
PTIFF_INSTANCE_DATA TiffInstance,
PBYTE plinebuf,
INT lineWidth
)
/*++
Routine Description:
Encodes a single line of TIFF data using 2 dimensional
TIFF compression.
Arguments:
TiffInstance - Pointer to the TIFF instance data
plinebuf - Pointer to the input data
lineWidth - Width of the line in pixels
Return Value:
TRUE for success, FALSE for failure
--*/
{
INT a0, a1, a2, b1, b2, distance;
LPBYTE prefline;
#if TIFFDBG
_tprintf( TEXT("encoding line #%d\n"), TiffInstance->Lines );
#endif
OutputEOL( TiffInstance, FALSE );
//
// Use 2-dimensional encoding scheme
//
prefline = TiffInstance->RefLine;
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( TiffInstance, PASSCODE_LENGTH, PASSCODE );
#if TIFFDBG
PrintRunInfo( 1, 0, PASSCODE_LENGTH, PASSCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = b2;
} else if ((distance = a1 - b1) <= 3 && distance >= -3) {
//
// Vertical mode
//
OutputBits( TiffInstance, VertCodes[distance+3].length, VertCodes[distance+3].code );
#if TIFFDBG
PrintRunInfo( 2, a1-a0, VertCodes[distance+3].length, VertCodes[distance+3].code );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = a1;
} else {
//
// Horizontal mode
//
a2 = (a1 >= lineWidth) ? lineWidth :
NextChangingElement( plinebuf, a1, lineWidth, GetBit( plinebuf, a1 ) );
OutputBits( TiffInstance, HORZCODE_LENGTH, HORZCODE );
#if TIFFDBG
PrintRunInfo( 3, 0, HORZCODE_LENGTH, HORZCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
if (a1 != 0 && GetBit( plinebuf, a0 )) {
OutputRun( TiffInstance, a1-a0, BlackRunCodes );
OutputRun( TiffInstance, a2-a1, WhiteRunCodes );
} else {
OutputRun( TiffInstance, a1-a0, WhiteRunCodes );
OutputRun( TiffInstance, 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 ) );
}
CopyMemory( TiffInstance->RefLine, plinebuf, TiffInstance->BytesPerLine );
return TRUE;
}
BOOL
EncodeFaxData(
PTIFF_INSTANCE_DATA TiffInstance,
PBYTE plinebuf,
INT lineWidth,
DWORD CompressionType
)
/*++
Routine Description:
Encodes a single line of TIFF data using the specified
compression method.
Arguments:
TiffInstance - Pointer to the TIFF instance data
plinebuf - Pointer to the input data
lineWidth - Width of the line in pixels
CompressionType - Requested compression method
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
switch( CompressionType ) {
case TIFF_COMPRESSION_NONE:
return EncodeFaxDataNoCompression( TiffInstance, plinebuf, lineWidth );
case TIFF_COMPRESSION_MH:
return EncodeFaxDataMhCompression( TiffInstance, plinebuf, lineWidth );
case TIFF_COMPRESSION_MR:
if (!TiffInstance->Lines) {
return EncodeFaxDataMhCompression( TiffInstance, plinebuf, lineWidth );
}
return EncodeFaxDataMmrCompression( TiffInstance, plinebuf, lineWidth );
}
return FALSE;
}
BOOL
EncodeFaxPageMmrCompression(
PTIFF_INSTANCE_DATA TiffInstance,
PBYTE plinebuf,
INT lineWidth,
DWORD ImageHeight,
DWORD *DestSize
)
/*++
Routine Description:
Encodes a page of TIFF data using 2 dimensional
TIFF compression.
Arguments:
TiffInstance - Pointer to the TIFF instance data
plinebuf - Pointer to the input data
lineWidth - Width of the line in pixels
Return Value:
TRUE for success, FALSE for failure
--*/
{
INT a0, a1, a2, b1, b2, distance;
LPBYTE prefline;
BYTE pZeroline[1728/8];
DWORD Lines=0;
LPBYTE StartBitbuf = TiffInstance->bitbuf;
// set first all white reference line
prefline = pZeroline;
ZeroMemory( pZeroline, sizeof(pZeroline) );
// loop til end
do {
//
// 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( TiffInstance, PASSCODE_LENGTH, PASSCODE );
#if TIFFDBG
PrintRunInfo( 1, 0, PASSCODE_LENGTH, PASSCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = b2;
} else if ((distance = a1 - b1) <= 3 && distance >= -3) {
//
// Vertical mode
//
OutputBits( TiffInstance, VertCodes[distance+3].length, VertCodes[distance+3].code );
#if TIFFDBG
PrintRunInfo( 2, a1-a0, VertCodes[distance+3].length, VertCodes[distance+3].code );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = a1;
} else {
//
// Horizontal mode
//
a2 = (a1 >= lineWidth) ? lineWidth :
NextChangingElement( plinebuf, a1, lineWidth, GetBit( plinebuf, a1 ) );
OutputBits( TiffInstance, HORZCODE_LENGTH, HORZCODE );
#if TIFFDBG
PrintRunInfo( 3, 0, HORZCODE_LENGTH, HORZCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
if (a1 != 0 && GetBit( plinebuf, a0 )) {
OutputRun( TiffInstance, a1-a0, BlackRunCodes );
OutputRun( TiffInstance, a2-a1, WhiteRunCodes );
} else {
OutputRun( TiffInstance, a1-a0, WhiteRunCodes );
OutputRun( TiffInstance, a2-a1, BlackRunCodes );
}
a0 = a2;
}
if (a0 >= lineWidth) {
Lines++;
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 ) );
}
prefline = plinebuf;
plinebuf += TiffInstance->BytesPerLine;
} while (Lines < ImageHeight);
OutputEOL( TiffInstance, FALSE );
*DestSize = (DWORD)(TiffInstance->bitbuf - StartBitbuf);
TiffInstance->Lines = Lines;
return TRUE;
}
BOOL
EncodeMmrBranding(
PBYTE pBrandBits,
LPDWORD pMmrBrandBits,
INT BrandHeight,
INT BrandWidth,
DWORD *DwordsOut,
DWORD *BitsOut
)
/*++
Routine Description:
Encode an MMR branding from uncompressed branding bits.
I don't have enough time to write an optimized
Uncompressed -> MMR convertor, so the compromise is
to use the existing Uncompressed Decoder (fast enough)
and use the optimized MMR Encoder.
Since we only convert few lines for Branding, it's OK.
--*/
{
INT a0, a1, a2, b1, b2, distance;
LPBYTE prefline;
BYTE pZeroline[1728/8];
INT Lines = 0;
LPDWORD lpdwOut = pMmrBrandBits;
BYTE BitOut = 0;
// set first all white reference line
prefline = pZeroline;
ZeroMemory(pZeroline, BrandWidth/8);
// loop til all lines done
do {
a0 = 0;
a1 = GetBit( pBrandBits, 0) ? 0 : NextChangingElement(pBrandBits, 0, BrandWidth, 0 );
b1 = GetBit( prefline, 0) ? 0 : NextChangingElement(prefline, 0, BrandWidth, 0 );
while (TRUE) {
b2 = (b1 >= BrandWidth) ? BrandWidth :
NextChangingElement( prefline, b1, BrandWidth, GetBit(prefline, b1 ));
if (b2 < a1) {
//
// Pass mode
//
//OutputBits( TiffInstance, PASSCODE_LENGTH, PASSCODE );
(*lpdwOut) += ( ((DWORD) (PASSCODE_REVERSED)) << BitOut);
if ( (BitOut = BitOut + PASSCODE_LENGTH ) > 31 ) {
BitOut -= 32;
*(++lpdwOut) = ( (DWORD) (PASSCODE_REVERSED) ) >> (PASSCODE_LENGTH - BitOut);
}
#if TIFFDBG
PrintRunInfo( 1, 0, PASSCODE_LENGTH, PASSCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = b2;
} else if ((distance = a1 - b1) <= 3 && distance >= -3) {
//
// Vertical mode
//
// OutputBits( TiffInstance, VertCodes[distance+3].length, VertCodes[distance+3].code );
(*lpdwOut) += ( ( (DWORD) VertCodesReversed[distance+3].code) << BitOut);
if ( (BitOut = BitOut + VertCodesReversed[distance+3].length ) > 31 ) {
BitOut -= 32;
*(++lpdwOut) = ( (DWORD) (VertCodesReversed[distance+3].code) ) >> (VertCodesReversed[distance+3].length - BitOut);
}
#if TIFFDBG
PrintRunInfo( 2, a1-a0, VertCodes[distance+3].length, VertCodes[distance+3].code );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
a0 = a1;
} else {
//
// Horizontal mode
//
a2 = (a1 >= BrandWidth) ? BrandWidth :
NextChangingElement( pBrandBits, a1, BrandWidth, GetBit( pBrandBits, a1 ) );
// OutputBits( TiffInstance, HORZCODE_LENGTH, HORZCODE );
(*lpdwOut) += ( ((DWORD) (HORZCODE_REVERSED)) << BitOut);
if ( (BitOut = BitOut + HORZCODE_LENGTH ) > 31 ) {
BitOut -= 32;
*(++lpdwOut) = ( (DWORD) (HORZCODE_REVERSED) ) >> (HORZCODE_LENGTH - BitOut);
}
#if TIFFDBG
PrintRunInfo( 3, 0, HORZCODE_LENGTH, HORZCODE );
_tprintf( TEXT("\t\ta0=%d, a1=%d, a2=%d, b1=%d, b2=%d\n"), a0, a1, a2, b1, b2 );
#endif
if (a1 != 0 && GetBit( pBrandBits, a0 )) {
//OutputRun( TiffInstance, a1-a0, BlackRunCodes );
//OutputRun( TiffInstance, a2-a1, WhiteRunCodes );
OutputRunFastReversed(a1-a0, BLACK, &lpdwOut, &BitOut);
OutputRunFastReversed(a2-a1, WHITE, &lpdwOut, &BitOut);
} else {
//OutputRun( TiffInstance, a1-a0, WhiteRunCodes );
//OutputRun( TiffInstance, a2-a1, BlackRunCodes );
OutputRunFastReversed(a1-a0, WHITE, &lpdwOut, &BitOut);
OutputRunFastReversed(a2-a1, BLACK, &lpdwOut, &BitOut);
}
a0 = a2;
}
if (a0 >= BrandWidth) {
Lines++;
break;
}
a1 = NextChangingElement( pBrandBits, a0, BrandWidth, GetBit( pBrandBits, a0 ) );
b1 = NextChangingElement( prefline, a0, BrandWidth, !GetBit( pBrandBits, a0 ) );
b1 = NextChangingElement( prefline, b1, BrandWidth, GetBit( pBrandBits, a0 ) );
}
prefline = pBrandBits;
pBrandBits += (BrandWidth / 8);
} while (Lines < BrandHeight);
*DwordsOut = (DWORD)(lpdwOut - pMmrBrandBits);
*BitsOut = BitOut;
return TRUE;
}