/*++ Copyright (c) 1996 Microsoft Corporation Module Name: decode.c Abstract: This file contains functions for decoding (de-compressing) compressed 1 bit per pel data from 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 BOOL DecodeUnCompressedFaxData( PTIFF_INSTANCE_DATA TiffInstance, LPBYTE OutputBuffer, BOOL SingleLineBuffer, DWORD PadLength ) /*++ Routine Description: Decode a single page of uncompressed TIFF data. Arguments: TiffInstance - Pointer to the TIFF instance data OutputBuffer - Output buffer where the uncompressed data is written. This buffer must be allocated by the caller and must be large enough for a single page of data. Return Value: NONE --*/ { __try { FillMemory( OutputBuffer, TiffInstance->ImageHeight * (TiffInstance->ImageWidth / 8), WHITE ); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } TiffInstance->Lines = TiffInstance->StripDataSize / (TiffInstance->ImageWidth / 8); CopyMemory( OutputBuffer, TiffInstance->StripData, TiffInstance->StripDataSize ); return TRUE; } BOOL DecodeMHFaxData( PTIFF_INSTANCE_DATA TiffInstance, LPBYTE OutputBuffer, BOOL SingleLineBuffer, DWORD PadLength ) /*++ Routine Description: Decode a single page of 1 dimensionaly compressed TIFF data. Arguments: TiffInstance - Pointer to the TIFF instance data OutputBuffer - Output buffer where the uncompressed data is written. This buffer must be allocated by the caller and must be large enough for a single page of data. Return Value: NONE --*/ { DWORD i; DWORD j; BYTE octet; PDECODE_TREE Tree; INT code; PBYTE plinebuf; DWORD lineWidth; DWORD Lines; DWORD EolCount; DWORD BadFaxLines; BOOL LastLineBad; // // initialization // if (!SingleLineBuffer) { __try { FillMemory( OutputBuffer, TiffInstance->ImageHeight * (TiffInstance->ImageWidth / 8), WHITE ); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } } Tree = WhiteDecodeTree; code = 0; Lines = 0; EolCount = 1; BadFaxLines = 0; LastLineBad = FALSE; TiffInstance->Color = 0; TiffInstance->RunLength = 0; TiffInstance->bitdata = 0; TiffInstance->bitcnt = DWORDBITS; TiffInstance->bitbuf = OutputBuffer; TiffInstance->StartGood = 0; TiffInstance->EndGood = 0; plinebuf = TiffInstance->StripData; lineWidth = TiffInstance->ImageWidth; for (i=0; iStripDataSize; i++) { if (plinebuf[i] == 0) { break; } } // // loop thru each byte in the file // for (; iStripDataSize; i++) { octet = plinebuf[i]; if (i == 2147) DebugBreak(); // // loop thru each bit in the byte // for (j=0; j<8; j++,octet<<=1) { if (code == DECODEEOL) { if (!(octet&0x80)) { // // here we skip all bits until we hit a 1 bit // this happens when the first octet in a line // is all zeroes and we detect that we are // searching for an EOL // continue; } if (TiffInstance->RunLength && TiffInstance->RunLength != lineWidth) { if (TiffInstance->RunLength < lineWidth) { TiffInstance->Color = 0; OutputCodeBits( TiffInstance, lineWidth - TiffInstance->RunLength ); } if (LastLineBad) { BadFaxLines += 1; } else { if (BadFaxLines > TiffInstance->BadFaxLines) { TiffInstance->BadFaxLines = BadFaxLines; } BadFaxLines = 1; LastLineBad = TRUE; } } else { LastLineBad = FALSE; } if (!TiffInstance->StartGood) { TiffInstance->StartGood = i - 1; } // // we hit the eol marker // Tree = WhiteDecodeTree; TiffInstance->Color = 0; code = 0; if (SingleLineBuffer) { TiffInstance->bitbuf = OutputBuffer; } if (TiffInstance->RunLength) { FlushLine(TiffInstance,PadLength); TiffInstance->RunLength = 0; Lines += 1; EolCount = 1; } else { // // the eol count is maintained to that // an rtc sequence is detected. // EolCount += 1; if (EolCount == 6) { // // this is an rtc sequence, so any // data that follows in the file // is garbage. // goto good_exit; } } continue; } code = ((octet&0x80)>>7) ? Tree[code].Right : Tree[code].Left; if (code == BADRUN) { return FALSE; } if (code < 1) { code = (-code); OutputCodeBits( TiffInstance, code ); if (code < 64) { // // terminating code // TiffInstance->Color = !TiffInstance->Color; Tree = TiffInstance->Color ? BlackDecodeTree : WhiteDecodeTree; } code = 0; } } } good_exit: TiffInstance->EndGood = i; if (BadFaxLines > TiffInstance->BadFaxLines) { TiffInstance->BadFaxLines = BadFaxLines; } FlushBits( TiffInstance ); TiffInstance->Lines = Lines; return TRUE; } BOOL DecodeMRFaxData( PTIFF_INSTANCE_DATA TiffInstance, LPBYTE OutputBuffer, BOOL SingleLineBuffer, DWORD PadLength ) /*++ Routine Description: Decode a single page of 2 dimensionaly compressed TIFF data. Arguments: TiffInstance - Pointer to the TIFF instance data OutputBuffer - Output buffer where the uncompressed data is written. This buffer must be allocated by the caller and must be large enough for a single page of data. Return Value: NONE --*/ { DWORD i; DWORD j; BYTE octet; PDECODE_TREE Tree; INT code; LPBYTE prefline; LPBYTE pcurrline; DWORD HorzRuns; BOOL OneDimensional; DWORD a0; DWORD a1; DWORD b1; DWORD b2; PBYTE plinebuf; DWORD lineWidth; DWORD Lines; DWORD EolCount; DWORD BadFaxLines; BOOL LastLineBad; // // initialization // if (!SingleLineBuffer) { __try { FillMemory( OutputBuffer, TiffInstance->ImageHeight * (TiffInstance->ImageWidth / 8), WHITE ); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } } Tree = WhiteDecodeTree; code = 0; HorzRuns = 0; EolCount = 1; BadFaxLines = 0; LastLineBad = FALSE; TiffInstance->Color = 0; TiffInstance->RunLength = 0; TiffInstance->bitdata = 0; TiffInstance->bitcnt = DWORDBITS; TiffInstance->bitbuf = OutputBuffer; OneDimensional = TRUE; plinebuf = TiffInstance->StripData; lineWidth = TiffInstance->ImageWidth; pcurrline = OutputBuffer; prefline = OutputBuffer; a0 = 0; a1 = 0; b1 = 0; b2 = 0; Lines = 0; // // loop thru each byte in the file // for (j=0; jStripDataSize; j++) { octet = *plinebuf++; // // loop thru each bit in the byte // for (i=0; i<8; i++,octet<<=1) { if (code == DECODEEOL2) { // // we hit the final eol marker // if (TiffInstance->RunLength && TiffInstance->RunLength != lineWidth) { if (TiffInstance->RunLength < lineWidth) { TiffInstance->Color = 0; OutputCodeBits( TiffInstance, lineWidth - TiffInstance->RunLength ); } if (LastLineBad) { BadFaxLines += 1; } else { if (BadFaxLines > TiffInstance->BadFaxLines) { TiffInstance->BadFaxLines = BadFaxLines; } BadFaxLines = 1; LastLineBad = TRUE; } } else { LastLineBad = FALSE; } if (!TiffInstance->StartGood) { TiffInstance->StartGood = i - 1; } // // set the decoding tree // OneDimensional = (octet & 0x80) == 0x80; Tree = OneDimensional ? WhiteDecodeTree : TwoDecodeTree; // // reset the control variables // TiffInstance->Color = 0; code = 0; a0 = 0; a1 = 0; b1 = 0; b2 = 0; // // if there is a non-zero runlength then // spaw the reference & current line pointers // and count this line. the runlength can be // zero when there is just an empty eol in // the stream. // if (SingleLineBuffer) { TiffInstance->bitbuf = OutputBuffer; } if (TiffInstance->RunLength) { TiffInstance->RunLength = 0; Lines += 1; prefline = pcurrline; pcurrline = TiffInstance->bitbuf; } else { // // the eol count is maintained to that // an rtc sequence is detected. // EolCount += 1; if (EolCount == 6) { // // this is an rtc sequence, so any // data that follows in the file // is garbage. // goto good_exit; } } continue; } if (code == DECODEEOL) { if (!(octet&0x80)) { // // here we skip all bits until we hit a 1 bit // this happens when the first octet in a line // is all zeroes and we detect that we are // searching for an EOL // continue; } // // this forces the code to pickup the next // bit in the stream, which tells whether // the next line is encoded in MH or MR compression // code = DECODEEOL2; continue; } if (code == BADRUN) { code = 0; continue; } code = ((octet&0x80)>>7) ? Tree[code].Right : Tree[code].Left; b1 = NextChangingElement( prefline, a0, lineWidth, !TiffInstance->Color ); b1 = NextChangingElement( prefline, b1, lineWidth, TiffInstance->Color ); b2 = NextChangingElement( prefline, b1, lineWidth, GetBit(prefline, b1 ) ); if (OneDimensional) { if (code < 1) { code = (-code); OutputCodeBits( TiffInstance, code ); // // the affect of this is to accumulate the runlengths // into a0, causing a0 to be placed on a2 when horizontal // mode is completed/ // a0 += code; if (code < 64) { // // terminating code // TiffInstance->Color = !TiffInstance->Color; Tree = TiffInstance->Color ? BlackDecodeTree : WhiteDecodeTree; if (HorzRuns) { HorzRuns -= 1; if (!HorzRuns) { Tree = TwoDecodeTree; OneDimensional = FALSE; } } } code = 0; } continue; } if (code == HORZMODE) { // // horizontal mode occurs when b1-a1 greater than 3 // code= 0; HorzRuns = 2; OneDimensional = TRUE; Tree = TiffInstance->Color ? BlackDecodeTree : WhiteDecodeTree; } else if (code == PASSMODE) { // // pass mode occurs when the position of b2 lies // to the left of a1, but a1 cannot be equal to b2. // code = b2 - a0; OutputCodeBits( TiffInstance, code ); code = 0; a0 = b2; } else if (code >= VTMODE3N && code <= VTMODE3P) { // // vertical mode occurs when b1-a1 <= 3 // a1 = b1 - (VTMODE0 - code); code = a1 - a0; OutputCodeBits( TiffInstance, code ); code = 0; a0 = a1; TiffInstance->Color = !TiffInstance->Color; } } } good_exit: TiffInstance->EndGood = i; if (BadFaxLines > TiffInstance->BadFaxLines) { TiffInstance->BadFaxLines = BadFaxLines; } FlushBits( TiffInstance ); TiffInstance->Lines = Lines; return TRUE; } BOOL DecodeMMRFaxData( PTIFF_INSTANCE_DATA TiffInstance, LPBYTE OutputBuffer, BOOL SingleLineBuffer, DWORD PadLength ) /*++ Routine Description: Decode a single page of 2 dimensionaly compressed TIFF data. Arguments: TiffInstance - Pointer to the TIFF instance data OutputBuffer - Output buffer where the uncompressed data is written. This buffer must be allocated by the caller and must be large enough for a single page of data. Return Value: NONE --*/ { DWORD i; DWORD j; BYTE octet; PDECODE_TREE Tree; INT code; LPBYTE prefline; LPBYTE pcurrline; DWORD HorzRuns; BOOL OneDimensional; DWORD a0; DWORD a1; DWORD b1; DWORD b2; PBYTE plinebuf; DWORD lineWidth; DWORD Lines; DWORD EolCount; // // initialization // if (!SingleLineBuffer) { __try { FillMemory( OutputBuffer, TiffInstance->ImageHeight * (TiffInstance->ImageWidth / 8), WHITE ); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } } Tree = TwoDecodeTree; code = 0; HorzRuns = 0; EolCount = 0; TiffInstance->Color = 0; TiffInstance->RunLength = 0; TiffInstance->bitdata = 0; TiffInstance->bitcnt = DWORDBITS; TiffInstance->bitbuf = OutputBuffer; OneDimensional = FALSE; plinebuf = TiffInstance->StripData; lineWidth = TiffInstance->ImageWidth; pcurrline = OutputBuffer; prefline = OutputBuffer; a0 = 0; a1 = 0; b1 = 0; b2 = 0; Lines = 0; // // loop thru each byte in the file // for (j=0; jStripDataSize; j++) { octet = *plinebuf++; // // loop thru each bit in the byte // for (i=0; i<8; i++,octet<<=1) { if (Lines + 1 == TiffInstance->ImageHeight && TiffInstance->RunLength == lineWidth) { goto good_exit; } // // if the OneDimensional flag is set and the RunLength == lineWidth // then it means that the last run length was horizontal mode // and it was not a terminating code. in this case we must go // process the remaining termination code before ending the line. // // if the OneDimensional flag is NOT set and the RunLength == lineWidth // then we are at the end of a line. for mmr compression there are // no eols, so this is the pseudo eol. // if ((TiffInstance->RunLength == lineWidth) && (!OneDimensional)) { // // set the decoding tree // Tree = TwoDecodeTree; // // reset the control variables // TiffInstance->Color = 0; code = 0; a0 = 0; a1 = 0; b1 = 0; b2 = 0; Tree = TwoDecodeTree; OneDimensional = FALSE; // // if there is a non-zero runlength then // spaw the reference & current line pointers // and count this line. the runlength can be // zero when there is just an empty eol in // the stream. // if (SingleLineBuffer) { TiffInstance->bitbuf = OutputBuffer; } TiffInstance->RunLength = 0; Lines += 1; prefline = pcurrline; pcurrline = TiffInstance->bitbuf; b1 = GetBit(prefline, 0) ? 0 : NextChangingElement(prefline, 0, lineWidth, 0); } else if (code == DECODEEOL2) { // // the eol count is maintained to that // an rtc sequence is detected. // EolCount += 1; if (EolCount == 2) { // // this is an rtc sequence, so any // data that follows in the file // is garbage. // goto good_exit; } continue; } else if (code == DECODEEOL) { if (!(octet&0x80)) { // // here we skip all bits until we hit a 1 bit // this happens when the first octet in a line // is all zeroes and we detect that we are // searching for an EOL // continue; } // // this forces the code to pickup the next // bit in the stream, which tells whether // the next line is encoded in MH or MR compression // code = DECODEEOL2; continue; } else if (code == BADRUN) { code = 0; continue; } else { b1 = NextChangingElement( prefline, a0, lineWidth, !TiffInstance->Color ); b1 = NextChangingElement( prefline, b1, lineWidth, TiffInstance->Color ); } b2 = NextChangingElement( prefline, b1, lineWidth, GetBit(prefline, b1 ) ); code = ((octet&0x80)>>7) ? Tree[code].Right : Tree[code].Left; if (OneDimensional) { if (code < 1) { code = (-code); OutputCodeBits( TiffInstance, code ); // // the affect of this is to accumulate the runlengths // into a0, causing a0 to be placed on a2 when horizontal // mode is completed/ // a0 += code; if (code < 64) { // // terminating code // TiffInstance->Color = !TiffInstance->Color; Tree = TiffInstance->Color ? BlackDecodeTree : WhiteDecodeTree; if (HorzRuns) { HorzRuns -= 1; if (!HorzRuns) { Tree = TwoDecodeTree; OneDimensional = FALSE; } } } code = 0; } continue; } if (code == HORZMODE) { // // horizontal mode occurs when b1-a1 greater than 3 // code= 0; HorzRuns = 2; OneDimensional = TRUE; Tree = TiffInstance->Color ? BlackDecodeTree : WhiteDecodeTree; } else if (code == PASSMODE) { // // pass mode occurs when the position of b2 lies // to the left of a1, but a1 cannot be equal to b2. // code = b2 - a0; OutputCodeBits( TiffInstance, code ); code = 0; a0 = b2; } else if (code >= VTMODE3N && code <= VTMODE3P) { // // vertical mode occurs when b1-a1 <= 3 // a1 = b1 - (VTMODE0 - code); code = a1 - a0; OutputCodeBits( TiffInstance, code ); code = 0; a0 = a1; TiffInstance->Color = !TiffInstance->Color; } } } good_exit: FlushBits( TiffInstance ); TiffInstance->Lines = Lines; return TRUE; }