/* * (c) Copyright Ascensio System SIA 2010-2016 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, * EU, LV-1021. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include #include #include "List.h" #include "JArithmeticDecoder.h" #include "JBIG2Stream.h" //~ share these tables #include "CCITT-Tables.h" namespace PdfReader { static int c_arrContextSize[4] ={ 16, 13, 10, 10 }; static int c_arrRefContextSize[2] ={ 13, 10 }; //------------------------------------------------------------------------ // JBIG2HuffmanTable //------------------------------------------------------------------------ #define jbig2HuffmanLOW 0xfffffffd #define jbig2HuffmanOOB 0xfffffffe #define jbig2HuffmanEOT 0xffffffff struct JBIG2HuffmanTable { int nValue; unsigned int unPrefixLen; unsigned int unRangeLen; // can also be LOW, OOB, or EOT unsigned int unPrefix; }; JBIG2HuffmanTable c_oHuffTableA[] = { { 0, 1, 4, 0x000 }, { 16, 2, 8, 0x002 }, { 272, 3, 16, 0x006 }, { 65808, 3, 32, 0x007 }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableB[] = { { 0, 1, 0, 0x000 }, { 1, 2, 0, 0x002 }, { 2, 3, 0, 0x006 }, { 3, 4, 3, 0x00e }, { 11, 5, 6, 0x01e }, { 75, 6, 32, 0x03e }, { 0, 6, jbig2HuffmanOOB, 0x03f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableC[] = { { 0, 1, 0, 0x000 }, { 1, 2, 0, 0x002 }, { 2, 3, 0, 0x006 }, { 3, 4, 3, 0x00e }, { 11, 5, 6, 0x01e }, { 0, 6, jbig2HuffmanOOB, 0x03e }, { 75, 7, 32, 0x0fe }, { -256, 8, 8, 0x0fe }, { -257, 8, jbig2HuffmanLOW, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableD[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 0, 0x006 }, { 4, 4, 3, 0x00e }, { 12, 5, 6, 0x01e }, { 76, 5, 32, 0x01f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableE[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 0, 0x006 }, { 4, 4, 3, 0x00e }, { 12, 5, 6, 0x01e }, { 76, 6, 32, 0x03e }, { -255, 7, 8, 0x07e }, { -256, 7, jbig2HuffmanLOW, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableF[] = { { 0, 2, 7, 0x000 }, { 128, 3, 7, 0x002 }, { 256, 3, 8, 0x003 }, { -1024, 4, 9, 0x008 }, { -512, 4, 8, 0x009 }, { -256, 4, 7, 0x00a }, { -32, 4, 5, 0x00b }, { 512, 4, 9, 0x00c }, { 1024, 4, 10, 0x00d }, { -2048, 5, 10, 0x01c }, { -128, 5, 6, 0x01d }, { -64, 5, 5, 0x01e }, { -2049, 6, jbig2HuffmanLOW, 0x03e }, { 2048, 6, 32, 0x03f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableG[] = { { -512, 3, 8, 0x000 }, { 256, 3, 8, 0x001 }, { 512, 3, 9, 0x002 }, { 1024, 3, 10, 0x003 }, { -1024, 4, 9, 0x008 }, { -256, 4, 7, 0x009 }, { -32, 4, 5, 0x00a }, { 0, 4, 5, 0x00b }, { 128, 4, 7, 0x00c }, { -128, 5, 6, 0x01a }, { -64, 5, 5, 0x01b }, { 32, 5, 5, 0x01c }, { 64, 5, 6, 0x01d }, { -1025, 5, jbig2HuffmanLOW, 0x01e }, { 2048, 5, 32, 0x01f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableH[] = { { 0, 2, 1, 0x000 }, { 0, 2, jbig2HuffmanOOB, 0x001 }, { 4, 3, 4, 0x004 }, { -1, 4, 0, 0x00a }, { 22, 4, 4, 0x00b }, { 38, 4, 5, 0x00c }, { 2, 5, 0, 0x01a }, { 70, 5, 6, 0x01b }, { 134, 5, 7, 0x01c }, { 3, 6, 0, 0x03a }, { 20, 6, 1, 0x03b }, { 262, 6, 7, 0x03c }, { 646, 6, 10, 0x03d }, { -2, 7, 0, 0x07c }, { 390, 7, 8, 0x07d }, { -15, 8, 3, 0x0fc }, { -5, 8, 1, 0x0fd }, { -7, 9, 1, 0x1fc }, { -3, 9, 0, 0x1fd }, { -16, 9, jbig2HuffmanLOW, 0x1fe }, { 1670, 9, 32, 0x1ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableI[] = { { 0, 2, jbig2HuffmanOOB, 0x000 }, { -1, 3, 1, 0x002 }, { 1, 3, 1, 0x003 }, { 7, 3, 5, 0x004 }, { -3, 4, 1, 0x00a }, { 43, 4, 5, 0x00b }, { 75, 4, 6, 0x00c }, { 3, 5, 1, 0x01a }, { 139, 5, 7, 0x01b }, { 267, 5, 8, 0x01c }, { 5, 6, 1, 0x03a }, { 39, 6, 2, 0x03b }, { 523, 6, 8, 0x03c }, { 1291, 6, 11, 0x03d }, { -5, 7, 1, 0x07c }, { 779, 7, 9, 0x07d }, { -31, 8, 4, 0x0fc }, { -11, 8, 2, 0x0fd }, { -15, 9, 2, 0x1fc }, { -7, 9, 1, 0x1fd }, { -32, 9, jbig2HuffmanLOW, 0x1fe }, { 3339, 9, 32, 0x1ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableJ[] = { { -2, 2, 2, 0x000 }, { 6, 2, 6, 0x001 }, { 0, 2, jbig2HuffmanOOB, 0x002 }, { -3, 5, 0, 0x018 }, { 2, 5, 0, 0x019 }, { 70, 5, 5, 0x01a }, { 3, 6, 0, 0x036 }, { 102, 6, 5, 0x037 }, { 134, 6, 6, 0x038 }, { 198, 6, 7, 0x039 }, { 326, 6, 8, 0x03a }, { 582, 6, 9, 0x03b }, { 1094, 6, 10, 0x03c }, { -21, 7, 4, 0x07a }, { -4, 7, 0, 0x07b }, { 4, 7, 0, 0x07c }, { 2118, 7, 11, 0x07d }, { -5, 8, 0, 0x0fc }, { 5, 8, 0, 0x0fd }, { -22, 8, jbig2HuffmanLOW, 0x0fe }, { 4166, 8, 32, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableK[] = { { 1, 1, 0, 0x000 }, { 2, 2, 1, 0x002 }, { 4, 4, 0, 0x00c }, { 5, 4, 1, 0x00d }, { 7, 5, 1, 0x01c }, { 9, 5, 2, 0x01d }, { 13, 6, 2, 0x03c }, { 17, 7, 2, 0x07a }, { 21, 7, 3, 0x07b }, { 29, 7, 4, 0x07c }, { 45, 7, 5, 0x07d }, { 77, 7, 6, 0x07e }, { 141, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableL[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 1, 0x006 }, { 5, 5, 0, 0x01c }, { 6, 5, 1, 0x01d }, { 8, 6, 1, 0x03c }, { 10, 7, 0, 0x07a }, { 11, 7, 1, 0x07b }, { 13, 7, 2, 0x07c }, { 17, 7, 3, 0x07d }, { 25, 7, 4, 0x07e }, { 41, 8, 5, 0x0fe }, { 73, 8, 32, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableM[] = { { 1, 1, 0, 0x000 }, { 2, 3, 0, 0x004 }, { 7, 3, 3, 0x005 }, { 3, 4, 0, 0x00c }, { 5, 4, 1, 0x00d }, { 4, 5, 0, 0x01c }, { 15, 6, 1, 0x03a }, { 17, 6, 2, 0x03b }, { 21, 6, 3, 0x03c }, { 29, 6, 4, 0x03d }, { 45, 6, 5, 0x03e }, { 77, 7, 6, 0x07e }, { 141, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableN[] = { { 0, 1, 0, 0x000 }, { -2, 3, 0, 0x004 }, { -1, 3, 0, 0x005 }, { 1, 3, 0, 0x006 }, { 2, 3, 0, 0x007 }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable c_oHuffTableO[] = { { 0, 1, 0, 0x000 }, { -1, 3, 0, 0x004 }, { 1, 3, 0, 0x005 }, { -2, 4, 0, 0x00c }, { 2, 4, 0, 0x00d }, { -4, 5, 1, 0x01c }, { 3, 5, 1, 0x01d }, { -8, 6, 2, 0x03c }, { 5, 6, 2, 0x03d }, { -24, 7, 4, 0x07c }, { 9, 7, 4, 0x07d }, { -25, 7, jbig2HuffmanLOW, 0x07e }, { 25, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; //------------------------------------------------------------------------ // JBIG2HuffmanDecoder //------------------------------------------------------------------------ class JBIG2HuffmanDecoder { public: JBIG2HuffmanDecoder() { m_pStream = NULL; Reset(); } ~JBIG2HuffmanDecoder() { } void SetStream(Stream *pStream) { m_pStream = pStream; } void Reset() { unBuffer = 0; unBufferLen = 0; } // Returns false for OOB, otherwise sets * and returns true. //~ optimize this bool DecodeInt(int *pnValue, JBIG2HuffmanTable *pTable) { unsigned int unIndex = 0, unPrefix = 0, unLen = 0; while (pTable[unIndex].unRangeLen != jbig2HuffmanEOT) { while (unLen < pTable[unIndex].unPrefixLen) { unPrefix = (unPrefix << 1) | ReadBit(); ++unLen; } if (unPrefix == pTable[unIndex].unPrefix) { if (pTable[unIndex].unRangeLen == jbig2HuffmanOOB) { return false; } if (pTable[unIndex].unRangeLen == jbig2HuffmanLOW) { *pnValue = pTable[unIndex].nValue - ReadBits(32); } else if (pTable[unIndex].unRangeLen > 0) { *pnValue = pTable[unIndex].nValue + ReadBits(pTable[unIndex].unRangeLen); } else { *pnValue = pTable[unIndex].nValue; } return true; } ++unIndex; } return false; } unsigned int ReadBits(unsigned int unCount) { unsigned int unMask = (unCount == 32) ? 0xffffffff : ((1 << unCount) - 1); unsigned int unValue; if (unBufferLen >= unCount) { unValue = (unBuffer >> (unBufferLen - unCount)) & unMask; unBufferLen -= unCount; } else { unValue = unBuffer & ((1 << unBufferLen) - 1); unsigned int unLeftCount = unCount - unBufferLen; unBufferLen = 0; while (unLeftCount >= 8) { unValue = (unValue << 8) | (m_pStream->GetChar() & 0xff); unLeftCount -= 8; } if (unLeftCount > 0) { unBuffer = m_pStream->GetChar(); unBufferLen = 8 - unLeftCount; unValue = (unValue << unLeftCount) | ((unBuffer >> unBufferLen) & ((1 << unLeftCount) - 1)); } } return unValue; } unsigned int ReadBit() { if (unBufferLen == 0) { unBuffer = m_pStream->GetChar(); unBufferLen = 8; } --unBufferLen; return (unBuffer >> unBufferLen) & 1; } // Sort the table by prefix length and assign prefix values. void BuildTable(JBIG2HuffmanTable *pTable, unsigned int unLen) { // stable selection sort: // - entries with prefixLen > 0, in ascending prefixLen order // - entry with prefixLen = 0, rangeLen = EOT // - all other entries with prefixLen = 0 // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) unsigned int unI, unJ, unK; for (unI = 0; unI < unLen; ++unI) { for (unJ = unI; unJ < unLen && pTable[unJ].unPrefixLen == 0; ++unJ); if (unJ == unLen) { break; } for (unK = unJ + 1; unK < unLen; ++unK) { if (pTable[unK].unPrefixLen > 0 && pTable[unK].unPrefixLen < pTable[unJ].unPrefixLen) { unJ = unK; } } if (unJ != unI) { JBIG2HuffmanTable oTable = pTable[unJ]; for (unK = unJ; unK > unI; --unK) { pTable[unK] = pTable[unK - 1]; } pTable[unI] = oTable; } } pTable[unI] = pTable[unLen]; // assign prefixes unI = 0; unsigned int unPrefix = 0; pTable[unI++].unPrefix = unPrefix++; for (; pTable[unI].unRangeLen != jbig2HuffmanEOT; ++unI) { unPrefix <<= pTable[unI].unPrefixLen - pTable[unI - 1].unPrefixLen; pTable[unI].unPrefix = unPrefix++; } } private: Stream *m_pStream; unsigned int unBuffer; unsigned int unBufferLen; }; //------------------------------------------------------------------------ // JBIG2MMRDecoder //------------------------------------------------------------------------ class JBIG2MMRDecoder { public: JBIG2MMRDecoder() { m_pStream = NULL; Reset(); } ~JBIG2MMRDecoder() { } void SetStream(Stream *pStream) { m_pStream = pStream; } void Reset() { unBuffer = 0; unBufferLen = 0; unBytesReadCount = 0; } int Get2DCode() { CCITTCode *pCode = NULL; if (unBufferLen == 0) { unBuffer = m_pStream->GetChar() & 0xff; unBufferLen = 8; ++unBytesReadCount; pCode = &c_arrTable2D[(unBuffer >> 1) & 0x7f]; } else if (unBufferLen == 8) { pCode = &c_arrTable2D[(unBuffer >> 1) & 0x7f]; } else { pCode = &c_arrTable2D[(unBuffer << (7 - unBufferLen)) & 0x7f]; if (pCode->nBitsCount < 0 || pCode->nBitsCount >(int)unBufferLen) { unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff); unBufferLen += 8; ++unBytesReadCount; pCode = &c_arrTable2D[(unBuffer >> (unBufferLen - 7)) & 0x7f]; } } if (pCode->nBitsCount < 0) { return 0; } unBufferLen -= pCode->nBitsCount; return pCode->nCode; } int GetWhiteCode() { if (unBufferLen == 0) { unBuffer = m_pStream->GetChar() & 0xff; unBufferLen = 8; ++unBytesReadCount; } while (1) { CCITTCode *pCode = NULL; if (unBufferLen >= 7 && ((unBuffer >> (unBufferLen - 7)) & 0x7f) == 0) { unsigned int unCode; if (unBufferLen <= 12) { unCode = unBuffer << (12 - unBufferLen); } else { unCode = unBuffer >> (unBufferLen - 12); } pCode = &c_arrWhiteTable1[unCode & 0x1f]; } else { unsigned int unCode; if (unBufferLen <= 9) { unCode = unBuffer << (9 - unBufferLen); } else { unCode = unBuffer >> (unBufferLen - 9); } pCode = &c_arrWhiteTable2[unCode & 0x1ff]; } if (pCode->nBitsCount > 0 && pCode->nBitsCount <= (int)unBufferLen) { unBufferLen -= pCode->nBitsCount; return pCode->nCode; } if (unBufferLen >= 12) { break; } unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff); unBufferLen += 8; ++unBytesReadCount; } // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop --unBufferLen; return 1; } int GetBlackCode() { if (unBufferLen == 0) { unBuffer = m_pStream->GetChar() & 0xff; unBufferLen = 8; ++unBytesReadCount; } while (1) { CCITTCode *pCode = NULL; if (unBufferLen >= 6 && ((unBuffer >> (unBufferLen - 6)) & 0x3f) == 0) { unsigned int unCode; if (unBufferLen <= 13) { unCode = unBuffer << (13 - unBufferLen); } else { unCode = unBuffer >> (unBufferLen - 13); } pCode = &c_arrBlackTable1[unCode & 0x7f]; } else if (unBufferLen >= 4 && ((unBuffer >> (unBufferLen - 4)) & 0x0f) == 0) { unsigned int unCode; if (unBufferLen <= 12) { unCode = unBuffer << (12 - unBufferLen); } else { unCode = unBuffer >> (unBufferLen - 12); } pCode = &c_arrBlackTable2[(unCode & 0xff) - 64]; } else { unsigned int unCode; if (unBufferLen <= 6) { unCode = unBuffer << (6 - unBufferLen); } else { unCode = unBuffer >> (unBufferLen - 6); } pCode = &c_arrBlackTable3[unCode & 0x3f]; } if (pCode->nBitsCount > 0 && pCode->nBitsCount <= (int)unBufferLen) { unBufferLen -= pCode->nBitsCount; return pCode->nCode; } if (unBufferLen >= 13) { break; } unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff); unBufferLen += 8; ++unBytesReadCount; } // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop --unBufferLen; return 1; } unsigned int Get24Bits() { while (unBufferLen < 24) { unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff); unBufferLen += 8; ++unBytesReadCount; } return (unBuffer >> (unBufferLen - 24)) & 0xffffff; } void SkipTo(unsigned int unLength) { while (unBytesReadCount < unLength) { m_pStream->GetChar(); ++unBytesReadCount; } } private: Stream *m_pStream; unsigned int unBuffer; unsigned int unBufferLen; unsigned int unBytesReadCount; }; //------------------------------------------------------------------------ // JBIG2Segment //------------------------------------------------------------------------ enum JBIG2SegmentType { jbig2SegBitmap, jbig2SegSymbolDict, jbig2SegPatternDict, jbig2SegCodeTable }; class JBIG2Segment { public: JBIG2Segment(unsigned int unSegNum) { m_unSegNum = unSegNum; } virtual ~JBIG2Segment() { } void SetSegNum(unsigned int unSegNum) { m_unSegNum = unSegNum; } unsigned int GetSegNum() { return m_unSegNum; } virtual JBIG2SegmentType GetType() = 0; private: unsigned int m_unSegNum; }; //------------------------------------------------------------------------ // JBIG2Bitmap //------------------------------------------------------------------------ struct JBIG2BitmapPtr { unsigned char *pDataPtr; int nShift; int nX; }; class JBIG2Bitmap : public JBIG2Segment { public: JBIG2Bitmap(unsigned int unSegNum, int nW, int nH) : JBIG2Segment(unSegNum) { m_nW = nW; m_nH = nH; m_nLine = (nW + 7) >> 3; if (m_nW <= 0 || m_nH <= 0 || m_nLine <= 0 || m_nH >= (INT_MAX - 1) / m_nLine) { m_pData = NULL; return; } // need to allocate one extra guard byte for use in Combine() m_pData = (unsigned char *)MemUtilsMalloc(m_nH * m_nLine + 1); m_pData[m_nH * m_nLine] = 0; } virtual ~JBIG2Bitmap() { MemUtilsFree(m_pData); } virtual JBIG2SegmentType GetType() { return jbig2SegBitmap; } JBIG2Bitmap *Copy() { return new JBIG2Bitmap(0, this); } //~ optimize this JBIG2Bitmap *GetSlice(unsigned int unX, unsigned int unY, unsigned int unW, unsigned int unH) { JBIG2Bitmap *pSlice = new JBIG2Bitmap(0, unW, unH); pSlice->ClearToZero(); for (unsigned int unCurY = 0; unCurY < unH; ++unCurY) { for (unsigned int unCurX = 0; unCurX < unW; ++unCurX) { if (GetPixel(unX + unCurX, unY + unCurY)) { pSlice->SetPixel(unCurX, unCurY); } } } return pSlice; } void Expand(int nNewH, unsigned int unPixel) { if (nNewH <= m_nH || m_nLine <= 0 || nNewH >= (INT_MAX - 1) / m_nLine) { return; } // need to allocate one extra guard byte for use in combine() m_pData = (unsigned char *)MemUtilsRealloc(m_pData, nNewH * m_nLine + 1); if (unPixel) { memset(m_pData + m_nH * m_nLine, 0xff, (nNewH - m_nH) * m_nLine); } else { memset(m_pData + m_nH * m_nLine, 0x00, (nNewH - m_nH) * m_nLine); } m_nH = nNewH; m_pData[m_nH * m_nLine] = 0; } void ClearToZero() { memset(m_pData, 0, m_nH * m_nLine); } void ClearToOne() { memset(m_pData, 0xff, m_nH * m_nLine); } int GetWidth() { return m_nW; } int GetHeight() { return m_nH; } int GetPixel(int nX, int nY) { return (nX < 0 || nX >= m_nW || nY < 0 || nY >= m_nH) ? 0 : (m_pData[nY * m_nLine + (nX >> 3)] >> (7 - (nX & 7))) & 1; } void SetPixel(int nX, int nY) { m_pData[nY * m_nLine + (nX >> 3)] |= 1 << (7 - (nX & 7)); } void ClearPixel(int nX, int nY) { m_pData[nY * m_nLine + (nX >> 3)] &= 0x7f7f >> (nX & 7); } inline void GetPixelPtr(int nX, int nY, JBIG2BitmapPtr *pPtr) { if (nY < 0 || nY >= m_nH || nX >= m_nW) { pPtr->pDataPtr = NULL; } else if (nX < 0) { pPtr->pDataPtr = &m_pData[nY * m_nLine]; pPtr->nShift = 7; pPtr->nX = nX; } else { pPtr->pDataPtr = &m_pData[nY * m_nLine + (nX >> 3)]; pPtr->nShift = 7 - (nX & 7); pPtr->nX = nX; } } inline int NextPixel(JBIG2BitmapPtr *pPtr) { int nPixel; if (!pPtr->pDataPtr) { nPixel = 0; } else if (pPtr->nX < 0) { ++pPtr->nX; nPixel = 0; } else { nPixel = (*pPtr->pDataPtr >> pPtr->nShift) & 1; if (++pPtr->nX == m_nW) { pPtr->pDataPtr = NULL; } else if (pPtr->nShift == 0) { ++pPtr->pDataPtr; pPtr->nShift = 7; } else { --pPtr->nShift; } } return nPixel; } void DuplicateRow(int nDstY, int nSrcY) { memcpy(m_pData + nDstY * m_nLine, m_pData + nSrcY * m_nLine, m_nLine); } void Combine(JBIG2Bitmap *pBitmap, int nX, int nY, unsigned int unCombOp) { int nY0; if (nY < 0) { nY0 = -nY; } else { nY0 = 0; } int nY1; if (nY + pBitmap->m_nH > m_nH) { nY1 = m_nH - nY; } else { nY1 = pBitmap->m_nH; } if (nY0 >= nY1) { return; } int nX0; if (nX >= 0) { nX0 = nX & ~7; } else { nX0 = 0; } int nX1 = nX + pBitmap->m_nW; if (nX1 > m_nW) { nX1 = m_nW; } if (nX0 >= nX1) { return; } unsigned int unS1 = nX & 7; unsigned int unS2 = 8 - unS1; unsigned int unM1 = 0xff >> (nX1 & 7); unsigned int unM2 = 0xff << (((nX1 & 7) == 0) ? 0 : 8 - (nX1 & 7)); unsigned int unM3 = (0xff >> unS1) & unM2; bool bOneByte = (nX0 == ((nX1 - 1) & ~7)); unsigned char *pSrcPtr, *pDstPtr; for (int nCurY = nY0; nCurY < nY1; ++nCurY) { // one byte per line -- need to mask both left and right side if (bOneByte) { unsigned int unSrc1, unDst; if (nX >= 0) { pDstPtr = m_pData + (nY + nCurY) * m_nLine + (nX >> 3); pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine; unDst = *pDstPtr; unSrc1 = *pSrcPtr; switch (unCombOp) { case 0: // or unDst |= (unSrc1 >> unS1) & unM2; break; case 1: // and unDst &= ((0xff00 | unSrc1) >> unS1) | unM1; break; case 2: // xor unDst ^= (unSrc1 >> unS1) & unM2; break; case 3: // xnor unDst ^= ((unSrc1 ^ 0xff) >> unS1) & unM2; break; case 4: // replace unDst = (unDst & ~unM3) | ((unSrc1 >> unS1) & unM3); break; } *pDstPtr = unDst; } else { pDstPtr = m_pData + (nY + nCurY) * m_nLine; pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine + (-nX >> 3); unDst = *pDstPtr; unSrc1 = *pSrcPtr; switch (unCombOp) { case 0: // or unDst |= unSrc1 & unM2; break; case 1: // and unDst &= unSrc1 | unM1; break; case 2: // xor unDst ^= unSrc1 & unM2; break; case 3: // xnor unDst ^= (unSrc1 ^ 0xff) & unM2; break; case 4: // replace unDst = (unSrc1 & unM2) | (unDst & unM1); break; } *pDstPtr = unDst; } } else // multiple bytes per line -- need to mask left side of left-most byte and right side of right-most byte { int nCurX; unsigned int unSrc0, unSrc1, unSrc, unDst; if (nX >= 0) // left-most byte { pDstPtr = m_pData + (nY + nCurY) * m_nLine + (nX >> 3); pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine; unSrc1 = *pSrcPtr++; unDst = *pDstPtr; switch (unCombOp) { case 0: // or unDst |= unSrc1 >> unS1; break; case 1: // and unDst &= (0xff00 | unSrc1) >> unS1; break; case 2: // xor unDst ^= unSrc1 >> unS1; break; case 3: // xnor unDst ^= (unSrc1 ^ 0xff) >> unS1; break; case 4: // replace unDst = (unDst & (0xff << unS2)) | (unSrc1 >> unS1); break; } *pDstPtr++ = unDst; nCurX = nX0 + 8; } else { pDstPtr = m_pData + (nY + nCurY) * m_nLine; pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine + (-nX >> 3); unSrc1 = *pSrcPtr++; nCurX = nX0; } // middle bytes for (; nCurX < nX1 - 8; nCurX += 8) { unDst = *pDstPtr; unSrc0 = unSrc1; unSrc1 = *pSrcPtr++; unSrc = (((unSrc0 << 8) | unSrc1) >> unS1) & 0xff; switch (unCombOp) { case 0: // or unDst |= unSrc; break; case 1: // and unDst &= unSrc; break; case 2: // xor unDst ^= unSrc; break; case 3: // xnor unDst ^= unSrc ^ 0xff; break; case 4: // replace unDst = unSrc; break; } *pDstPtr++ = unDst; } // right-most byte // note: this last byte (src1) may not actually be used, depending // on the values of s1, m1, and m2 - and in fact, it may be off // the edge of the source bitmap, which means we need to allocate // one extra guard byte at the end of each bitmap unDst = *pDstPtr; unSrc0 = unSrc1; unSrc1 = *pSrcPtr++; unSrc = (((unSrc0 << 8) | unSrc1) >> unS1) & 0xff; switch (unCombOp) { case 0: // or unDst |= unSrc & unM2; break; case 1: // and unDst &= unSrc | unM1; break; case 2: // xor unDst ^= unSrc & unM2; break; case 3: // xnor unDst ^= (unSrc ^ 0xff) & unM2; break; case 4: // replace unDst = (unSrc & unM2) | (unDst & unM1); break; } *pDstPtr = unDst; } } } unsigned char *GetDataPtr() { return m_pData; } int GetDataSize() { return m_nH * m_nLine; } private: JBIG2Bitmap(unsigned int unSegNum, JBIG2Bitmap *pBitmap) : JBIG2Segment(unSegNum) { m_nW = pBitmap->m_nW; m_nH = pBitmap->m_nH; m_nLine = pBitmap->m_nLine; if (m_nW <= 0 || m_nH <= 0 || m_nLine <= 0 || m_nH >= (INT_MAX - 1) / m_nLine) { m_pData = NULL; return; } // need to allocate one extra guard byte for use in Combine() m_pData = (unsigned char *)MemUtilsMalloc(m_nH * m_nLine + 1); memcpy(m_pData, pBitmap->m_pData, m_nH * m_nLine); m_pData[m_nH * m_nLine] = 0; } private: int m_nW; int m_nH; int m_nLine; unsigned char *m_pData; }; //------------------------------------------------------------------------ // JBIG2SymbolDict //------------------------------------------------------------------------ class JBIG2SymbolDict : public JBIG2Segment { public: JBIG2SymbolDict(unsigned int unSegNum, unsigned int unSize) : JBIG2Segment(unSegNum) { m_unSize = unSize; m_ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(m_unSize, sizeof(JBIG2Bitmap *)); m_pGenericRegionStats = NULL; m_pRefinementRegionStats = NULL; } virtual ~JBIG2SymbolDict() { for (unsigned int unIndex = 0; unIndex < m_unSize; ++unIndex) { delete m_ppBitmaps[unIndex]; } MemUtilsFree(m_ppBitmaps); if (m_pGenericRegionStats) { delete m_pGenericRegionStats; } if (m_pRefinementRegionStats) { delete m_pRefinementRegionStats; } } virtual JBIG2SegmentType GetType() { return jbig2SegSymbolDict; } unsigned int GetSize() { return m_unSize; } void SetBitmap(unsigned int unIndex, JBIG2Bitmap *pBitmap) { m_ppBitmaps[unIndex] = pBitmap; } JBIG2Bitmap *GetBitmap(unsigned int unIndex) { return m_ppBitmaps[unIndex]; } void SetGenericRegionStats(JArithmeticDecoderStats *pStats) { m_pGenericRegionStats = pStats; } void SetRefinementRegionStats(JArithmeticDecoderStats *pStats) { m_pRefinementRegionStats = pStats; } JArithmeticDecoderStats *GetGenericRegionStats() { return m_pGenericRegionStats; } JArithmeticDecoderStats *GetRefinementRegionStats() { return m_pRefinementRegionStats; } private: unsigned int m_unSize; JBIG2Bitmap **m_ppBitmaps; JArithmeticDecoderStats *m_pGenericRegionStats; JArithmeticDecoderStats *m_pRefinementRegionStats; }; //------------------------------------------------------------------------ // JBIG2PatternDict //------------------------------------------------------------------------ class JBIG2PatternDict : public JBIG2Segment { public: JBIG2PatternDict(unsigned int unSegNum, unsigned int unSize) : JBIG2Segment(unSegNum) { m_unSize = unSize; m_ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(m_unSize, sizeof(JBIG2Bitmap *)); } virtual ~JBIG2PatternDict() { for (unsigned int unIndex = 0; unIndex < m_unSize; ++unIndex) { delete m_ppBitmaps[unIndex]; } MemUtilsFree(m_ppBitmaps); } virtual JBIG2SegmentType GetType() { return jbig2SegPatternDict; } unsigned int GetSize() { return m_unSize; } void SetBitmap(unsigned int unIndex, JBIG2Bitmap *pBitmap) { m_ppBitmaps[unIndex] = pBitmap; } JBIG2Bitmap *GetBitmap(unsigned int unIndex) { return m_ppBitmaps[unIndex]; } private: unsigned int m_unSize; JBIG2Bitmap **m_ppBitmaps; }; //------------------------------------------------------------------------ // JBIG2CodeTable //------------------------------------------------------------------------ class JBIG2CodeTable : public JBIG2Segment { public: JBIG2CodeTable(unsigned int unSegNum, JBIG2HuffmanTable *pTable) : JBIG2Segment(unSegNum) { m_pTable = pTable; } virtual ~JBIG2CodeTable() { MemUtilsFree(m_pTable); } virtual JBIG2SegmentType GetType() { return jbig2SegCodeTable; } JBIG2HuffmanTable *GetHuffTable() { return m_pTable; } private: JBIG2HuffmanTable *m_pTable; }; //------------------------------------------------------------------------ // JBIG2Stream //------------------------------------------------------------------------ JBIG2Stream::JBIG2Stream(Stream *pStream, Object *pGlobalsStream) : FilterStream(pStream) { m_pPageBitmap = NULL; m_pArithDecoder = new JArithmeticDecoder(); m_pGenericRegionStats = new JArithmeticDecoderStats(1 << 1); m_pRefinementRegionStats = new JArithmeticDecoderStats(1 << 1); m_pIadhStats = new JArithmeticDecoderStats(1 << 9); m_pIadwStats = new JArithmeticDecoderStats(1 << 9); m_pIaexStats = new JArithmeticDecoderStats(1 << 9); m_pIaaiStats = new JArithmeticDecoderStats(1 << 9); m_pIadtStats = new JArithmeticDecoderStats(1 << 9); m_pIaitStats = new JArithmeticDecoderStats(1 << 9); m_pIafsStats = new JArithmeticDecoderStats(1 << 9); m_pIadsStats = new JArithmeticDecoderStats(1 << 9); m_pIardxStats = new JArithmeticDecoderStats(1 << 9); m_pIardyStats = new JArithmeticDecoderStats(1 << 9); m_pIardwStats = new JArithmeticDecoderStats(1 << 9); m_pIardhStats = new JArithmeticDecoderStats(1 << 9); m_pIariStats = new JArithmeticDecoderStats(1 << 9); m_pIaidStats = new JArithmeticDecoderStats(1 << 1); m_pHuffDecoder = new JBIG2HuffmanDecoder(); m_pMMrDecoder = new JBIG2MMRDecoder(); pGlobalsStream->Copy(&m_oGlobalsStream); m_pSegments = m_pGlobalSegments = NULL; m_pCurStream = NULL; m_pDataPtr = m_pDataEnd = NULL; } JBIG2Stream::~JBIG2Stream() { Close(); m_oGlobalsStream.Free(); delete m_pArithDecoder; delete m_pGenericRegionStats; delete m_pRefinementRegionStats; delete m_pIadhStats; delete m_pIadwStats; delete m_pIaexStats; delete m_pIaaiStats; delete m_pIadtStats; delete m_pIaitStats; delete m_pIafsStats; delete m_pIadsStats; delete m_pIardxStats; delete m_pIardyStats; delete m_pIardwStats; delete m_pIardhStats; delete m_pIariStats; delete m_pIaidStats; delete m_pHuffDecoder; delete m_pMMrDecoder; delete m_pStream; } void JBIG2Stream::Reset() { // read the globals stream m_pGlobalSegments = new CList(); if (m_oGlobalsStream.IsStream()) { m_pSegments = m_pGlobalSegments; m_pCurStream = m_oGlobalsStream.GetStream(); m_pCurStream->Reset(); m_pArithDecoder->SetStream(m_pCurStream); m_pHuffDecoder->SetStream(m_pCurStream); m_pMMrDecoder->SetStream(m_pCurStream); ReadSegments(); m_pCurStream->Close(); } // read the main stream m_pSegments = new CList(); m_pCurStream = m_pStream; m_pCurStream->Reset(); m_pArithDecoder->SetStream(m_pCurStream); m_pHuffDecoder->SetStream(m_pCurStream); m_pMMrDecoder->SetStream(m_pCurStream); ReadSegments(); if (m_pPageBitmap) { m_pDataPtr = m_pPageBitmap->GetDataPtr(); m_pDataEnd = m_pDataPtr + m_pPageBitmap->GetDataSize(); } else { m_pDataPtr = m_pDataEnd = NULL; } } void JBIG2Stream::Close() { if (m_pPageBitmap) { delete m_pPageBitmap; m_pPageBitmap = NULL; } if (m_pSegments) { DeleteCList(m_pSegments, JBIG2Segment); m_pSegments = NULL; } if (m_pGlobalSegments) { DeleteCList(m_pGlobalSegments, JBIG2Segment); m_pGlobalSegments = NULL; } m_pDataPtr = m_pDataEnd = NULL; FilterStream::Close(); } int JBIG2Stream::GetChar() { if (m_pDataPtr && m_pDataPtr < m_pDataEnd) { return (*m_pDataPtr++ ^ 0xff) & 0xff; } return EOF; } int JBIG2Stream::LookChar() { if (m_pDataPtr && m_pDataPtr < m_pDataEnd) { return (*m_pDataPtr ^ 0xff) & 0xff; } return EOF; } StringExt *JBIG2Stream::GetPSFilter(int nPSLevel, char *sIndent) { return NULL; } bool JBIG2Stream::IsBinary(bool bLast) { return m_pStream->IsBinary(true); } void JBIG2Stream::ReadSegments() { unsigned int unSegNum; while (ReadULong(&unSegNum)) { // segment header flags unsigned int unSegFlags; if (!ReadUByte(&unSegFlags)) { return; } unsigned int unSegType = unSegFlags & 0x3f; // referred-to segment count and retention flags unsigned int unRefFlags; if (!ReadUByte(&unRefFlags)) { return; } unsigned int unRefSegsCount = unRefFlags >> 5; if (7 == unRefSegsCount) { int nChar1, nChar2, nChar3; if (EOF == (nChar1 = m_pCurStream->GetChar()) || EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar())) { return; } unRefFlags = (unRefFlags << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3; unRefSegsCount = unRefFlags & 0x1fffffff; for (unsigned int unIndex = 0; unIndex < (unRefSegsCount + 9) >> 3; ++unIndex) { nChar1 = m_pCurStream->GetChar(); } } // referred-to segment numbers unsigned int *punRefSegs = (unsigned int *)MemUtilsMallocArray(unRefSegsCount, sizeof(unsigned int)); if (unSegNum <= 256) { for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex) { if (!ReadUByte(&punRefSegs[unIndex])) { MemUtilsFree(punRefSegs); return; } } } else if (unSegNum <= 65536) { for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex) { if (!ReadUWord(&punRefSegs[unIndex])) { MemUtilsFree(punRefSegs); return; } } } else { for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex) { if (!ReadULong(&punRefSegs[unIndex])) { MemUtilsFree(punRefSegs); return; } } } // segment page association unsigned int unPage; if (unSegFlags & 0x40) { if (!ReadULong(&unPage)) { MemUtilsFree(punRefSegs); return; } } else { if (!ReadUByte(&unPage)) { MemUtilsFree(punRefSegs); return; } } // segment data length unsigned int unSegLength; if (!ReadULong(&unSegLength)) { MemUtilsFree(punRefSegs); return; } unsigned int unDataStartPos = m_pCurStream->GetPos(); // read the segment data switch (unSegType) { case 0: if (!ReadSymbolDictSegment(unSegNum, unSegLength, punRefSegs, unRefSegsCount)) { MemUtilsFree(punRefSegs); return; } break; case 4: ReadTextRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount); break; case 6: ReadTextRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount); break; case 7: ReadTextRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount); break; case 16: ReadPatternDictSegment(unSegNum, unSegLength); break; case 20: ReadHalftoneRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount); break; case 22: ReadHalftoneRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount); break; case 23: ReadHalftoneRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount); break; case 36: ReadGenericRegionSegment(unSegNum, false, false, unSegLength); break; case 38: ReadGenericRegionSegment(unSegNum, true, false, unSegLength); break; case 39: ReadGenericRegionSegment(unSegNum, true, true, unSegLength); break; case 40: ReadGenericRefinementRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount); break; case 42: ReadGenericRefinementRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount); break; case 43: ReadGenericRefinementRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount); break; case 48: ReadPageInfoSegment(unSegLength); break; case 50: ReadEndOfStripeSegment(unSegLength); break; case 52: ReadProfilesSegment(unSegLength); break; case 53: ReadCodeTableSegment(unSegNum, unSegLength); break; case 62: ReadExtensionSegment(unSegLength); break; default: for (unsigned int unIndex = 0; unIndex < unSegLength; ++unIndex) { int nChar; if (EOF == (nChar = m_pCurStream->GetChar())) { MemUtilsFree(punRefSegs); return; } } break; } MemUtilsFree(punRefSegs); if (m_pCurStream->GetPos() - unDataStartPos != unSegLength) m_pCurStream->SetPos(unDataStartPos + unSegLength); } return; } bool JBIG2Stream::ReadSymbolDictSegment(unsigned int unSegNum, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount) { // symbol dictionary flags unsigned int unFlags; if (!ReadUWord(&unFlags)) { return false; } unsigned int unHuff = unFlags & 1; unsigned int unRefAgg = (unFlags >> 1) & 1; unsigned int unHuffDH = (unFlags >> 2) & 3; unsigned int unHuffDW = (unFlags >> 4) & 3; unsigned int unHuffBMSize = (unFlags >> 6) & 1; unsigned int unHuffAggInst = (unFlags >> 7) & 1; unsigned int unContextUsed = (unFlags >> 8) & 1; unsigned int unContextRetained = (unFlags >> 9) & 1; unsigned int unSDTemplate = (unFlags >> 10) & 3; unsigned int unSDRTemplate = (unFlags >> 12) & 1; // symbol dictionary AT flags int arrSDATx[4], arrSDATy[4]; if (!unHuff) { if (unSDTemplate == 0) { if (!ReadByte(&arrSDATx[0]) || !ReadByte(&arrSDATy[0]) || !ReadByte(&arrSDATx[1]) || !ReadByte(&arrSDATy[1]) || !ReadByte(&arrSDATx[2]) || !ReadByte(&arrSDATy[2]) || !ReadByte(&arrSDATx[3]) || !ReadByte(&arrSDATy[3])) { return false; } } else { if (!ReadByte(&arrSDATx[0]) || !ReadByte(&arrSDATy[0])) { return false; } } } // symbol dictionary refinement AT flags int arrSDRATx[2], arrSDRATy[2]; if (unRefAgg && !unSDRTemplate) { if (!ReadByte(&arrSDRATx[0]) || !ReadByte(&arrSDRATy[0]) || !ReadByte(&arrSDRATx[1]) || !ReadByte(&arrSDRATy[1])) { return false; } } // SDNUMEXSYMS and SDNUMNEWSYMS unsigned int unNumExSyms, unNumNewSyms; if (!ReadULong(&unNumExSyms) || !ReadULong(&unNumNewSyms)) { return false; } // get referenced segments: input symbol dictionaries and code tables CList *pCodeTables = new CList(); unsigned int unNumInputSyms = 0, unI; for (unI = 0; unI < unRefSegsCount; ++unI) { JBIG2Segment *pSegment = FindSegment(punRefSegs[unI]); if (pSegment->GetType() == jbig2SegSymbolDict) { unNumInputSyms += ((JBIG2SymbolDict *)pSegment)->GetSize(); } else if (pSegment->GetType() == jbig2SegCodeTable) { pCodeTables->Append(pSegment); } } // compute symbol code length unsigned int unSymCodeLen = 0; unI = 1; while (unI < unNumInputSyms + unNumNewSyms) { ++unSymCodeLen; unI <<= 1; } // get the input symbol bitmaps JBIG2Bitmap **ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(unNumInputSyms + unNumNewSyms, sizeof(JBIG2Bitmap *)); for (unI = 0; unI < unNumInputSyms + unNumNewSyms; ++unI) { ppBitmaps[unI] = NULL; } unsigned int unK = 0, unJ; JBIG2SymbolDict *pInputSymbolDict = NULL; for (unI = 0; unI < unRefSegsCount; ++unI) { JBIG2Segment *pSegment = FindSegment(punRefSegs[unI]); if (pSegment->GetType() == jbig2SegSymbolDict) { pInputSymbolDict = (JBIG2SymbolDict *)pSegment; for (unJ = 0; unJ < pInputSymbolDict->GetSize(); ++unJ) { ppBitmaps[unK++] = pInputSymbolDict->GetBitmap(unJ); } } } // get the Huffman tables JBIG2HuffmanTable *pHuffDHTable = NULL, *pHuffDWTable = NULL, *pHuffBMSizeTable = NULL, *pHuffAggInstTable = NULL; unI = 0; if (unHuff) { if (unHuffDH == 0) { pHuffDHTable = c_oHuffTableD; } else if (unHuffDH == 1) { pHuffDHTable = c_oHuffTableE; } else { pHuffDHTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable(); } if (unHuffDW == 0) { pHuffDWTable = c_oHuffTableB; } else if (unHuffDW == 1) { pHuffDWTable = c_oHuffTableC; } else { pHuffDWTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable(); } if (unHuffBMSize == 0) { pHuffBMSizeTable = c_oHuffTableA; } else { pHuffBMSizeTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable(); } if (unHuffAggInst == 0) { pHuffAggInstTable = c_oHuffTableA; } else { pHuffAggInstTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable(); } } delete pCodeTables; // set up the Huffman decoder if (unHuff) { m_pHuffDecoder->Reset(); } else // set up the arithmetic decoder { if (unContextUsed && pInputSymbolDict) { ResetGenericStats(unSDTemplate, pInputSymbolDict->GetGenericRegionStats()); } else { ResetGenericStats(unSDTemplate, NULL); } ResetIntStats(unSymCodeLen); m_pArithDecoder->Start(); } // set up the arithmetic decoder for refinement/aggregation if (unRefAgg) { if (unContextUsed && pInputSymbolDict) { ResetRefinementStats(unSDRTemplate, pInputSymbolDict->GetRefinementRegionStats()); } else { ResetRefinementStats(unSDRTemplate, NULL); } } // allocate symbol widths storage unsigned int *pSymWidths = NULL; if (unHuff && !unRefAgg) { pSymWidths = (unsigned int *)MemUtilsMallocArray(unNumNewSyms, sizeof(unsigned int)); } unsigned int unSymHeight = 0; unI = 0; while (unI < unNumNewSyms) { // read the height class delta height int nDh; if (unHuff) { m_pHuffDecoder->DecodeInt(&nDh, pHuffDHTable); } else { m_pArithDecoder->DecodeInt(&nDh, m_pIadhStats); } if (nDh < 0 && (unsigned int)-nDh >= unSymHeight) { // SyntaxError for (unsigned int unIndex = 0; unIndex < unNumNewSyms; ++unIndex) { if (ppBitmaps[unNumInputSyms + unIndex]) { delete ppBitmaps[unNumInputSyms + unIndex]; } } MemUtilsFree(ppBitmaps); if (pSymWidths) { MemUtilsFree(pSymWidths); } return false; } unSymHeight += nDh; unsigned int unSymWidth = 0, unTotalWidth = 0; unJ = unI; // read the symbols in this height class while (1) { // read the delta width int nDw; if (unHuff) { if (!m_pHuffDecoder->DecodeInt(&nDw, pHuffDWTable)) { break; } } else { if (!m_pArithDecoder->DecodeInt(&nDw, m_pIadwStats)) { break; } } if (nDw < 0 && (unsigned int)-nDw >= unSymWidth) { // SyntaxError for (unsigned int unIndex = 0; unIndex < unNumNewSyms; ++unIndex) { if (ppBitmaps[unNumInputSyms + unIndex]) { delete ppBitmaps[unNumInputSyms + unIndex]; } } MemUtilsFree(ppBitmaps); if (pSymWidths) { MemUtilsFree(pSymWidths); } return false; } unSymWidth += nDw; // using a collective bitmap, so don't read a bitmap here if (unHuff && !unRefAgg) { pSymWidths[unI] = unSymWidth; unTotalWidth += unSymWidth; } else if (unRefAgg) // refinement/aggregate coding { int nRefAggNum; if (unHuff) { if (!m_pHuffDecoder->DecodeInt(&nRefAggNum, pHuffAggInstTable)) { break; } } else { if (!m_pArithDecoder->DecodeInt(&nRefAggNum, m_pIaaiStats)) { break; } } #if 0 //~ This special case was added about a year before the final draft //~ of the JBIG2 spec was released. I have encountered some old //~ JBIG2 images that predate it. if ( 0 ) { #else if (nRefAggNum == 1) { #endif unsigned int unSymID; int nRefDX, nRefDY, nBMSize; if (unHuff) { unSymID = m_pHuffDecoder->ReadBits(unSymCodeLen); m_pHuffDecoder->DecodeInt(&nRefDX, c_oHuffTableO); m_pHuffDecoder->DecodeInt(&nRefDY, c_oHuffTableO); m_pHuffDecoder->DecodeInt(&nBMSize, c_oHuffTableA); m_pHuffDecoder->Reset(); m_pArithDecoder->Start(); } else { unSymID = m_pArithDecoder->DecodeIAID(unSymCodeLen, m_pIaidStats); m_pArithDecoder->DecodeInt(&nRefDX, m_pIardxStats); m_pArithDecoder->DecodeInt(&nRefDY, m_pIardyStats); } JBIG2Bitmap *pRefBitmap = ppBitmaps[unSymID]; ppBitmaps[unNumInputSyms + unI] = ReadGenericRefinementRegion(unSymWidth, unSymHeight, unSDRTemplate, false, pRefBitmap, nRefDX, nRefDY, arrSDRATx, arrSDRATy); } else //~ do we need to use the bmSize value here (in Huffman mode)? { ppBitmaps[unNumInputSyms + unI] = ReadTextRegion(unHuff ? true : false, true, unSymWidth, unSymHeight, nRefAggNum, 0, unNumInputSyms + unI, NULL, unSymCodeLen, ppBitmaps, 0, 0, 0, 1, 0, c_oHuffTableF, c_oHuffTableH, c_oHuffTableK, c_oHuffTableO, c_oHuffTableO, c_oHuffTableO, c_oHuffTableO, c_oHuffTableA, unSDRTemplate, arrSDRATx, arrSDRATy); } } else // non-ref/agg coding { ppBitmaps[unNumInputSyms + unI] = ReadGenericBitmap(false, unSymWidth, unSymHeight, unSDTemplate, false, false, NULL, arrSDATx, arrSDATy, 0); } ++unI; } // read the collective bitmap if (unHuff && !unRefAgg) { int nBMSize; m_pHuffDecoder->DecodeInt(&nBMSize, pHuffBMSizeTable); m_pHuffDecoder->Reset(); JBIG2Bitmap *pCollBitmap; if (nBMSize == 0) { pCollBitmap = new JBIG2Bitmap(0, unTotalWidth, unSymHeight); nBMSize = unSymHeight * ((unTotalWidth + 7) >> 3); unsigned char *pDataPtr = pCollBitmap->GetDataPtr(); for (unK = 0; unK < (unsigned int)nBMSize; ++unK) { *pDataPtr++ = m_pCurStream->GetChar(); } } else { pCollBitmap = ReadGenericBitmap(true, unTotalWidth, unSymHeight, 0, false, false, NULL, NULL, NULL, nBMSize); } unsigned int unX = 0; for (; unJ < unI; ++unJ) { ppBitmaps[unNumInputSyms + unJ] = pCollBitmap->GetSlice(unX, 0, pSymWidths[unJ], unSymHeight); unX += pSymWidths[unJ]; } delete pCollBitmap; } } // create the symbol dict object JBIG2SymbolDict *pSymbolDict = new JBIG2SymbolDict(unSegNum, unNumExSyms); // exported symbol list unI = unJ = 0; bool bEx = false; while (unI < unNumInputSyms + unNumNewSyms) { int nRun; if (unHuff) { m_pHuffDecoder->DecodeInt(&nRun, c_oHuffTableA); } else { m_pArithDecoder->DecodeInt(&nRun, m_pIaexStats); } if (bEx) { for (int nCounter = 0; nCounter < nRun; ++nCounter) { pSymbolDict->SetBitmap(unJ++, ppBitmaps[unI++]->Copy()); } } else { unI += nRun; } bEx = !bEx; } for (unI = 0; unI < unNumNewSyms; ++unI) { delete ppBitmaps[unNumInputSyms + unI]; } MemUtilsFree(ppBitmaps); if (pSymWidths) { MemUtilsFree(pSymWidths); } // save the arithmetic decoder stats if (!unHuff && unContextRetained) { pSymbolDict->SetGenericRegionStats(m_pGenericRegionStats->Copy()); if (unRefAgg) { pSymbolDict->SetRefinementRegionStats(m_pRefinementRegionStats->Copy()); } } // store the new symbol dict m_pSegments->Append(pSymbolDict); return true; } void JBIG2Stream::ReadTextRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount) { // region segment info field unsigned int unW, unH, unX, unY, unSegInfoFlags; if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags)) { return; } unsigned int unExtCombOp = unSegInfoFlags & 7; // rest of the text region header unsigned int unFlags; if (!ReadUWord(&unFlags)) { return; } unsigned int unHuff = unFlags & 1; unsigned int unRefine = (unFlags >> 1) & 1; unsigned int unLogStrips = (unFlags >> 2) & 3; unsigned int unRefCorner = (unFlags >> 4) & 3; unsigned int unTransposed = (unFlags >> 6) & 1; unsigned int unCombOp = (unFlags >> 7) & 3; unsigned int unDefPixel = (unFlags >> 9) & 1; int nSOffset = (unFlags >> 10) & 0x1f; unsigned int unTempl = (unFlags >> 15) & 1; if (nSOffset & 0x10) { nSOffset |= -1 - 0x0f; } unsigned int unHuffFS = 0, unHuffDS = 0, unHuffDT = 0, unHuffRDW = 0, unHuffRDH = 0, unHuffRDX = 0, unHuffRDY = 0, unHuffRSize = 0; if (unHuff) { unsigned int unHuffFlags; if (!ReadUWord(&unHuffFlags)) { return; } unHuffFS = unHuffFlags & 3; unHuffDS = (unHuffFlags >> 2) & 3; unHuffDT = (unHuffFlags >> 4) & 3; unHuffRDW = (unHuffFlags >> 6) & 3; unHuffRDH = (unHuffFlags >> 8) & 3; unHuffRDX = (unHuffFlags >> 10) & 3; unHuffRDY = (unHuffFlags >> 12) & 3; unHuffRSize = (unHuffFlags >> 14) & 1; } int arrATx[2], arrATy[2]; if (unRefine && unTempl == 0) { if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1])) { return; } } unsigned int unNumInstances; if (!ReadULong(&unNumInstances)) { return; } // get symbol dictionaries and tables CList *pCodeTables = new CList(); unsigned int unNumSyms = 0; unsigned int unIndex; for (unIndex = 0; unIndex < unRefSegsCount; ++unIndex) { JBIG2Segment *pSegment = NULL; if ((pSegment = FindSegment(punRefSegs[unIndex]))) { if (pSegment->GetType() == jbig2SegSymbolDict) { unNumSyms += ((JBIG2SymbolDict *)pSegment)->GetSize(); } else if (pSegment->GetType() == jbig2SegCodeTable) { pCodeTables->Append(pSegment); } } else { } } unsigned int unSymCodeLen = 0; unIndex = 1; while (unIndex < unNumSyms) { ++unSymCodeLen; unIndex <<= 1; } // get the symbol bitmaps JBIG2Bitmap **ppSyms = (JBIG2Bitmap **)MemUtilsMallocArray(unNumSyms, sizeof(JBIG2Bitmap *)); unsigned int unSymsIndex = 0; for (unIndex = 0; unIndex < unRefSegsCount; ++unIndex) { JBIG2Segment *pSegment = NULL; if ((pSegment = FindSegment(punRefSegs[unIndex]))) { if (pSegment->GetType() == jbig2SegSymbolDict) { JBIG2SymbolDict *pSymbolDict = (JBIG2SymbolDict *)pSegment; for (unsigned int unK = 0; unK < pSymbolDict->GetSize(); ++unK) { ppSyms[unSymsIndex++] = pSymbolDict->GetBitmap(unK); } } } } // get the Huffman tables JBIG2HuffmanTable *pHuffFSTable = NULL, *pHuffDSTable = NULL, *pHuffDTTable = NULL, *pHuffRDWTable = NULL, *pHuffRDHTable = NULL, *pHuffRDXTable = NULL, *pHuffRDYTable = NULL, *pHuffRSizeTable = NULL; unIndex = 0; if (unHuff) { if (unHuffFS == 0) { pHuffFSTable = c_oHuffTableF; } else if (unHuffFS == 1) { pHuffFSTable = c_oHuffTableG; } else { pHuffFSTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffDS == 0) { pHuffDSTable = c_oHuffTableH; } else if (unHuffDS == 1) { pHuffDSTable = c_oHuffTableI; } else if (unHuffDS == 2) { pHuffDSTable = c_oHuffTableJ; } else { pHuffDSTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffDT == 0) { pHuffDTTable = c_oHuffTableK; } else if (unHuffDT == 1) { pHuffDTTable = c_oHuffTableL; } else if (unHuffDT == 2) { pHuffDTTable = c_oHuffTableM; } else { pHuffDTTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffRDW == 0) { pHuffRDWTable = c_oHuffTableN; } else if (unHuffRDW == 1) { pHuffRDWTable = c_oHuffTableO; } else { pHuffRDWTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffRDH == 0) { pHuffRDHTable = c_oHuffTableN; } else if (unHuffRDH == 1) { pHuffRDHTable = c_oHuffTableO; } else { pHuffRDHTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffRDX == 0) { pHuffRDXTable = c_oHuffTableN; } else if (unHuffRDX == 1) { pHuffRDXTable = c_oHuffTableO; } else { pHuffRDXTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffRDY == 0) { pHuffRDYTable = c_oHuffTableN; } else if (unHuffRDY == 1) { pHuffRDYTable = c_oHuffTableO; } else { pHuffRDYTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } if (unHuffRSize == 0) { pHuffRSizeTable = c_oHuffTableA; } else { pHuffRSizeTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable(); } } delete pCodeTables; // symbol ID Huffman decoding table JBIG2HuffmanTable *pSymCodeTab; if (unHuff) { m_pHuffDecoder->Reset(); JBIG2HuffmanTable arrRunLengthTab[36]; for (unIndex = 0; unIndex < 32; ++unIndex) { arrRunLengthTab[unIndex].nValue = unIndex; arrRunLengthTab[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(4); arrRunLengthTab[unIndex].unRangeLen = 0; } arrRunLengthTab[32].nValue = 0x103; arrRunLengthTab[32].unPrefixLen = m_pHuffDecoder->ReadBits(4); arrRunLengthTab[32].unRangeLen = 2; arrRunLengthTab[33].nValue = 0x203; arrRunLengthTab[33].unPrefixLen = m_pHuffDecoder->ReadBits(4); arrRunLengthTab[33].unRangeLen = 3; arrRunLengthTab[34].nValue = 0x20b; arrRunLengthTab[34].unPrefixLen = m_pHuffDecoder->ReadBits(4); arrRunLengthTab[34].unRangeLen = 7; arrRunLengthTab[35].unPrefixLen = 0; arrRunLengthTab[35].unRangeLen = jbig2HuffmanEOT; m_pHuffDecoder->BuildTable(arrRunLengthTab, 35); pSymCodeTab = (JBIG2HuffmanTable *)MemUtilsMallocArray(unNumSyms + 1, sizeof(JBIG2HuffmanTable)); for (unIndex = 0; unIndex < unNumSyms; ++unIndex) { pSymCodeTab[unIndex].nValue = unIndex; pSymCodeTab[unIndex].unRangeLen = 0; } unIndex = 0; int nJ; while (unIndex < unNumSyms) { m_pHuffDecoder->DecodeInt(&nJ, arrRunLengthTab); if (nJ > 0x200) { for (nJ -= 0x200; nJ && unIndex < unNumSyms; --nJ) { pSymCodeTab[unIndex++].unPrefixLen = 0; } } else if (nJ > 0x100) { for (nJ -= 0x100; nJ && unIndex < unNumSyms; --nJ) { pSymCodeTab[unIndex].unPrefixLen = pSymCodeTab[unIndex - 1].unPrefixLen; ++unIndex; } } else { pSymCodeTab[unIndex++].unPrefixLen = nJ; } } pSymCodeTab[unNumSyms].unPrefixLen = 0; pSymCodeTab[unNumSyms].unRangeLen = jbig2HuffmanEOT; m_pHuffDecoder->BuildTable(pSymCodeTab, unNumSyms); m_pHuffDecoder->Reset(); } else // set up the arithmetic decoder { pSymCodeTab = NULL; ResetIntStats(unSymCodeLen); m_pArithDecoder->Start(); } if (unRefine) { ResetRefinementStats(unTempl, NULL); } JBIG2Bitmap *pBitmap = ReadTextRegion(unHuff ? true : false, unRefine ? true : false, unW, unH, unNumInstances, unLogStrips, unNumSyms, pSymCodeTab, unSymCodeLen, ppSyms, unDefPixel, unCombOp, unTransposed, unRefCorner, nSOffset, pHuffFSTable, pHuffDSTable, pHuffDTTable, pHuffRDWTable, pHuffRDHTable, pHuffRDXTable, pHuffRDYTable, pHuffRSizeTable, unTempl, arrATx, arrATy); MemUtilsFree(ppSyms); // combine the region bitmap into the page bitmap if (bImm) { if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH) { m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel); } m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp); delete pBitmap; } else // store the region bitmap { pBitmap->SetSegNum(unSegNum); m_pSegments->Append(pBitmap); } // clean up the Huffman decoder if (unHuff) { MemUtilsFree(pSymCodeTab); } return; } JBIG2Bitmap *JBIG2Stream::ReadTextRegion(bool bHuff, bool bRefine, int nW, int nH, unsigned int unNumInstances, unsigned int unLogStrips, int nNumSyms, JBIG2HuffmanTable *pSymCodeTab, unsigned int unSymCodeLen, JBIG2Bitmap **ppSyms, unsigned int unDefPixel, unsigned int unCombOp, unsigned int transposed, unsigned int refCorner, int nSOffset, JBIG2HuffmanTable *pHuffFSTable, JBIG2HuffmanTable *pHuffDSTable, JBIG2HuffmanTable *pHuffDTTable, JBIG2HuffmanTable *pHuffRDWTable, JBIG2HuffmanTable *pHuffRDHTable, JBIG2HuffmanTable *pHuffRDXTable, JBIG2HuffmanTable *pHuffRDYTable, JBIG2HuffmanTable *pHuffRSizeTable, unsigned int unTempl, int *pnATx, int *pnATy) { unsigned int unStrips = 1 << unLogStrips; // allocate the bitmap JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH); if (unDefPixel) { pBitmap->ClearToOne(); } else { pBitmap->ClearToZero(); } // decode initial T value int nT; if (bHuff) { m_pHuffDecoder->DecodeInt(&nT, pHuffDTTable); } else { m_pArithDecoder->DecodeInt(&nT, m_pIadtStats); } nT *= -(int)unStrips; unsigned int unInstance = 0; int nSFirst = 0; while (unInstance < unNumInstances) { // decode delta-T int nDeltaT; if (bHuff) { m_pHuffDecoder->DecodeInt(&nDeltaT, pHuffDTTable); } else { m_pArithDecoder->DecodeInt(&nDeltaT, m_pIadtStats); } nT += nDeltaT * unStrips; // first S value int nDS; if (bHuff) { m_pHuffDecoder->DecodeInt(&nDS, pHuffFSTable); } else { m_pArithDecoder->DecodeInt(&nDS, m_pIafsStats); } nSFirst += nDS; int nCurS = nSFirst; // read the instances while (1) { // T value if (1 == unStrips) { nDeltaT = 0; } else if (bHuff) { nDeltaT = m_pHuffDecoder->ReadBits(unLogStrips); } else { m_pArithDecoder->DecodeInt(&nDeltaT, m_pIaitStats); } int nCurT = nT + nDeltaT; // symbol ID unsigned int unSymID; if (bHuff) { if (pSymCodeTab) { int nTemp; m_pHuffDecoder->DecodeInt(&nTemp, pSymCodeTab); unSymID = (unsigned int)nTemp; } else { unSymID = m_pHuffDecoder->ReadBits(unSymCodeLen); } } else { unSymID = m_pArithDecoder->DecodeIAID(unSymCodeLen, m_pIaidStats); } if (unSymID >= (unsigned int)nNumSyms) { } else { // get the symbol bitmap JBIG2Bitmap *pSymbolBitmap = NULL; int nReadInt; if (bRefine) { if (bHuff) { nReadInt = (int)m_pHuffDecoder->ReadBit(); } else { m_pArithDecoder->DecodeInt(&nReadInt, m_pIariStats); } } else { nReadInt = 0; } if (nReadInt) { int nRDW, nRDH, nRDX, nRDY, nBMSize; if (bHuff) { m_pHuffDecoder->DecodeInt(&nRDW, pHuffRDWTable); m_pHuffDecoder->DecodeInt(&nRDH, pHuffRDHTable); m_pHuffDecoder->DecodeInt(&nRDX, pHuffRDXTable); m_pHuffDecoder->DecodeInt(&nRDY, pHuffRDYTable); m_pHuffDecoder->DecodeInt(&nBMSize, pHuffRSizeTable); m_pHuffDecoder->Reset(); m_pArithDecoder->Start(); } else { m_pArithDecoder->DecodeInt(&nRDW, m_pIardwStats); m_pArithDecoder->DecodeInt(&nRDH, m_pIardhStats); m_pArithDecoder->DecodeInt(&nRDX, m_pIardxStats); m_pArithDecoder->DecodeInt(&nRDY, m_pIardyStats); } int nRefDX = ((nRDW >= 0) ? nRDW : nRDW - 1) / 2 + nRDX; int nRefDY = ((nRDH >= 0) ? nRDH : nRDH - 1) / 2 + nRDY; pSymbolBitmap = ReadGenericRefinementRegion(nRDW + ppSyms[unSymID]->GetWidth(), nRDH + ppSyms[unSymID]->GetHeight(), unTempl, false, ppSyms[unSymID], nRefDX, nRefDY, pnATx, pnATy); } else //~ do we need to use the bmSize value here (in Huffman mode)? { pSymbolBitmap = ppSyms[unSymID]; } // combine the symbol bitmap into the region bitmap //~ something is wrong here - refCorner shouldn't degenerate into //~ two cases unsigned int unBitmapW = pSymbolBitmap->GetWidth() - 1; unsigned int unBitmapH = pSymbolBitmap->GetHeight() - 1; if (transposed) { switch (refCorner) { case 0: // bottom left pBitmap->Combine(pSymbolBitmap, nCurT, nCurS, unCombOp); break; case 1: // top left pBitmap->Combine(pSymbolBitmap, nCurT, nCurS, unCombOp); break; case 2: // bottom right pBitmap->Combine(pSymbolBitmap, nCurT - unBitmapW, nCurS, unCombOp); break; case 3: // top right pBitmap->Combine(pSymbolBitmap, nCurT - unBitmapW, nCurS, unCombOp); break; } nCurS += unBitmapH; } else { switch (refCorner) { case 0: // bottom left pBitmap->Combine(pSymbolBitmap, nCurS, nCurT - unBitmapH, unCombOp); break; case 1: // top left pBitmap->Combine(pSymbolBitmap, nCurS, nCurT, unCombOp); break; case 2: // bottom right pBitmap->Combine(pSymbolBitmap, nCurS, nCurT - unBitmapH, unCombOp); break; case 3: // top right pBitmap->Combine(pSymbolBitmap, nCurS, nCurT, unCombOp); break; } nCurS += unBitmapW; } if (nReadInt) { delete pSymbolBitmap; } } // next instance ++unInstance; // next S value if (bHuff) { if (!m_pHuffDecoder->DecodeInt(&nDS, pHuffDSTable)) { break; } } else { if (!m_pArithDecoder->DecodeInt(&nDS, m_pIadsStats)) { break; } } nCurS += nSOffset + nDS; } } return pBitmap; } void JBIG2Stream::ReadPatternDictSegment(unsigned int unSegNum, unsigned int unLength) { // halftone dictionary flags, pattern width and height, max gray value unsigned int unFlags, unPatternW, unPatternH, unGrayMax; if (!ReadUByte(&unFlags) || !ReadUByte(&unPatternW) || !ReadUByte(&unPatternH) || !ReadULong(&unGrayMax)) { return; } unsigned int unTempl = (unFlags >> 1) & 3; unsigned int unMMR = unFlags & 1; // set up the arithmetic decoder if (!unMMR) { ResetGenericStats(unTempl, NULL); m_pArithDecoder->Start(); } // read the bitmap int arrATx[4], arrATy[4]; arrATx[0] = -(int)unPatternW; arrATy[0] = 0; arrATx[1] = -3; arrATy[1] = -1; arrATx[2] = 2; arrATy[2] = -2; arrATx[3] = -2; arrATy[3] = -2; JBIG2Bitmap *pBitmap = ReadGenericBitmap(unMMR ? true : false, (unGrayMax + 1) * unPatternW, unPatternH, unTempl, false, false, NULL, arrATx, arrATy, unLength - 7); // create the pattern dict object JBIG2PatternDict *pPatternDict = new JBIG2PatternDict(unSegNum, unGrayMax + 1); // split up the bitmap unsigned int unX = 0; for (unsigned int unIndex = 0; unIndex <= unGrayMax; ++unIndex) { pPatternDict->SetBitmap(unIndex, pBitmap->GetSlice(unX, 0, unPatternW, unPatternH)); unX += unPatternW; } // free memory delete pBitmap; // store the new pattern dict m_pSegments->Append(pPatternDict); return; } void JBIG2Stream::ReadHalftoneRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount) { // region segment info field unsigned int unW, unH, unX, unY, unSegInfoFlags; if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags)) { return; } unsigned int unExtCombOp = unSegInfoFlags & 7; // rest of the halftone region header unsigned int unFlags; if (!ReadUByte(&unFlags)) { return; } unsigned int unMMR = unFlags & 1; unsigned int unTempl = (unFlags >> 1) & 3; unsigned int unEnableSkip = (unFlags >> 3) & 1; unsigned int unCombOp = (unFlags >> 4) & 7; unsigned int unGridW, unGridH, unStepX, unStepY; int nGridX, nGridY; if (!ReadULong(&unGridW) || !ReadULong(&unGridH) || !ReadLong(&nGridX) || !ReadLong(&nGridY) || !ReadUWord(&unStepX) || !ReadUWord(&unStepY)) { return; } if (unW == 0 || unH == 0 || unW >= INT_MAX / unH) { return; } if (unGridH == 0 || unGridW >= INT_MAX / unGridH) { return; } // get pattern dictionary if (unRefSegsCount != 1) { return; } JBIG2Segment *pSegment = FindSegment(punRefSegs[0]); if (pSegment->GetType() != jbig2SegPatternDict) { return; } JBIG2PatternDict *pPatternDict = (JBIG2PatternDict *)pSegment; unsigned int unBPP = 0; unsigned int unIndex = 1; while (unIndex < pPatternDict->GetSize()) { ++unBPP; unIndex <<= 1; } unsigned int unPatternW = pPatternDict->GetBitmap(0)->GetWidth(); unsigned int unPatternH = pPatternDict->GetBitmap(0)->GetHeight(); // set up the arithmetic decoder if (!unMMR) { ResetGenericStats(unTempl, NULL); m_pArithDecoder->Start(); } // allocate the bitmap JBIG2Bitmap *pBitmap = new JBIG2Bitmap(unSegNum, unW, unH); if (unFlags & 0x80) // HDEFPIXEL { pBitmap->ClearToOne(); } else { pBitmap->ClearToZero(); } // compute the skip bitmap JBIG2Bitmap *pSkipBitmap = NULL; if (unEnableSkip) { pSkipBitmap = new JBIG2Bitmap(0, unGridW, unGridH); pSkipBitmap->ClearToZero(); for (unsigned int unM = 0; unM < unGridH; ++unM) { for (unsigned int unN = 0; unN < unGridW; ++unN) { int nCurX = nGridX + unM * unStepY + unN * unStepX; int nCurY = nGridY + unM * unStepX - unN * unStepY; if (((nCurX + (int)unPatternW) >> 8) <= 0 || (nCurX >> 8) >= (int)unW || ((nCurY + (int)unPatternH) >> 8) <= 0 || (nCurY >> 8) >= (int)unH) { pSkipBitmap->SetPixel(unN, unM); } } } } // read the gray-scale image unsigned int *pGrayImage = (unsigned int *)MemUtilsMallocArray(unGridW * unGridH, sizeof(unsigned int)); memset(pGrayImage, 0, unGridW * unGridH * sizeof(unsigned int)); int arrATx[4], arrATy[4]; arrATx[0] = unTempl <= 1 ? 3 : 2; arrATy[0] = -1; arrATx[1] = -3; arrATy[1] = -1; arrATx[2] = 2; arrATy[2] = -2; arrATx[3] = -2; arrATy[3] = -2; for (int nBitIndex = unBPP - 1; nBitIndex >= 0; --nBitIndex) { JBIG2Bitmap *pGrayBitmap = ReadGenericBitmap(0 != unMMR, unGridW, unGridH, unTempl, false, 0 != unEnableSkip, pSkipBitmap, arrATx, arrATy, -1); unIndex = 0; for (unsigned int unM = 0; unM < unGridH; ++unM) { for (unsigned int unN = 0; unN < unGridW; ++unN) { int nBit = pGrayBitmap->GetPixel(unN, unM) ^ (pGrayImage[unIndex] & 1); pGrayImage[unIndex] = (pGrayImage[unIndex] << 1) | nBit; ++unIndex; } } delete pGrayBitmap; } // decode the image unIndex = 0; for (unsigned int unM = 0; unM < unGridH; ++unM) { int nCurX = nGridX + unM * unStepY; int nCurY = nGridY + unM * unStepX; for (unsigned int unN = 0; unN < unGridW; ++unN) { if (!(unEnableSkip && pSkipBitmap->GetPixel(unN, unM))) { JBIG2Bitmap *pPatternBitmap = pPatternDict->GetBitmap(pGrayImage[unIndex]); pBitmap->Combine(pPatternBitmap, nCurX >> 8, nCurY >> 8, unCombOp); } nCurX += unStepX; nCurY -= unStepY; ++unIndex; } } MemUtilsFree(pGrayImage); if (pSkipBitmap) { delete pSkipBitmap; } // combine the region bitmap into the page bitmap if (bImm) { if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH) { m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel); } m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp); delete pBitmap; } else // store the region bitmap { m_pSegments->Append(pBitmap); } return; } void JBIG2Stream::ReadGenericRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength) { // region segment info field unsigned int unW, unH, unX, unY, unSegInfoFlags; if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags)) { return; } unsigned int unExtCombOp = unSegInfoFlags & 7; // rest of the generic region segment header unsigned int unFlags; if (!ReadUByte(&unFlags)) { return; } unsigned int unMMR = unFlags & 1; unsigned int unTempl = (unFlags >> 1) & 3; unsigned int unTpgdOn = (unFlags >> 3) & 1; // AT flags int arrATx[4], arrATy[4]; if (!unMMR) { if (unTempl == 0) { if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1]) || !ReadByte(&arrATx[2]) || !ReadByte(&arrATy[2]) || !ReadByte(&arrATx[3]) || !ReadByte(&arrATy[3])) { return; } } else { if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0])) { return; } } } // set up the arithmetic decoder if (!unMMR) { ResetGenericStats(unTempl, NULL); m_pArithDecoder->Start(); } // read the bitmap JBIG2Bitmap *pBitmap = ReadGenericBitmap(0 != unMMR, unW, unH, unTempl, 0 != unTpgdOn, false, NULL, arrATx, arrATy, unMMR ? 0 : unLength - 18); // combine the region bitmap into the page bitmap if (bImm) { if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH) { m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel); } m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp); delete pBitmap; } else // store the region bitmap { pBitmap->SetSegNum(unSegNum); m_pSegments->Append(pBitmap); } return; } JBIG2Bitmap *JBIG2Stream::ReadGenericBitmap(bool bMMR, int nW, int nH, int unTempl, bool bTpgdOn, bool bUseSkip, JBIG2Bitmap *pSkip, int *pnATx, int *pnATy, int nMMrDataLength) { JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH); pBitmap->ClearToZero(); if (bMMR) //----- MMR decode { m_pMMrDecoder->Reset(); int *pRefLine = (int *)MemUtilsMallocArray(nW + 2, sizeof(int)); int *pCodingLine = (int *)MemUtilsMallocArray(nW + 2, sizeof(int)); pCodingLine[0] = pCodingLine[1] = nW; for (int nY = 0; nY < nH; ++nY) { // copy coding line to ref line int nIndex; for (nIndex = 0; pCodingLine[nIndex] < nW; ++nIndex) { pRefLine[nIndex] = pCodingLine[nIndex]; } pRefLine[nIndex] = pRefLine[nIndex + 1] = nW; // decode a line int nRefIndex = 0; // nB1 = pRefLine[refI] int nCodingIndex = 0; // nA1 = pCodingLine[codingI] int nA0 = 0; do { int nCode1 = m_pMMrDecoder->Get2DCode(); switch (nCode1) { case Pass_2D: if (pRefLine[nRefIndex] < nW) { nA0 = pRefLine[nRefIndex + 1]; nRefIndex += 2; } break; case Horiz_2D: { int nCode2, nCode3; if (nCodingIndex & 1) { nCode1 = 0; do { nCode1 += nCode3 = m_pMMrDecoder->GetBlackCode(); } while (nCode3 >= 64); nCode2 = 0; do { nCode2 += nCode3 = m_pMMrDecoder->GetWhiteCode(); } while (nCode3 >= 64); } else { nCode1 = 0; do { nCode1 += nCode3 = m_pMMrDecoder->GetWhiteCode(); } while (nCode3 >= 64); nCode2 = 0; do { nCode2 += nCode3 = m_pMMrDecoder->GetBlackCode(); } while (nCode3 >= 64); } if (nCode1 > 0 || nCode2 > 0) { nA0 = pCodingLine[nCodingIndex++] = nA0 + nCode1; nA0 = pCodingLine[nCodingIndex++] = nA0 + nCode2; while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } } } break; case Vert0_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex]; if (pRefLine[nRefIndex] < nW) { ++nRefIndex; } break; case VertR1_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 1; if (pRefLine[nRefIndex] < nW) { ++nRefIndex; while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } } break; case VertR2_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 2; if (pRefLine[nRefIndex] < nW) { ++nRefIndex; while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } } break; case VertR3_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 3; if (pRefLine[nRefIndex] < nW) { ++nRefIndex; while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } } break; case VertL1_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 1; if (nRefIndex > 0) { --nRefIndex; } else { ++nRefIndex; } while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } break; case VertL2_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 2; if (nRefIndex > 0) { --nRefIndex; } else { ++nRefIndex; } while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } break; case VertL3_2D: nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 3; if (nRefIndex > 0) { --nRefIndex; } else { ++nRefIndex; } while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW) { nRefIndex += 2; } break; default: break; } } while (nA0 < nW); pCodingLine[nCodingIndex++] = nW; // convert the run lengths to a bitmap line nIndex = 0; while (pCodingLine[nIndex] < nW) { for (int nX = pCodingLine[nIndex]; nX < pCodingLine[nIndex + 1]; ++nX) { pBitmap->SetPixel(nX, nY); } nIndex += 2; } } if (nMMrDataLength >= 0) { m_pMMrDecoder->SkipTo(nMMrDataLength); } else { if (m_pMMrDecoder->Get24Bits() != 0x001001) { } } MemUtilsFree(pRefLine); MemUtilsFree(pCodingLine); } else //----- arithmetic decode { // set up the typical row context unsigned int unLtpCX = 0; if (bTpgdOn) { switch (unTempl) { case 0: unLtpCX = 0x3953; // 001 11001 0101 0011 break; case 1: unLtpCX = 0x079a; // 0011 11001 101 0 break; case 2: unLtpCX = 0x0e3; // 001 1100 01 1 break; case 3: unLtpCX = 0x18a; // 01100 0101 1 break; } } bool bLtp = 0; unsigned int unCX = 0, unCX0 = 0, unCX1 = 0, unCX2 = 0; JBIG2BitmapPtr oCXPtr0, oCXPtr1; JBIG2BitmapPtr oATPtr0, oATPtr1, oATPtr2, oATPtr3; for (int nY = 0; nY < nH; ++nY) { // check for a "typical" (duplicate) row if (bTpgdOn) { if (m_pArithDecoder->DecodeBit(unLtpCX, m_pGenericRegionStats)) { bLtp = !bLtp; } if (bLtp) { pBitmap->DuplicateRow(nY, nY - 1); continue; } } switch (unTempl) { case 0: // set up the context pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0); unCX0 = pBitmap->NextPixel(&oCXPtr0); unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0); pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1); unCX1 = pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX2 = 0; pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0); pBitmap->GetPixelPtr(pnATx[1], nY + pnATy[1], &oATPtr1); pBitmap->GetPixelPtr(pnATx[2], nY + pnATy[2], &oATPtr2); pBitmap->GetPixelPtr(pnATx[3], nY + pnATy[3], &oATPtr3); // decode the row for (int nX = 0; nX < nW; ++nX) { // build the context unCX = (unCX0 << 13) | (unCX1 << 8) | (unCX2 << 4) | (pBitmap->NextPixel(&oATPtr0) << 3) | (pBitmap->NextPixel(&oATPtr1) << 2) | (pBitmap->NextPixel(&oATPtr2) << 1) | pBitmap->NextPixel(&oATPtr3); int nPixel; if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel { nPixel = 0; } else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel { pBitmap->SetPixel(nX, nY); } // update the context unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x07; unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f; unCX2 = ((unCX2 << 1) | nPixel) & 0x0f; } break; case 1: // set up the context pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0); unCX0 = pBitmap->NextPixel(&oCXPtr0); unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0); unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0); pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1); unCX1 = pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX2 = 0; pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0); // decode the row for (int nX = 0; nX < nW; ++nX) { // build the context unCX = (unCX0 << 9) | (unCX1 << 4) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0); int nPixel; if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel { nPixel = 0; } else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel { pBitmap->SetPixel(nX, nY); } // update the context unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x0f; unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f; unCX2 = ((unCX2 << 1) | nPixel) & 0x07; } break; case 2: // set up the context pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0); unCX0 = pBitmap->NextPixel(&oCXPtr0); unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0); pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1); unCX1 = pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX2 = 0; pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0); // decode the row for (int nX = 0; nX < nW; ++nX) { // build the context unCX = (unCX0 << 7) | (unCX1 << 3) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0); int nPixel; if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel { nPixel = 0; } else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel { pBitmap->SetPixel(nX, nY); } // update the context unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x07; unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x0f; unCX2 = ((unCX2 << 1) | nPixel) & 0x03; } break; case 3: // set up the context pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1); unCX1 = pBitmap->NextPixel(&oCXPtr1); unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1); unCX2 = 0; pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0); // decode the row for (int nX = 0; nX < nW; ++nX) { // build the context unCX = (unCX1 << 5) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0); int nPixel; if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel { nPixel = 0; } else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel { pBitmap->SetPixel(nX, nY); } // update the context unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f; unCX2 = ((unCX2 << 1) | nPixel) & 0x0f; } break; } } } return pBitmap; } void JBIG2Stream::ReadGenericRefinementRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount) { unsigned int unW, unH, unX, unY, unSegInfoFlags; // region segment info field if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags)) { return; } unsigned int unExtCombOp = unSegInfoFlags & 7; // rest of the generic refinement region segment header unsigned int unFlags; if (!ReadUByte(&unFlags)) { return; } unsigned int unTempl = unFlags & 1; unsigned int unTpgrOn = (unFlags >> 1) & 1; // AT flags int arrATx[2], arrATy[2]; if (!unTempl) { if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1])) { return; } } // resize the page bitmap if needed if (unRefSegsCount == 0 || bImm) { if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH) { m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel); } } // get referenced bitmap JBIG2Bitmap *pRefBitmap = NULL; if (unRefSegsCount > 1) { return; } if (unRefSegsCount == 1) { JBIG2Segment *pSegment = FindSegment(punRefSegs[0]); if (pSegment->GetType() != jbig2SegBitmap) { return; } pRefBitmap = (JBIG2Bitmap *)pSegment; } else { pRefBitmap = m_pPageBitmap->GetSlice(unX, unY, unW, unH); } // set up the arithmetic decoder ResetRefinementStats(unTempl, NULL); m_pArithDecoder->Start(); // read JBIG2Bitmap *pBitmap = ReadGenericRefinementRegion(unW, unH, unTempl, 0 != unTpgrOn, pRefBitmap, 0, 0, arrATx, arrATy); if (bImm) // combine the region bitmap into the page bitmap { m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp); delete pBitmap; } else // store the region bitmap { pBitmap->SetSegNum(unSegNum); m_pSegments->Append(pBitmap); } // delete the referenced bitmap if (unRefSegsCount == 1) { DiscardSegment(punRefSegs[0]); } else { delete pRefBitmap; } return; } JBIG2Bitmap *JBIG2Stream::ReadGenericRefinementRegion(int nW, int nH, int nTempl, bool bTpgrOn, JBIG2Bitmap *pRefBitmap, int nRefDX, int nRefDY, int *pnAtx, int *pnAty) { JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH); pBitmap->ClearToZero(); // Typical row context unsigned int unLtpCX; if (nTempl) { unLtpCX = 0x008; } else { unLtpCX = 0x0010; } bool bLtp = 0; unsigned int unCx0, unCx2, unCx3, unCx4; JBIG2BitmapPtr oCxPtr0, oCxPtr1, oCxPtr2, oCxPtr3, oCxPtr4, oCxPtr5, oCxPtr6; for (int nY = 0; nY < nH; ++nY) { if (nTempl) { // set up the context pBitmap->GetPixelPtr(0, nY - 1, &oCxPtr0); unCx0 = pBitmap->NextPixel(&oCxPtr0); pBitmap->GetPixelPtr(-1, nY, &oCxPtr1); pRefBitmap->GetPixelPtr(-nRefDX, nY - 1 - nRefDY, &oCxPtr2); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oCxPtr3); unCx3 = pRefBitmap->NextPixel(&oCxPtr3); unCx3 = (unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3); pRefBitmap->GetPixelPtr(-nRefDX, nY + 1 - nRefDY, &oCxPtr4); unCx4 = pRefBitmap->NextPixel(&oCxPtr4); // set up the typical prediction context unsigned int unTpgrCX0 = 0, unTpgrCX1 = 0, unTpgrCX2 = 0; JBIG2BitmapPtr oTpgrCXPtr0, oTpgrCXPtr1, oTpgrCXPtr2; if (bTpgrOn) { pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - 1 - nRefDY, &oTpgrCXPtr0); unTpgrCX0 = pRefBitmap->NextPixel(&oTpgrCXPtr0); unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0); unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oTpgrCXPtr1); unTpgrCX1 = pRefBitmap->NextPixel(&oTpgrCXPtr1); unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1); unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oTpgrCXPtr2); unTpgrCX2 = pRefBitmap->NextPixel(&oTpgrCXPtr2); unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2); unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2); } for (int nX = 0; nX < nW; ++nX) { // update the context unCx0 = ((unCx0 << 1) | pBitmap->NextPixel(&oCxPtr0)) & 7; unCx3 = ((unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3)) & 7; unCx4 = ((unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4)) & 3; if (bTpgrOn) { // update the typical predictor context unTpgrCX0 = ((unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0)) & 7; unTpgrCX1 = ((unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1)) & 7; unTpgrCX2 = ((unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2)) & 7; // check for a "typical" pixel if (m_pArithDecoder->DecodeBit(unLtpCX, m_pRefinementRegionStats)) { bLtp = !bLtp; } if (unTpgrCX0 == 0 && unTpgrCX1 == 0 && unTpgrCX2 == 0) { pBitmap->ClearPixel(nX, nY); continue; } else if (unTpgrCX0 == 7 && unTpgrCX1 == 7 && unTpgrCX2 == 7) { pBitmap->SetPixel(nX, nY); continue; } } // build the context unsigned int unCx = (unCx0 << 7) | (pBitmap->NextPixel(&oCxPtr1) << 6) | (pRefBitmap->NextPixel(&oCxPtr2) << 5) | (unCx3 << 2) | unCx4; // decode the pixel int nPix; if ((nPix = m_pArithDecoder->DecodeBit(unCx, m_pRefinementRegionStats))) { pBitmap->SetPixel(nX, nY); } } } else { // set up the context pBitmap->GetPixelPtr(0, nY - 1, &oCxPtr0); unCx0 = pBitmap->NextPixel(&oCxPtr0); pBitmap->GetPixelPtr(-1, nY, &oCxPtr1); pRefBitmap->GetPixelPtr(-nRefDX, nY - 1 - nRefDY, &oCxPtr2); unCx2 = pRefBitmap->NextPixel(&oCxPtr2); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oCxPtr3); unCx3 = pRefBitmap->NextPixel(&oCxPtr3); unCx3 = (unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oCxPtr4); unCx4 = pRefBitmap->NextPixel(&oCxPtr4); unCx4 = (unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4); pBitmap->GetPixelPtr(pnAtx[0], nY + pnAty[0], &oCxPtr5); pRefBitmap->GetPixelPtr(pnAtx[1] - nRefDX, nY + pnAty[1] - nRefDY, &oCxPtr6); // set up the typical prediction context unsigned int unTpgrCX0 = 0, unTpgrCX1 = 0, unTpgrCX2 = 0; JBIG2BitmapPtr oTpgrCXPtr0, oTpgrCXPtr1, oTpgrCXPtr2; if (bTpgrOn) { pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - 1 - nRefDY, &oTpgrCXPtr0); unTpgrCX0 = pRefBitmap->NextPixel(&oTpgrCXPtr0); unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0); unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oTpgrCXPtr1); unTpgrCX1 = pRefBitmap->NextPixel(&oTpgrCXPtr1); unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1); unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1); pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oTpgrCXPtr2); unTpgrCX2 = pRefBitmap->NextPixel(&oTpgrCXPtr2); unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2); unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2); } for (int nX = 0; nX < nW; ++nX) { // update the context unCx0 = ((unCx0 << 1) | pBitmap->NextPixel(&oCxPtr0)) & 3; unCx2 = ((unCx2 << 1) | pRefBitmap->NextPixel(&oCxPtr2)) & 3; unCx3 = ((unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3)) & 7; unCx4 = ((unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4)) & 7; if (bTpgrOn) { // update the typical predictor context unTpgrCX0 = ((unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0)) & 7; unTpgrCX1 = ((unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1)) & 7; unTpgrCX2 = ((unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2)) & 7; // check for a "typical" pixel if (m_pArithDecoder->DecodeBit(unLtpCX, m_pRefinementRegionStats)) { bLtp = !bLtp; } if (unTpgrCX0 == 0 && unTpgrCX1 == 0 && unTpgrCX2 == 0) { pBitmap->ClearPixel(nX, nY); continue; } else if (unTpgrCX0 == 7 && unTpgrCX1 == 7 && unTpgrCX2 == 7) { pBitmap->SetPixel(nX, nY); continue; } } // build the context unsigned int unCx = (unCx0 << 11) | (pBitmap->NextPixel(&oCxPtr1) << 10) | (unCx2 << 8) | (unCx3 << 5) | (unCx4 << 2) | (pBitmap->NextPixel(&oCxPtr5) << 1) | pRefBitmap->NextPixel(&oCxPtr6); // decode the pixel int nPix; if ((nPix = m_pArithDecoder->DecodeBit(unCx, m_pRefinementRegionStats))) { pBitmap->SetPixel(nX, nY); } } } } return pBitmap; } void JBIG2Stream::ReadPageInfoSegment(unsigned int unLength) { unsigned int unResX, unResY, unFlags, unStriping; if (!ReadULong(&m_unPageW) || !ReadULong(&m_unPageH) || !ReadULong(&unResX) || !ReadULong(&unResY) || !ReadUByte(&unFlags) || !ReadUWord(&unStriping)) { return; } m_unPageDefPixel = (unFlags >> 2) & 1; m_unDefCombOp = (unFlags >> 3) & 3; if (0xffffffff == m_unPageH) { m_unCurPageH = unStriping & 0x7fff; } else { m_unCurPageH = m_unPageH; } m_pPageBitmap = new JBIG2Bitmap(0, m_unPageW, m_unPageH); // Очищаем картинку if (m_unPageDefPixel) { m_pPageBitmap->ClearToOne(); } else { m_pPageBitmap->ClearToZero(); } return; } void JBIG2Stream::ReadEndOfStripeSegment(unsigned int unLength) { // Пропускаем данный сегмент for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex) { m_pCurStream->GetChar(); } } void JBIG2Stream::ReadProfilesSegment(unsigned int unLength) { // Пропускаем данный сегмент for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex) { m_pCurStream->GetChar(); } } void JBIG2Stream::ReadCodeTableSegment(unsigned int unSegNum, unsigned int unLength) { unsigned int unFlags; int nLowVal, nHighVal; if (!ReadUByte(&unFlags) || !ReadLong(&nLowVal) || !ReadLong(&nHighVal)) { return; } unsigned int unOOB = unFlags & 1; unsigned int unPrefixBits = ((unFlags >> 1) & 7) + 1; unsigned int unRangeBits = ((unFlags >> 4) & 7) + 1; m_pHuffDecoder->Reset(); unsigned int unHuffTabSize = 8; JBIG2HuffmanTable *pHuffTable = (JBIG2HuffmanTable *)MemUtilsMallocArray(unHuffTabSize, sizeof(JBIG2HuffmanTable)); unsigned int unIndex = 0; int nVal = nLowVal; while (nVal < nHighVal) { if (unIndex == unHuffTabSize) { unHuffTabSize *= 2; pHuffTable = (JBIG2HuffmanTable *)MemUtilsReallocArray(pHuffTable, unHuffTabSize, sizeof(JBIG2HuffmanTable)); } pHuffTable[unIndex].nValue = nVal; pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits); pHuffTable[unIndex].unRangeLen = m_pHuffDecoder->ReadBits(unRangeBits); nVal += 1 << pHuffTable[unIndex].unRangeLen; ++unIndex; } if (unIndex + unOOB + 3 > unHuffTabSize) { unHuffTabSize = unIndex + unOOB + 3; pHuffTable = (JBIG2HuffmanTable *)MemUtilsReallocArray(pHuffTable, unHuffTabSize, sizeof(JBIG2HuffmanTable)); } pHuffTable[unIndex].nValue = nLowVal - 1; pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits); pHuffTable[unIndex].unRangeLen = jbig2HuffmanLOW; ++unIndex; pHuffTable[unIndex].nValue = nHighVal; pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits); pHuffTable[unIndex].unRangeLen = 32; ++unIndex; if (unOOB) { pHuffTable[unIndex].nValue = 0; pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits); pHuffTable[unIndex].unRangeLen = jbig2HuffmanOOB; ++unIndex; } pHuffTable[unIndex].nValue = 0; pHuffTable[unIndex].unPrefixLen = 0; pHuffTable[unIndex].unRangeLen = jbig2HuffmanEOT; m_pHuffDecoder->BuildTable(pHuffTable, unIndex); // Создаем и сохраняем новый сегмент таблицы m_pSegments->Append(new JBIG2CodeTable(unSegNum, pHuffTable)); return; } void JBIG2Stream::ReadExtensionSegment(unsigned int unLength) { // Пропускаем данный сегмент for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex) { m_pCurStream->GetChar(); } } JBIG2Segment *JBIG2Stream::FindSegment(unsigned int unSegNum) { JBIG2Segment *pSegment = NULL; for (int nIndex = 0; nIndex < m_pGlobalSegments->GetLength(); ++nIndex) { pSegment = (JBIG2Segment *)m_pGlobalSegments->GetByIndex(nIndex); if (pSegment->GetSegNum() == unSegNum) { return pSegment; } } for (int nIndex = 0; nIndex < m_pSegments->GetLength(); ++nIndex) { pSegment = (JBIG2Segment *)m_pSegments->GetByIndex(nIndex); if (pSegment->GetSegNum() == unSegNum) { return pSegment; } } return NULL; } void JBIG2Stream::DiscardSegment(unsigned int unSegNum) { JBIG2Segment *pSegment = NULL; for (int nIndex = 0; nIndex < m_pGlobalSegments->GetLength(); ++nIndex) { pSegment = (JBIG2Segment *)m_pGlobalSegments->GetByIndex(nIndex); if (pSegment->GetSegNum() == unSegNum) { m_pGlobalSegments->Delete(nIndex); return; } } for (int nIndex = 0; nIndex < m_pSegments->GetLength(); ++nIndex) { pSegment = (JBIG2Segment *)m_pSegments->GetByIndex(nIndex); if (pSegment->GetSegNum() == unSegNum) { m_pSegments->Delete(nIndex); return; } } } void JBIG2Stream::ResetGenericStats(unsigned int unTempl, JArithmeticDecoderStats *pPrevStats) { int nSize = c_arrContextSize[unTempl]; if (pPrevStats && pPrevStats->GetContextSize() == nSize) { if (m_pGenericRegionStats->GetContextSize() == nSize) { m_pGenericRegionStats->CopyFrom(pPrevStats); } else { delete m_pGenericRegionStats; m_pGenericRegionStats = pPrevStats->Copy(); } } else { if (m_pGenericRegionStats->GetContextSize() == nSize) { m_pGenericRegionStats->Reset(); } else { delete m_pGenericRegionStats; m_pGenericRegionStats = new JArithmeticDecoderStats(1 << nSize); } } } void JBIG2Stream::ResetRefinementStats(unsigned int unTempl, JArithmeticDecoderStats *pPrevStats) { int nSize = c_arrRefContextSize[unTempl]; if (pPrevStats && pPrevStats->GetContextSize() == nSize) { if (m_pRefinementRegionStats->GetContextSize() == nSize) { m_pRefinementRegionStats->CopyFrom(pPrevStats); } else { delete m_pRefinementRegionStats; m_pRefinementRegionStats = pPrevStats->Copy(); } } else { if (m_pRefinementRegionStats->GetContextSize() == nSize) { m_pRefinementRegionStats->Reset(); } else { delete m_pRefinementRegionStats; m_pRefinementRegionStats = new JArithmeticDecoderStats(1 << nSize); } } } void JBIG2Stream::ResetIntStats(int nSymCodeLen) { m_pIadhStats->Reset(); m_pIadwStats->Reset(); m_pIaexStats->Reset(); m_pIaaiStats->Reset(); m_pIadtStats->Reset(); m_pIaitStats->Reset(); m_pIafsStats->Reset(); m_pIadsStats->Reset(); m_pIardxStats->Reset(); m_pIardyStats->Reset(); m_pIardwStats->Reset(); m_pIardhStats->Reset(); m_pIariStats->Reset(); if (m_pIaidStats->GetContextSize() == 1 << (nSymCodeLen + 1)) { m_pIaidStats->Reset(); } else { delete m_pIaidStats; m_pIaidStats = new JArithmeticDecoderStats(1 << (nSymCodeLen + 1)); } } bool JBIG2Stream::ReadUByte(unsigned int *pBuffer) { int nChar; if (EOF == (nChar = m_pCurStream->GetChar())) { return false; } *pBuffer = (unsigned int)nChar; return true; } bool JBIG2Stream::ReadByte(int *pBuffer) { int nChar; if (EOF == (nChar = m_pCurStream->GetChar())) { return false; } *pBuffer = nChar; if (nChar & 0x80) { *pBuffer |= -1 - 0xff; } return true; } bool JBIG2Stream::ReadUWord(unsigned int *pBuffer) { int nChar0, nChar1; if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar())) { return false; } *pBuffer = (unsigned int)((nChar0 << 8) | nChar1); return true; } bool JBIG2Stream::ReadULong(unsigned int *pBuffer) { int nChar0, nChar1, nChar2, nChar3; if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar()) || EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar())) { return false; } *pBuffer = (unsigned int)((nChar0 << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3); return true; } bool JBIG2Stream::ReadLong(int *pBuffer) { int nChar0, nChar1, nChar2, nChar3; if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar()) || EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar())) { return false; } *pBuffer = ((nChar0 << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3); if (nChar0 & 0x80) { *pBuffer |= -1 - (int)0xffffffff; } return true; } }