CCITT fax decoder, finishing

This commit is contained in:
Jakub Melka
2019-10-13 19:02:38 +02:00
parent e20dfe6a5c
commit b1b5780753
4 changed files with 116 additions and 9 deletions

View File

@ -312,7 +312,7 @@ PDFImageData PDFCCITTFaxDecoder::decode()
int row = 0; int row = 0;
const size_t lineSize = m_parameters.columns + 2; const size_t lineSize = m_parameters.columns + 2;
codingLine.resize(lineSize, m_parameters.columns); codingLine.resize(lineSize, 0);
referenceLine.resize(lineSize, m_parameters.columns); referenceLine.resize(lineSize, m_parameters.columns);
bool isUsing2DEncoding = m_parameters.K < 0; bool isUsing2DEncoding = m_parameters.K < 0;
bool isEndOfLineOccured = m_parameters.hasEndOfLine; bool isEndOfLineOccured = m_parameters.hasEndOfLine;
@ -334,7 +334,6 @@ PDFImageData PDFCCITTFaxDecoder::decode()
int a0_index = 0; int a0_index = 0;
bool isCurrentPixelBlack = false; bool isCurrentPixelBlack = false;
if (isUsing2DEncoding) if (isUsing2DEncoding)
{ {
int b1_index = 0; int b1_index = 0;
@ -444,22 +443,74 @@ PDFImageData PDFCCITTFaxDecoder::decode()
++index; ++index;
} }
writer.write((isCurrentPixelBlack != m_parameters.hasBlackIsOne) ? 0 : 1); writer.write((isCurrentPixelBlack != m_parameters.hasBlackIsOne) ? 1 : 0);
} }
writer.finishLine(); writer.finishLine();
++row; ++row;
// Check if we have reached desired number of rows (and end-of-block mode
// is not set). If yes, then break the reading.
if (!m_parameters.hasEndOfBlock && row == m_parameters.rows) if (!m_parameters.hasEndOfBlock && row == m_parameters.rows)
{ {
// We have reached number of rows, stop reading the data // We have reached number of rows, stop reading the data
break; break;
} }
pokracovat zde
bool foundEndOfLine = false;
if (m_parameters.hasEndOfLine)
{
// End of line is required, try to scan it (until end of stream is reached).
while (!m_reader.isAtEnd())
{
if (m_reader.look(12) == 1)
{
m_reader.read(12);
foundEndOfLine = true;
break;
}
else
{
m_reader.read(1);
}
}
}
else if (!m_parameters.hasEncodedByteAlign)
{
// Skip fill zeros and possibly find EOL
foundEndOfLine = skipFillAndEOL();
}
// If end of line is found, be do not perform align to bytes (end of line
// has perference against byte align)
if (m_parameters.hasEncodedByteAlign && !foundEndOfLine)
{
m_reader.alignToBytes();
}
if (m_reader.isAtEnd())
{
// Have we finished reading?
break;
}
updateIsUsing2DEncoding();
if (m_parameters.hasEndOfBlock && foundEndOfLine)
{
if (m_reader.look(60) == 0x1001001001001ULL)
{
// End of block found, stop reading the data
break;
}
}
std::swap(codingLine, referenceLine); std::swap(codingLine, referenceLine);
std::fill(codingLine.begin(), codingLine.end(), 0);
std::fill(std::next(referenceLine.begin(), a0_index + 1), referenceLine.end(), m_parameters.columns);
} }
return PDFImageData(1, 1, m_parameters.columns, row, (m_parameters.columns + 7) / 8, m_parameters.maskingType, writer.takeByteArray(), { }, { }, { });
} }
void PDFCCITTFaxDecoder::skipFill() void PDFCCITTFaxDecoder::skipFill()
@ -467,7 +518,7 @@ void PDFCCITTFaxDecoder::skipFill()
// This functions skips zero bits (because codewords have at most 12 bits, // This functions skips zero bits (because codewords have at most 12 bits,
// we use 12 bit lookahead to ensure, that we do not broke data sequence). // we use 12 bit lookahead to ensure, that we do not broke data sequence).
while (m_reader.look(12) == 0) while (!m_reader.isAtEnd() && m_reader.look(12) == 0)
{ {
m_reader.read(1); m_reader.read(1);
} }

View File

@ -64,6 +64,8 @@ struct PDFCCITTFaxDecoderParameters
/// If this flag is true, then 1 means black pixel, 0 white pixel. Otherwise, if false, /// If this flag is true, then 1 means black pixel, 0 white pixel. Otherwise, if false,
/// then 0 means black pixel and 1 white pixel. /// then 0 means black pixel and 1 white pixel.
bool hasBlackIsOne = false; bool hasBlackIsOne = false;
PDFImageData::MaskingType maskingType = PDFImageData::MaskingType::None;
}; };
enum CCITT_2D_Code_Mode; enum CCITT_2D_Code_Mode;

View File

@ -20,6 +20,7 @@
#include "pdfconstants.h" #include "pdfconstants.h"
#include "pdfexception.h" #include "pdfexception.h"
#include "pdfutils.h" #include "pdfutils.h"
#include "pdfccittfaxdecoder.h"
#include <openjpeg.h> #include <openjpeg.h>
#include <jpeglib.h> #include <jpeglib.h>
@ -166,6 +167,26 @@ PDFImage PDFImage::createImage(const PDFDocument* document, const PDFStream* str
} }
} }
const PDFDictionary* filterParamsDictionary = nullptr;
if (filterParameters.isDictionary())
{
filterParamsDictionary = filterParameters.getDictionary();
}
else if (filterParameters.isArray())
{
const PDFArray* filterParametersArray = filterParameters.getArray();
const size_t filterParamsCount = filterParametersArray->getCount();
if (filterParamsCount)
{
const PDFObject& object = document->getObject(filterParametersArray->getItem(filterParamsCount - 1));
if (object.isDictionary())
{
filterParamsDictionary = object.getDictionary();
}
}
}
if (imageFilterName == "DCTDecode" || imageFilterName == "DCT") if (imageFilterName == "DCTDecode" || imageFilterName == "DCT")
{ {
int colorTransform = loader.readIntegerFromDictionary(dictionary, "ColorTransform", -1); int colorTransform = loader.readIntegerFromDictionary(dictionary, "ColorTransform", -1);
@ -493,7 +514,26 @@ PDFImage PDFImage::createImage(const PDFDocument* document, const PDFStream* str
} }
else if (imageFilterName == "CCITTFaxDecode" || imageFilterName == "CCF") else if (imageFilterName == "CCITTFaxDecode" || imageFilterName == "CCF")
{ {
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Not implemented image filter 'CCITTFaxDecode'.")); if (!filterParamsDictionary)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid parameters for filter CCITT fax decode."));
}
PDFCCITTFaxDecoderParameters parameters;
parameters.maskingType = maskingType;
parameters.K = loader.readIntegerFromDictionary(filterParamsDictionary, "K", 0);
parameters.hasEndOfLine = loader.readBooleanFromDictionary(filterParamsDictionary, "EndOfLine", false);
parameters.hasEncodedByteAlign = loader.readBooleanFromDictionary(filterParamsDictionary, "EncodedByteAlign", false);
parameters.columns = loader.readIntegerFromDictionary(filterParamsDictionary, "Columns", 1728);
parameters.rows = loader.readIntegerFromDictionary(filterParamsDictionary, "Rows", 0);
parameters.hasEndOfBlock = loader.readBooleanFromDictionary(filterParamsDictionary, "EndOfBlock", true);
parameters.hasBlackIsOne = loader.readBooleanFromDictionary(filterParamsDictionary, "BlackIs1", false);
parameters.damagedRowsBeforeError = loader.readIntegerFromDictionary(filterParamsDictionary, "DamagedRowsBeforeError", 0);
QByteArray imageDataBuffer = document->getDecodedStream(stream);
PDFCCITTFaxDecoder decoder(&imageDataBuffer, parameters);
image.m_imageData = decoder.decode();
} }
else if (imageFilterName == "JBIG2Decode") else if (imageFilterName == "JBIG2Decode")
{ {

View File

@ -56,10 +56,24 @@ PDFBitReader::Value PDFBitReader::read(PDFBitReader::Value bits)
return value; return value;
} }
PDFBitReader::Value PDFBitReader::look(PDFBitReader::Value bits) const PDFBitReader::Value PDFBitReader::look(Value bits) const
{ {
PDFBitReader temp(*this); PDFBitReader temp(*this);
return temp.read(bits);
Value result = 0;
for (Value i = 0; i < bits; ++i)
{
if (!temp.isAtEnd())
{
result = (result << 1) | temp.read(1);
}
else
{
result = (result << 1);
}
}
return result;
} }
void PDFBitReader::seek(qint64 position) void PDFBitReader::seek(qint64 position)