mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
JBIG2 - text region segment
This commit is contained in:
@ -22,6 +22,103 @@
|
|||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Info structure for text region decoding structure
|
||||||
|
struct PDFJBIG2TextRegionDecodingParameters
|
||||||
|
{
|
||||||
|
bool SBHUFF = false;
|
||||||
|
bool SBREFINE = false;
|
||||||
|
uint8_t SBDEFPIXEL = 0;
|
||||||
|
PDFJBIG2BitOperation SBCOMBOP = PDFJBIG2BitOperation::Invalid;
|
||||||
|
bool TRANSPOSED = false;
|
||||||
|
uint8_t REFCORNER = 0;
|
||||||
|
uint8_t SBDSOFFSET = 0;
|
||||||
|
uint32_t SBW = 0;
|
||||||
|
uint32_t SBH = 0;
|
||||||
|
uint32_t SBNUMINSTANCES = 0;
|
||||||
|
uint8_t SBSTRIPS = 0;
|
||||||
|
uint32_t SBNUMSYMS = 0;
|
||||||
|
std::vector<const PDFJBIG2Bitmap*> SBSYMS;
|
||||||
|
uint8_t SBSYMCODELEN = 0;
|
||||||
|
PDFJBIG2HuffmanDecoder SBSYMCODES;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFFS;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFDS;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFDT;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFRDW;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFRDH;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFRDX;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFRDY;
|
||||||
|
PDFJBIG2HuffmanDecoder SBHUFFRSIZE;
|
||||||
|
uint8_t SBRTEMPLATE = 0;
|
||||||
|
PDFJBIG2ATPositions SBRAT = { };
|
||||||
|
PDFJBIG2ArithmeticDecoder* arithmeticDecoder = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Info structure for bitmap decoding parameters
|
||||||
|
struct PDFJBIG2BitmapDecodingParameters
|
||||||
|
{
|
||||||
|
/// Is Modified-Modified-Read encoding used? This encoding is simalr to CCITT pure 2D encoding.
|
||||||
|
bool MMR = false;
|
||||||
|
|
||||||
|
/// Is typical prediction for generic direct coding used?
|
||||||
|
bool TPGDON = false;
|
||||||
|
|
||||||
|
/// Width of the image
|
||||||
|
int GBW = 0;
|
||||||
|
|
||||||
|
/// Height of the image
|
||||||
|
int GBH = 0;
|
||||||
|
|
||||||
|
/// Template mode (not used for MMR).
|
||||||
|
uint8_t GBTEMPLATE = 0;
|
||||||
|
|
||||||
|
/// Positions of adaptative pixels
|
||||||
|
PDFJBIG2ATPositions ATXY = { };
|
||||||
|
|
||||||
|
/// Data with encoded image
|
||||||
|
QByteArray data;
|
||||||
|
|
||||||
|
/// State of arithmetic decoder
|
||||||
|
PDFJBIG2ArithmeticDecoderState* arithmeticDecoderState = nullptr;
|
||||||
|
|
||||||
|
/// Skip bitmap (pixel is skipped if corresponding pixel in the
|
||||||
|
/// skip bitmap is 1). Set to nullptr, if not used.
|
||||||
|
const PDFJBIG2Bitmap* SKIP = nullptr;
|
||||||
|
|
||||||
|
/// Arithmetic decoder (used, if MMR == false)
|
||||||
|
PDFJBIG2ArithmeticDecoder* arithmeticDecoder = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Info structure for refinement bitmap decoding parameters
|
||||||
|
struct PDFJBIG2BitmapRefinementDecodingParameters
|
||||||
|
{
|
||||||
|
/// Template mode used (0/1)
|
||||||
|
uint8_t GRTEMPLATE = 0;
|
||||||
|
|
||||||
|
/// Prediction (same as previous row)
|
||||||
|
bool TPGRON = false;
|
||||||
|
|
||||||
|
/// Bitmap width
|
||||||
|
uint32_t GRW = 0;
|
||||||
|
|
||||||
|
/// Bitmap height
|
||||||
|
uint32_t GRH = 0;
|
||||||
|
|
||||||
|
/// Reference bitmap
|
||||||
|
const PDFJBIG2Bitmap* GRREFERENCE = nullptr;
|
||||||
|
|
||||||
|
/// Offset x
|
||||||
|
int32_t GRREFERENCEX = 0;
|
||||||
|
|
||||||
|
/// Offset y
|
||||||
|
int32_t GRREFERENCEY = 0;
|
||||||
|
|
||||||
|
/// State of arithmetic decoder
|
||||||
|
PDFJBIG2ArithmeticDecoderState* arithmeticDecoderState = nullptr;
|
||||||
|
|
||||||
|
/// Positions of adaptative pixels
|
||||||
|
PDFJBIG2ATPositions GRAT = { };
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr PDFJBIG2HuffmanTableEntry PDFJBIG2StandardHuffmanTable_A[] =
|
static constexpr PDFJBIG2HuffmanTableEntry PDFJBIG2StandardHuffmanTable_A[] =
|
||||||
{
|
{
|
||||||
{ 0, 1, 4, 0b0, PDFJBIG2HuffmanTableEntry::Type::Standard},
|
{ 0, 1, 4, 0b0, PDFJBIG2HuffmanTableEntry::Type::Standard},
|
||||||
@ -958,38 +1055,13 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
|
|
||||||
/* 7.4.2.2 step 2) */
|
/* 7.4.2.2 step 2) */
|
||||||
PDFJBIG2ReferencedSegments references = getReferencedSegments(header);
|
PDFJBIG2ReferencedSegments references = getReferencedSegments(header);
|
||||||
|
parameters.SDINSYMS = references.getSymbolBitmaps();
|
||||||
for (const PDFJBIG2SymbolDictionary* dictionary : references.symbolDictionaries)
|
|
||||||
{
|
|
||||||
const std::vector<PDFJBIG2Bitmap>& bitmaps = dictionary->getBitmaps();
|
|
||||||
parameters.SDINSYMS.reserve(parameters.SDINSYMS.size() + bitmaps.size());
|
|
||||||
for (const PDFJBIG2Bitmap& bitmap : bitmaps)
|
|
||||||
{
|
|
||||||
parameters.SDINSYMS.push_back(&bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parameters.SDNUMINSYMS = static_cast<uint32_t>(parameters.SDINSYMS.size());
|
parameters.SDNUMINSYMS = static_cast<uint32_t>(parameters.SDINSYMS.size());
|
||||||
|
|
||||||
/* 7.4.2.1.6 - huffman table selection */
|
/* 7.4.2.1.6 - huffman table selection */
|
||||||
|
|
||||||
if (parameters.SDHUFF)
|
if (parameters.SDHUFF)
|
||||||
{
|
{
|
||||||
size_t currentUserCodeTableIndex = 0;
|
|
||||||
|
|
||||||
auto getUserTable = [&](void) -> PDFJBIG2HuffmanDecoder
|
|
||||||
{
|
|
||||||
if (currentUserCodeTableIndex < references.codeTables.size())
|
|
||||||
{
|
|
||||||
return PDFJBIG2HuffmanDecoder(&m_reader, references.codeTables[currentUserCodeTableIndex++]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
|
||||||
}
|
|
||||||
|
|
||||||
return PDFJBIG2HuffmanDecoder();
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (parameters.SDHUFFDH)
|
switch (parameters.SDHUFFDH)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -1001,7 +1073,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
parameters.SDHUFFDH_Decoder = getUserTable();
|
parameters.SDHUFFDH_Decoder = references.getUserTable(&m_reader);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1019,7 +1091,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
parameters.SDHUFFDW_Decoder = getUserTable();
|
parameters.SDHUFFDW_Decoder = references.getUserTable(&m_reader);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1033,7 +1105,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
parameters.SDHUFFBMSIZE_Decoder = getUserTable();
|
parameters.SDHUFFBMSIZE_Decoder = references.getUserTable(&m_reader);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1047,7 +1119,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
parameters.SDHUFFAGGINST_Decoder = getUserTable();
|
parameters.SDHUFFAGGINST_Decoder = references.getUserTable(&m_reader);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1056,9 +1128,9 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
|
|
||||||
parameters.EXRUNLENGTH_Decoder = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_A), std::end(PDFJBIG2StandardHuffmanTable_A));
|
parameters.EXRUNLENGTH_Decoder = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_A), std::end(PDFJBIG2StandardHuffmanTable_A));
|
||||||
|
|
||||||
if (currentUserCodeTableIndex != references.codeTables.size())
|
if (references.currentUserCodeTableIndex != references.codeTables.size())
|
||||||
{
|
{
|
||||||
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid number of huffam code table - %1 unused.").arg(references.codeTables.size() - currentUserCodeTableIndex));
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid number of huffam code table - %1 unused.").arg(references.codeTables.size() - references.currentUserCodeTableIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1244,17 +1316,363 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
|||||||
|
|
||||||
void PDFJBIG2Decoder::processTextRegion(const PDFJBIG2SegmentHeader& header)
|
void PDFJBIG2Decoder::processTextRegion(const PDFJBIG2SegmentHeader& header)
|
||||||
{
|
{
|
||||||
// TODO: JBIG2 - processTextRegion
|
auto getSBCOMBOOP = [](const uint8_t value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return PDFJBIG2BitOperation::Or;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return PDFJBIG2BitOperation::And;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return PDFJBIG2BitOperation::Xor;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return PDFJBIG2BitOperation::NotXor;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return PDFJBIG2BitOperation::Invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
PDFJBIG2RegionSegmentInformationField regionSegmentInfo = readRegionSegmentInformationField();
|
||||||
|
const uint16_t flags = m_reader.readUnsignedWord();
|
||||||
|
const bool SBHUFF = flags & 0x0001;
|
||||||
|
const bool SBREFINE = flags & 0x0002;
|
||||||
|
const uint8_t SBSTRIPS = 1 << ((flags >> 2) & 0x03);
|
||||||
|
const uint8_t REFCORNER = (flags >> 4) & 0x03;
|
||||||
|
const bool TRANSPOSED = (flags >> 6) & 0x01;
|
||||||
|
const uint8_t SBCOMBOOP_value = (flags >> 7) & 0x03;
|
||||||
|
const PDFJBIG2BitOperation SBCOMBOOP = getSBCOMBOOP(SBCOMBOOP_value);
|
||||||
|
const uint8_t SBDEFPIXEL = ((flags >> 9) & 0x01) ? 0xFF : 0x00;
|
||||||
|
const uint8_t SBDSOFFSET = (flags >> 10) & 0x1F;
|
||||||
|
const uint8_t SBRTEMPLATE = (flags >> 15) & 0x01;
|
||||||
|
|
||||||
|
// Decoding parameters
|
||||||
|
PDFJBIG2TextRegionDecodingParameters parameters;
|
||||||
|
parameters.SBHUFF = SBHUFF;
|
||||||
|
parameters.SBREFINE = SBREFINE;
|
||||||
|
parameters.SBDEFPIXEL = SBDEFPIXEL;
|
||||||
|
parameters.SBCOMBOP = SBCOMBOOP;
|
||||||
|
parameters.TRANSPOSED = TRANSPOSED;
|
||||||
|
parameters.REFCORNER = REFCORNER;
|
||||||
|
parameters.SBDSOFFSET = SBDSOFFSET;
|
||||||
|
parameters.SBW = regionSegmentInfo.width;
|
||||||
|
parameters.SBH = regionSegmentInfo.height;
|
||||||
|
parameters.SBRTEMPLATE = SBRTEMPLATE;
|
||||||
|
parameters.SBSTRIPS = SBSTRIPS;
|
||||||
|
|
||||||
|
// Referenced segments data
|
||||||
|
PDFJBIG2ReferencedSegments references = getReferencedSegments(header);
|
||||||
|
|
||||||
|
if (SBHUFF)
|
||||||
|
{
|
||||||
|
uint16_t huffmanFlags = m_reader.readUnsignedWord();
|
||||||
|
|
||||||
|
auto readHuffmanTableSelection = [&huffmanFlags]() -> const uint8_t
|
||||||
|
{
|
||||||
|
const uint8_t result = huffmanFlags & 0x03;
|
||||||
|
huffmanFlags = huffmanFlags >> 2;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t SBHUFFFS = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFDS = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFDT = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFRDW = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFRDH = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFRDX = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFRDY = readHuffmanTableSelection();
|
||||||
|
const uint8_t SBHUFFRSIZE = readHuffmanTableSelection();
|
||||||
|
|
||||||
|
if (huffmanFlags)
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 - invalid huffman table flags in text region segment."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create huffman tables
|
||||||
|
switch (SBHUFFFS)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFFS = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_F), std::end(PDFJBIG2StandardHuffmanTable_F));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFFS = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_G), std::end(PDFJBIG2StandardHuffmanTable_G));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFFS = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFDS)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFDS = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_H), std::end(PDFJBIG2StandardHuffmanTable_H));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFDS = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_I), std::end(PDFJBIG2StandardHuffmanTable_I));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
parameters.SBHUFFDS = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_J), std::end(PDFJBIG2StandardHuffmanTable_J));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFDS = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFDT)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFDT = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_K), std::end(PDFJBIG2StandardHuffmanTable_K));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFDT = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_L), std::end(PDFJBIG2StandardHuffmanTable_L));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
parameters.SBHUFFDT = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_M), std::end(PDFJBIG2StandardHuffmanTable_M));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFDT = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFRDW)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFRDW = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_N), std::end(PDFJBIG2StandardHuffmanTable_N));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFRDW = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_O), std::end(PDFJBIG2StandardHuffmanTable_O));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFRDW = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFRDH)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFRDH = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_N), std::end(PDFJBIG2StandardHuffmanTable_N));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFRDH = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_O), std::end(PDFJBIG2StandardHuffmanTable_O));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFRDH = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFRDX)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFRDX = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_N), std::end(PDFJBIG2StandardHuffmanTable_N));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFRDX = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_O), std::end(PDFJBIG2StandardHuffmanTable_O));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFRDX = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFRDY)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFRDY = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_N), std::end(PDFJBIG2StandardHuffmanTable_N));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFRDY = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_O), std::end(PDFJBIG2StandardHuffmanTable_O));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
parameters.SBHUFFRDY = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SBHUFFRSIZE)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
parameters.SBHUFFRSIZE = PDFJBIG2HuffmanDecoder(&m_reader, std::begin(PDFJBIG2StandardHuffmanTable_A), std::end(PDFJBIG2StandardHuffmanTable_A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
parameters.SBHUFFRSIZE = references.getUserTable(&m_reader);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SBREFINE && SBRTEMPLATE == 0)
|
||||||
|
{
|
||||||
|
parameters.SBRAT = readATTemplatePixelPositions(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.SBSYMS = references.getSymbolBitmaps();
|
||||||
|
parameters.SBNUMSYMS = static_cast<uint32_t>(parameters.SBSYMS.size());
|
||||||
|
parameters.SBNUMINSTANCES = m_reader.readUnsignedInt();
|
||||||
|
parameters.SBSYMCODELEN = log2ceil(parameters.SBNUMSYMS);
|
||||||
|
|
||||||
|
if (parameters.SBNUMSYMS == 0)
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 no referred symbols in text region segment."));
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFJBIG2ArithmeticDecoder decoder(&m_reader);
|
||||||
|
if (SBHUFF)
|
||||||
|
{
|
||||||
|
// Read run code lengths
|
||||||
|
std::vector<PDFJBIG2HuffmanTableEntry> rangeLengthTable(35, PDFJBIG2HuffmanTableEntry());
|
||||||
|
for (int32_t i = 0; i < rangeLengthTable.size(); ++i)
|
||||||
|
{
|
||||||
|
rangeLengthTable[i].value = i;
|
||||||
|
rangeLengthTable[i].prefixBitLength = m_reader.read(4);
|
||||||
|
}
|
||||||
|
rangeLengthTable = PDFJBIG2HuffmanCodeTable::buildPrefixes(rangeLengthTable);
|
||||||
|
PDFJBIG2HuffmanDecoder runLengthDecoder(&m_reader, qMove(rangeLengthTable));
|
||||||
|
|
||||||
|
std::vector<PDFJBIG2HuffmanTableEntry> symCodeTable(parameters.SBNUMSYMS, PDFJBIG2HuffmanTableEntry());
|
||||||
|
for (uint32_t i = 0; i < parameters.SBNUMSYMS;)
|
||||||
|
{
|
||||||
|
symCodeTable[i].value = i;
|
||||||
|
uint32_t code = checkInteger(runLengthDecoder.readSignedInteger());
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
symCodeTable[i++].prefixBitLength = code;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
case 33:
|
||||||
|
case 34:
|
||||||
|
{
|
||||||
|
uint32_t length = 0;
|
||||||
|
uint32_t range = 0;
|
||||||
|
|
||||||
|
if (code == 32)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid symbol length code table for text region segment."));
|
||||||
|
}
|
||||||
|
length = symCodeTable[i - 1].prefixBitLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case 32:
|
||||||
|
range = m_reader.read(2) + 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 33:
|
||||||
|
range = m_reader.read(3) + 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 34:
|
||||||
|
range = m_reader.read(7) + 11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < range; ++j)
|
||||||
|
{
|
||||||
|
symCodeTable[i].value = i;
|
||||||
|
symCodeTable[i].prefixBitLength = length;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symCodeTable = PDFJBIG2HuffmanCodeTable::buildPrefixes(symCodeTable);
|
||||||
|
parameters.SBSYMCODES = PDFJBIG2HuffmanDecoder(&m_reader, qMove(symCodeTable));
|
||||||
|
m_reader.alignToBytes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Arithmetic decoder
|
||||||
|
decoder.initialize();
|
||||||
|
parameters.arithmeticDecoder = &decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.SBREFINE)
|
||||||
|
{
|
||||||
|
resetArithmeticStatesGenericRefinement(parameters.SBRTEMPLATE, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFJBIG2Bitmap bitmap = readTextBitmap(parameters);
|
||||||
|
if (bitmap.isValid())
|
||||||
|
{
|
||||||
|
if (header.isImmediate())
|
||||||
|
{
|
||||||
|
m_pageBitmap.paint(bitmap, regionSegmentInfo.offsetX, regionSegmentInfo.offsetY, regionSegmentInfo.operation, m_pageSizeUndefined, m_pageDefaultPixelValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_segments[header.getSegmentNumber()] = std::make_unique<PDFJBIG2Bitmap>(qMove(bitmap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 - invalid bitmap for generic region."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFJBIG2Decoder::processPatternDictionary(const PDFJBIG2SegmentHeader& header)
|
void PDFJBIG2Decoder::processPatternDictionary(const PDFJBIG2SegmentHeader& header)
|
||||||
{
|
{
|
||||||
// TODO: JBIG2 - processPatternDictionary
|
// TODO: JBIG2 - processPatternDictionary
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 NOT IMPLEMENTED."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFJBIG2Decoder::processHalftoneRegion(const PDFJBIG2SegmentHeader& header)
|
void PDFJBIG2Decoder::processHalftoneRegion(const PDFJBIG2SegmentHeader& header)
|
||||||
{
|
{
|
||||||
// TODO: JBIG2 - processHalftoneRegion
|
// TODO: JBIG2 - processHalftoneRegion
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 NOT IMPLEMENTED."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFJBIG2Decoder::processGenericRegion(const PDFJBIG2SegmentHeader& header)
|
void PDFJBIG2Decoder::processGenericRegion(const PDFJBIG2SegmentHeader& header)
|
||||||
@ -2348,6 +2766,17 @@ PDFJBIG2HuffmanDecoder::PDFJBIG2HuffmanDecoder(PDFBitReader* reader, const PDFJB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFJBIG2HuffmanDecoder::PDFJBIG2HuffmanDecoder(PDFBitReader* reader, std::vector<PDFJBIG2HuffmanTableEntry>&& table) :
|
||||||
|
m_reader(reader),
|
||||||
|
m_entries(qMove(table))
|
||||||
|
{
|
||||||
|
if (!m_entries.empty())
|
||||||
|
{
|
||||||
|
m_begin = m_entries.data();
|
||||||
|
m_end = m_entries.data() + m_entries.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool PDFJBIG2HuffmanDecoder::isOutOfBandSupported() const
|
bool PDFJBIG2HuffmanDecoder::isOutOfBandSupported() const
|
||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
@ -2409,4 +2838,35 @@ std::optional<int32_t> PDFJBIG2HuffmanDecoder::readSignedInteger()
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<const PDFJBIG2Bitmap*> PDFJBIG2ReferencedSegments::getSymbolBitmaps() const
|
||||||
|
{
|
||||||
|
std::vector<const PDFJBIG2Bitmap*> result;
|
||||||
|
|
||||||
|
for (const PDFJBIG2SymbolDictionary* dictionary : symbolDictionaries)
|
||||||
|
{
|
||||||
|
const std::vector<PDFJBIG2Bitmap>& bitmaps = dictionary->getBitmaps();
|
||||||
|
result.reserve(result.size() + bitmaps.size());
|
||||||
|
for (const PDFJBIG2Bitmap& bitmap : bitmaps)
|
||||||
|
{
|
||||||
|
result.push_back(&bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFJBIG2HuffmanDecoder PDFJBIG2ReferencedSegments::getUserTable(PDFBitReader* reader)
|
||||||
|
{
|
||||||
|
if (currentUserCodeTableIndex < codeTables.size())
|
||||||
|
{
|
||||||
|
return PDFJBIG2HuffmanDecoder(reader, codeTables[currentUserCodeTableIndex++]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("JBIG2 invalid user huffman code table."));
|
||||||
|
}
|
||||||
|
|
||||||
|
return PDFJBIG2HuffmanDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -31,6 +31,9 @@ class PDFJBIG2HuffmanCodeTable;
|
|||||||
class PDFJBIG2SymbolDictionary;
|
class PDFJBIG2SymbolDictionary;
|
||||||
|
|
||||||
struct PDFJBIG2HuffmanTableEntry;
|
struct PDFJBIG2HuffmanTableEntry;
|
||||||
|
struct PDFJBIG2BitmapDecodingParameters;
|
||||||
|
struct PDFJBIG2TextRegionDecodingParameters;
|
||||||
|
struct PDFJBIG2BitmapRefinementDecodingParameters;
|
||||||
|
|
||||||
enum class PDFJBIG2BitOperation
|
enum class PDFJBIG2BitOperation
|
||||||
{
|
{
|
||||||
@ -304,6 +307,9 @@ public:
|
|||||||
/// Constructs huffman decoder from huffman code table, in this case, memory is allocated
|
/// Constructs huffman decoder from huffman code table, in this case, memory is allocated
|
||||||
explicit PDFJBIG2HuffmanDecoder(PDFBitReader* reader, const PDFJBIG2HuffmanCodeTable* table);
|
explicit PDFJBIG2HuffmanDecoder(PDFBitReader* reader, const PDFJBIG2HuffmanCodeTable* table);
|
||||||
|
|
||||||
|
/// Constructs huffman decoder from huffman code table, in this case, memory is allocated
|
||||||
|
explicit PDFJBIG2HuffmanDecoder(PDFBitReader* reader, std::vector<PDFJBIG2HuffmanTableEntry>&& table);
|
||||||
|
|
||||||
/// Returns true, if huffman table is valid (and usable)
|
/// Returns true, if huffman table is valid (and usable)
|
||||||
bool isValid() const { return m_begin != m_end; }
|
bool isValid() const { return m_begin != m_end; }
|
||||||
|
|
||||||
@ -418,6 +424,14 @@ struct PDFJBIG2ReferencedSegments
|
|||||||
std::vector<const PDFJBIG2Bitmap*> bitmaps;
|
std::vector<const PDFJBIG2Bitmap*> bitmaps;
|
||||||
std::vector<const PDFJBIG2HuffmanCodeTable*> codeTables;
|
std::vector<const PDFJBIG2HuffmanCodeTable*> codeTables;
|
||||||
std::vector<const PDFJBIG2SymbolDictionary*> symbolDictionaries;
|
std::vector<const PDFJBIG2SymbolDictionary*> symbolDictionaries;
|
||||||
|
size_t currentUserCodeTableIndex = 0;
|
||||||
|
|
||||||
|
/// Returns symbol bitmaps from all symbol dictionaries
|
||||||
|
std::vector<const PDFJBIG2Bitmap*> getSymbolBitmaps() const;
|
||||||
|
|
||||||
|
/// Returns current user huffman table according the index. If index
|
||||||
|
/// is out of range, then exception is thrown.
|
||||||
|
PDFJBIG2HuffmanDecoder getUserTable(PDFBitReader* reader);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Region segment information field, see chapter 7.4.1 in the specification
|
/// Region segment information field, see chapter 7.4.1 in the specification
|
||||||
@ -439,72 +453,6 @@ struct PDFJBIG2ATPosition
|
|||||||
|
|
||||||
using PDFJBIG2ATPositions = std::array<PDFJBIG2ATPosition, 4>;
|
using PDFJBIG2ATPositions = std::array<PDFJBIG2ATPosition, 4>;
|
||||||
|
|
||||||
/// Info structure for bitmap decoding parameters
|
|
||||||
struct PDFJBIG2BitmapDecodingParameters
|
|
||||||
{
|
|
||||||
/// Is Modified-Modified-Read encoding used? This encoding is simalr to CCITT pure 2D encoding.
|
|
||||||
bool MMR = false;
|
|
||||||
|
|
||||||
/// Is typical prediction for generic direct coding used?
|
|
||||||
bool TPGDON = false;
|
|
||||||
|
|
||||||
/// Width of the image
|
|
||||||
int GBW = 0;
|
|
||||||
|
|
||||||
/// Height of the image
|
|
||||||
int GBH = 0;
|
|
||||||
|
|
||||||
/// Template mode (not used for MMR).
|
|
||||||
uint8_t GBTEMPLATE = 0;
|
|
||||||
|
|
||||||
/// Positions of adaptative pixels
|
|
||||||
PDFJBIG2ATPositions ATXY = { };
|
|
||||||
|
|
||||||
/// Data with encoded image
|
|
||||||
QByteArray data;
|
|
||||||
|
|
||||||
/// State of arithmetic decoder
|
|
||||||
PDFJBIG2ArithmeticDecoderState* arithmeticDecoderState = nullptr;
|
|
||||||
|
|
||||||
/// Skip bitmap (pixel is skipped if corresponding pixel in the
|
|
||||||
/// skip bitmap is 1). Set to nullptr, if not used.
|
|
||||||
const PDFJBIG2Bitmap* SKIP = nullptr;
|
|
||||||
|
|
||||||
/// Arithmetic decoder (used, if MMR == false)
|
|
||||||
PDFJBIG2ArithmeticDecoder* arithmeticDecoder = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Info structure for refinement bitmap decoding parameters
|
|
||||||
struct PDFJBIG2BitmapRefinementDecodingParameters
|
|
||||||
{
|
|
||||||
/// Template mode used (0/1)
|
|
||||||
uint8_t GRTEMPLATE = 0;
|
|
||||||
|
|
||||||
/// Prediction (same as previous row)
|
|
||||||
bool TPGRON = false;
|
|
||||||
|
|
||||||
/// Bitmap width
|
|
||||||
uint32_t GRW = 0;
|
|
||||||
|
|
||||||
/// Bitmap height
|
|
||||||
uint32_t GRH = 0;
|
|
||||||
|
|
||||||
/// Reference bitmap
|
|
||||||
const PDFJBIG2Bitmap* GRREFERENCE = nullptr;
|
|
||||||
|
|
||||||
/// Offset x
|
|
||||||
int32_t GRREFERENCEX = 0;
|
|
||||||
|
|
||||||
/// Offset y
|
|
||||||
int32_t GRREFERENCEY = 0;
|
|
||||||
|
|
||||||
/// State of arithmetic decoder
|
|
||||||
PDFJBIG2ArithmeticDecoderState* arithmeticDecoderState = nullptr;
|
|
||||||
|
|
||||||
/// Positions of adaptative pixels
|
|
||||||
PDFJBIG2ATPositions GRAT = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Info structure for symbol dictionary decoding procedure
|
/// Info structure for symbol dictionary decoding procedure
|
||||||
struct PDFJBIG2SymbolDictionaryDecodingParameters
|
struct PDFJBIG2SymbolDictionaryDecodingParameters
|
||||||
{
|
{
|
||||||
|
@ -320,6 +320,34 @@ unsigned char* convertByteArrayToUcharPtr(QByteArray& data)
|
|||||||
return reinterpret_cast<unsigned char*>(data.data());
|
return reinterpret_cast<unsigned char*>(data.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function computes ceil of log base 2 of value. The algorithm is taken
|
||||||
|
/// from: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn.
|
||||||
|
/// License for this function is public domain.
|
||||||
|
inline constexpr uint8_t log2ceil(uint32_t value)
|
||||||
|
{
|
||||||
|
constexpr uint8_t MULTIPLY_DE_BRUIJN_BIT_POSITION[32] =
|
||||||
|
{
|
||||||
|
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||||
|
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
value |= value >> 1;
|
||||||
|
value |= value >> 2;
|
||||||
|
value |= value >> 4;
|
||||||
|
value |= value >> 8;
|
||||||
|
value |= value >> 16;
|
||||||
|
|
||||||
|
uint8_t logarithm = MULTIPLY_DE_BRUIJN_BIT_POSITION[static_cast<uint32_t>((value * 0x07C4ACDDU) >> 27)];
|
||||||
|
|
||||||
|
// Ceil
|
||||||
|
if ((1U << logarithm) < value)
|
||||||
|
{
|
||||||
|
++logarithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logarithm;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFUTILS_H
|
#endif // PDFUTILS_H
|
||||||
|
Reference in New Issue
Block a user