mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-03-09 16:00:23 +01:00
JBIG2 - text region segment
This commit is contained in:
parent
ca78f61260
commit
fc6985e35a
@ -22,6 +22,103 @@
|
||||
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[] =
|
||||
{
|
||||
{ 0, 1, 4, 0b0, PDFJBIG2HuffmanTableEntry::Type::Standard},
|
||||
@ -958,38 +1055,13 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
|
||||
/* 7.4.2.2 step 2) */
|
||||
PDFJBIG2ReferencedSegments references = getReferencedSegments(header);
|
||||
|
||||
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.SDINSYMS = references.getSymbolBitmaps();
|
||||
parameters.SDNUMINSYMS = static_cast<uint32_t>(parameters.SDINSYMS.size());
|
||||
|
||||
/* 7.4.2.1.6 - huffman table selection */
|
||||
|
||||
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)
|
||||
{
|
||||
case 0:
|
||||
@ -1001,7 +1073,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
break;
|
||||
|
||||
case 3:
|
||||
parameters.SDHUFFDH_Decoder = getUserTable();
|
||||
parameters.SDHUFFDH_Decoder = references.getUserTable(&m_reader);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1019,7 +1091,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
break;
|
||||
|
||||
case 3:
|
||||
parameters.SDHUFFDW_Decoder = getUserTable();
|
||||
parameters.SDHUFFDW_Decoder = references.getUserTable(&m_reader);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1033,7 +1105,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
break;
|
||||
|
||||
case 1:
|
||||
parameters.SDHUFFBMSIZE_Decoder = getUserTable();
|
||||
parameters.SDHUFFBMSIZE_Decoder = references.getUserTable(&m_reader);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1047,7 +1119,7 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
break;
|
||||
|
||||
case 1:
|
||||
parameters.SDHUFFAGGINST_Decoder = getUserTable();
|
||||
parameters.SDHUFFAGGINST_Decoder = references.getUserTable(&m_reader);
|
||||
break;
|
||||
|
||||
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));
|
||||
|
||||
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
|
||||
@ -1244,17 +1316,363 @@ void PDFJBIG2Decoder::processSymbolDictionary(const PDFJBIG2SegmentHeader& heade
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: JBIG2 - processPatternDictionary
|
||||
throw PDFException(PDFTranslationContext::tr("JBIG2 NOT IMPLEMENTED."));
|
||||
}
|
||||
|
||||
void PDFJBIG2Decoder::processHalftoneRegion(const PDFJBIG2SegmentHeader& header)
|
||||
{
|
||||
// TODO: JBIG2 - processHalftoneRegion
|
||||
throw PDFException(PDFTranslationContext::tr("JBIG2 NOT IMPLEMENTED."));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!isValid())
|
||||
@ -2409,4 +2838,35 @@ std::optional<int32_t> PDFJBIG2HuffmanDecoder::readSignedInteger()
|
||||
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
|
||||
|
@ -31,6 +31,9 @@ class PDFJBIG2HuffmanCodeTable;
|
||||
class PDFJBIG2SymbolDictionary;
|
||||
|
||||
struct PDFJBIG2HuffmanTableEntry;
|
||||
struct PDFJBIG2BitmapDecodingParameters;
|
||||
struct PDFJBIG2TextRegionDecodingParameters;
|
||||
struct PDFJBIG2BitmapRefinementDecodingParameters;
|
||||
|
||||
enum class PDFJBIG2BitOperation
|
||||
{
|
||||
@ -304,6 +307,9 @@ public:
|
||||
/// Constructs huffman decoder from huffman code table, in this case, memory is allocated
|
||||
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)
|
||||
bool isValid() const { return m_begin != m_end; }
|
||||
|
||||
@ -418,6 +424,14 @@ struct PDFJBIG2ReferencedSegments
|
||||
std::vector<const PDFJBIG2Bitmap*> bitmaps;
|
||||
std::vector<const PDFJBIG2HuffmanCodeTable*> codeTables;
|
||||
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
|
||||
@ -439,72 +453,6 @@ struct PDFJBIG2ATPosition
|
||||
|
||||
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
|
||||
struct PDFJBIG2SymbolDictionaryDecodingParameters
|
||||
{
|
||||
|
@ -320,6 +320,34 @@ unsigned char* convertByteArrayToUcharPtr(QByteArray& 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
|
||||
|
||||
#endif // PDFUTILS_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user