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;
const size_t lineSize = m_parameters.columns + 2;
codingLine.resize(lineSize, m_parameters.columns);
codingLine.resize(lineSize, 0);
referenceLine.resize(lineSize, m_parameters.columns);
bool isUsing2DEncoding = m_parameters.K < 0;
bool isEndOfLineOccured = m_parameters.hasEndOfLine;
@ -334,7 +334,6 @@ PDFImageData PDFCCITTFaxDecoder::decode()
int a0_index = 0;
bool isCurrentPixelBlack = false;
if (isUsing2DEncoding)
{
int b1_index = 0;
@ -444,22 +443,74 @@ PDFImageData PDFCCITTFaxDecoder::decode()
++index;
}
writer.write((isCurrentPixelBlack != m_parameters.hasBlackIsOne) ? 0 : 1);
writer.write((isCurrentPixelBlack != m_parameters.hasBlackIsOne) ? 1 : 0);
}
writer.finishLine();
++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)
{
// We have reached number of rows, stop reading the data
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::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()
@ -467,7 +518,7 @@ void PDFCCITTFaxDecoder::skipFill()
// 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).
while (m_reader.look(12) == 0)
while (!m_reader.isAtEnd() && m_reader.look(12) == 0)
{
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,
/// then 0 means black pixel and 1 white pixel.
bool hasBlackIsOne = false;
PDFImageData::MaskingType maskingType = PDFImageData::MaskingType::None;
};
enum CCITT_2D_Code_Mode;

View File

@ -20,6 +20,7 @@
#include "pdfconstants.h"
#include "pdfexception.h"
#include "pdfutils.h"
#include "pdfccittfaxdecoder.h"
#include <openjpeg.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")
{
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")
{
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")
{

View File

@ -56,10 +56,24 @@ PDFBitReader::Value PDFBitReader::read(PDFBitReader::Value bits)
return value;
}
PDFBitReader::Value PDFBitReader::look(PDFBitReader::Value bits) const
PDFBitReader::Value PDFBitReader::look(Value bits) const
{
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)