Form type XObject

This commit is contained in:
Jakub Melka
2019-06-16 16:32:23 +02:00
parent 84f26180c5
commit a429052002
3 changed files with 176 additions and 74 deletions

View File

@ -151,21 +151,11 @@ static constexpr const std::pair<const char*, PDFPageContentProcessor::Operator>
{ "EX", PDFPageContentProcessor::Operator::CompatibilityEnd }
};
PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document, const PDFFontCache* fontCache) :
m_page(page),
m_document(document),
m_fontCache(fontCache),
m_colorSpaceDictionary(nullptr),
m_fontDictionary(nullptr),
m_xobjectDictionary(nullptr),
m_textBeginEndState(0)
void PDFPageContentProcessor::initDictionaries(const PDFObject& resourcesObject)
{
Q_ASSERT(page);
Q_ASSERT(document);
auto getDictionary = [this](const char* resourceName) -> const pdf::PDFDictionary*
auto getDictionary = [this, &resourcesObject](const char* resourceName) -> const pdf::PDFDictionary*
{
const PDFObject& resources = m_document->getObject(m_page->getResources());
const PDFObject& resources = m_document->getObject(resourcesObject);
if (resources.isDictionary() && resources.getDictionary()->hasKey(resourceName))
{
const PDFObject& resourceDictionary = m_document->getObject(resources.getDictionary()->get(resourceName));
@ -181,6 +171,23 @@ PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFD
m_colorSpaceDictionary = getDictionary(COLOR_SPACE_DICTIONARY);
m_fontDictionary = getDictionary("Font");
m_xobjectDictionary = getDictionary("XObject");
m_extendedGraphicStateDictionary = getDictionary(PDF_RESOURCE_EXTGSTATE);
}
PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document, const PDFFontCache* fontCache) :
m_page(page),
m_document(document),
m_fontCache(fontCache),
m_colorSpaceDictionary(nullptr),
m_fontDictionary(nullptr),
m_xobjectDictionary(nullptr),
m_extendedGraphicStateDictionary(nullptr),
m_textBeginEndState(0)
{
Q_ASSERT(page);
Q_ASSERT(document);
initDictionaries(m_page->getResources());
}
PDFPageContentProcessor::~PDFPageContentProcessor()
@ -304,10 +311,8 @@ void PDFPageContentProcessor::performRestoreGraphicState(ProcessOrder order)
Q_UNUSED(order);
}
void PDFPageContentProcessor::processContentStream(const PDFStream* stream)
void PDFPageContentProcessor::processContent(const QByteArray& content)
{
QByteArray content = m_document->getDecodedStream(stream);
PDFLexicalAnalyzer parser(content.constBegin(), content.constEnd());
while (!parser.isAtEnd())
@ -352,6 +357,38 @@ void PDFPageContentProcessor::processContentStream(const PDFStream* stream)
}
}
void PDFPageContentProcessor::processContentStream(const PDFStream* stream)
{
QByteArray content = m_document->getDecodedStream(stream);
processContent(content);
}
void PDFPageContentProcessor::processForm(const QMatrix& matrix, const QRectF& boundingBox, const PDFObject& resources, const QByteArray& content)
{
PDFPageContentProcessorStateGuard guard(this);
QMatrix formMatrix = matrix * m_graphicState.getCurrentTransformationMatrix();
m_graphicState.setCurrentTransformationMatrix(formMatrix);
updateGraphicState();
// If the clipping box is valid, then use clipping. Clipping box is in the form coordinate system
if (boundingBox.isValid())
{
QPainterPath path;
path.addRect(boundingBox);
performClipping(path, path.fillRule());
}
// Initialize the resources, if we have them
if (!resources.isNull())
{
initDictionaries(resources);
}
processContent(content);
}
void PDFPageContentProcessor::processCommand(const QByteArray& command)
{
Operator op = Operator::Invalid;
@ -981,19 +1018,11 @@ void PDFPageContentProcessor::operatorSetFlatness(PDFReal flatness)
void PDFPageContentProcessor::operatorSetGraphicState(PDFOperandName dictionaryName)
{
const PDFObject& resources = m_page->getResources();
if (resources.isDictionary())
if (m_extendedGraphicStateDictionary)
{
const PDFDictionary* resourcesDictionary = resources.getDictionary();
if (resourcesDictionary->hasKey(PDF_RESOURCE_EXTGSTATE))
if (m_extendedGraphicStateDictionary->hasKey(dictionaryName.name))
{
const PDFObject& graphicStatesObject = m_document->getObject(resourcesDictionary->get(PDF_RESOURCE_EXTGSTATE));
if (graphicStatesObject.isDictionary())
{
const PDFDictionary* graphicStatesDictionary = graphicStatesObject.getDictionary();
if (graphicStatesDictionary->hasKey(dictionaryName.name))
{
const PDFObject& graphicStateObject = m_document->getObject(graphicStatesDictionary->get(dictionaryName.name));
const PDFObject& graphicStateObject = m_document->getObject(m_extendedGraphicStateDictionary->get(dictionaryName.name));
if (graphicStateObject.isDictionary())
{
const PDFDictionary* graphicStateDictionary = graphicStateObject.getDictionary();
@ -1046,17 +1075,7 @@ void PDFPageContentProcessor::operatorSetGraphicState(PDFOperandName dictionaryN
}
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid page resource dictionary."));
}
}
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid page resource dictionary."));
}
}
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid page resource dictionary."));
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid graphic state resource dictionary."));
}
}
@ -1808,10 +1827,42 @@ void PDFPageContentProcessor::operatorPaintXObject(PDFPageContentProcessor::PDFO
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Can't decode the image."));
}
}
else if (subtype == "Form")
{
PDFInteger formType = loader.readIntegerFromDictionary(streamDictionary, "FormType", 1);
if (formType != 1)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Form of type %1 not supported.").arg(formType));
}
// Read the bounding rectangle, if it is present
QRectF boundingBox = loader.readRectangle(streamDictionary->get("BBox"), QRectF());
// Read the transformation matrix, if it is present
QMatrix transformationMatrix;
if (streamDictionary->hasKey("Matrix"))
{
std::vector<PDFReal> matrixNumbers = loader.readNumberArrayFromDictionary(streamDictionary, "Matrix");
if (matrixNumbers.size() != 6)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid number of matrix elements. Expected 6, actual %1.").arg(matrixNumbers.size()));
}
transformationMatrix = QMatrix(matrixNumbers[0], matrixNumbers[1], matrixNumbers[2], matrixNumbers[3], matrixNumbers[4], matrixNumbers[5]);
}
// Read the dictionary content
QByteArray content = m_document->getDecodedStream(stream);
// Read resources
PDFObject resources = m_document->getObject(streamDictionary->get("Resources"));
processForm(transformationMatrix, boundingBox, resources, content);
}
else
{
// TODO: Handle another XObjects
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Unknown XObject type '%1'.").arg(QString::fromLatin1(subtype)));
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Unknown XObject type '%1'.").arg(QString::fromLatin1(subtype)));
}
}
else
@ -2224,4 +2275,25 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextCharacterSpac
}
}
PDFPageContentProcessor::PDFPageContentProcessorStateGuard::PDFPageContentProcessorStateGuard(PDFPageContentProcessor* processor) :
m_processor(processor),
m_colorSpaceDictionary(processor->m_colorSpaceDictionary),
m_fontDictionary(processor->m_fontDictionary),
m_xobjectDictionary(processor->m_xobjectDictionary),
m_extendedGraphicStateDictionary(processor->m_extendedGraphicStateDictionary)
{
m_processor->operatorSaveGraphicState();
}
PDFPageContentProcessor::PDFPageContentProcessorStateGuard::~PDFPageContentProcessorStateGuard()
{
// Restore dictionaries
m_processor->m_colorSpaceDictionary = m_colorSpaceDictionary;
m_processor->m_fontDictionary = m_fontDictionary;
m_processor->m_xobjectDictionary = m_xobjectDictionary;
m_processor->m_extendedGraphicStateDictionary = m_extendedGraphicStateDictionary;
m_processor->operatorRestoreGraphicState();
}
} // namespace pdf

View File

@ -387,12 +387,41 @@ protected:
void addError(const QString& error) { m_errorList.append(PDFRenderError(RenderErrorType::Error, error)); }
private:
/// Initializes the resources dictionaries
void initDictionaries(const PDFObject& resourcesObject);
/// Process the content stream
void processContentStream(const PDFStream* stream);
/// Process the content
void processContent(const QByteArray& content);
/// Processes single command
void processCommand(const QByteArray& command);
/// Processes form (XObject of type form)
/// \param Matrix Transformation matrix from form coordinate system to page coordinate system
/// \param boundingBox Bounding box, to which is drawed content clipped
/// \param resources Resources, assigned to the form
/// \param content Content stream of the form
void processForm(const QMatrix& matrix, const QRectF& boundingBox, const PDFObject& resources, const QByteArray& content);
struct PDFPageContentProcessorStateGuard
{
public:
explicit PDFPageContentProcessorStateGuard(PDFPageContentProcessor* processor);
~PDFPageContentProcessorStateGuard();
private:
PDFPageContentProcessor* m_processor;
// Stored resources
const PDFDictionary* m_colorSpaceDictionary;
const PDFDictionary* m_fontDictionary;
const PDFDictionary* m_xobjectDictionary;
const PDFDictionary* m_extendedGraphicStateDictionary;
};
/// Wrapper for PDF Name
struct PDFOperandName
{
@ -585,6 +614,7 @@ private:
const PDFDictionary* m_colorSpaceDictionary;
const PDFDictionary* m_fontDictionary;
const PDFDictionary* m_xobjectDictionary;
const PDFDictionary* m_extendedGraphicStateDictionary;
// Default color spaces
PDFColorSpacePointer m_deviceGrayColorSpace;

BIN
libjpeg/bin/jpeg.pdb Normal file

Binary file not shown.