Annotation painting, first part

This commit is contained in:
Jakub Melka
2020-03-29 18:53:04 +02:00
parent 8bce1bc1e5
commit 232832e753
20 changed files with 1175 additions and 339 deletions

View File

@ -188,7 +188,7 @@ void PDFExamplesGenerator::generateAnnotationsExample()
{ {
pdf::PDFObjectReference annotation = builder.createAnnotationSquare(page5, QRectF(150, 250, 50, 50), 3.0, Qt::green, Qt::red, "Title1", "Subject1", "Contents - green filling, red boundary"); pdf::PDFObjectReference annotation = builder.createAnnotationSquare(page5, QRectF(150, 250, 50, 50), 3.0, Qt::green, Qt::red, "Title1", "Subject1", "Contents - green filling, red boundary");
builder.setAnnotationBorderStyle(annotation, pdf::PDFAnnotationBorder::Style::Inset, 2.718); builder.setAnnotationBorder(annotation, 5.0, 3.0, 2.0);
builder.setAnnotationColor(annotation, Qt::black); builder.setAnnotationColor(annotation, Qt::black);
} }
} }

View File

@ -23,10 +23,10 @@
namespace pdf namespace pdf
{ {
PDFActionPtr PDFAction::parse(const PDFDocument* document, PDFObject object) PDFActionPtr PDFAction::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
std::set<PDFObjectReference> usedReferences; std::set<PDFObjectReference> usedReferences;
return parseImpl(document, qMove(object), usedReferences); return parseImpl(storage, qMove(object), usedReferences);
} }
void PDFAction::apply(const std::function<void (const PDFAction*)>& callback) void PDFAction::apply(const std::function<void (const PDFAction*)>& callback)
@ -46,7 +46,7 @@ std::vector<const PDFAction*> PDFAction::getActionList() const
return result; return result;
} }
PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object, std::set<PDFObjectReference>& usedReferences) PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject object, std::set<PDFObjectReference>& usedReferences)
{ {
if (object.isReference()) if (object.isReference())
{ {
@ -56,7 +56,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
throw PDFException(PDFTranslationContext::tr("Circular dependence in actions found.")); throw PDFException(PDFTranslationContext::tr("Circular dependence in actions found."));
} }
usedReferences.insert(reference); usedReferences.insert(reference);
object = document->getObjectByReference(reference); object = storage->getObjectByReference(reference);
} }
if (object.isNull()) if (object.isNull())
@ -69,34 +69,34 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
throw PDFException(PDFTranslationContext::tr("Invalid action.")); throw PDFException(PDFTranslationContext::tr("Invalid action."));
} }
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
const PDFDictionary* dictionary = object.getDictionary(); const PDFDictionary* dictionary = object.getDictionary();
QByteArray name = loader.readNameFromDictionary(dictionary, "S"); QByteArray name = loader.readNameFromDictionary(dictionary, "S");
if (name == "GoTo") // Goto action if (name == "GoTo") // Goto action
{ {
PDFDestination destination = PDFDestination::parse(document, dictionary->get("D")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
return PDFActionPtr(new PDFActionGoTo(qMove(destination))); return PDFActionPtr(new PDFActionGoTo(qMove(destination)));
} }
else if (name == "GoToR") else if (name == "GoToR")
{ {
PDFDestination destination = PDFDestination::parse(document, dictionary->get("D")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false))); return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false)));
} }
else if (name == "GoToE") else if (name == "GoToE")
{ {
PDFDestination destination = PDFDestination::parse(document, dictionary->get("D")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToE(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false), document->getObject(dictionary->get("T")))); return PDFActionPtr(new PDFActionGoToE(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false), storage->getObject(dictionary->get("T"))));
} }
else if (name == "Launch") else if (name == "Launch")
{ {
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
const bool newWindow = loader.readBooleanFromDictionary(dictionary, "NewWindow", false); const bool newWindow = loader.readBooleanFromDictionary(dictionary, "NewWindow", false);
PDFActionLaunch::Win win; PDFActionLaunch::Win win;
const PDFObject& winDictionaryObject = document->getObject(dictionary->get("Win")); const PDFObject& winDictionaryObject = storage->getObject(dictionary->get("Win"));
if (winDictionaryObject.isDictionary()) if (winDictionaryObject.isDictionary())
{ {
const PDFDictionary* winDictionary = winDictionaryObject.getDictionary(); const PDFDictionary* winDictionary = winDictionaryObject.getDictionary();
@ -110,7 +110,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
} }
else if (name == "Thread") else if (name == "Thread")
{ {
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
PDFActionThread::Thread thread; PDFActionThread::Thread thread;
PDFActionThread::Bead bead; PDFActionThread::Bead bead;
@ -149,7 +149,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
const bool isSynchronous = loader.readBooleanFromDictionary(dictionary, "Synchronous", false); const bool isSynchronous = loader.readBooleanFromDictionary(dictionary, "Synchronous", false);
const bool isRepeat = loader.readBooleanFromDictionary(dictionary, "Repeat", false); const bool isRepeat = loader.readBooleanFromDictionary(dictionary, "Repeat", false);
const bool isMix = loader.readBooleanFromDictionary(dictionary, "Mix", false); const bool isMix = loader.readBooleanFromDictionary(dictionary, "Mix", false);
return PDFActionPtr(new PDFActionSound(PDFSound::parse(document, dictionary->get("Sound")), volume, isSynchronous, isRepeat, isMix)); return PDFActionPtr(new PDFActionSound(PDFSound::parse(storage, dictionary->get("Sound")), volume, isSynchronous, isRepeat, isMix));
} }
else if (name == "Movie") else if (name == "Movie")
{ {
@ -220,7 +220,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
const bool isRadioButtonsPreserved = loader.readBooleanFromDictionary(dictionary, "PreserveRB", true); const bool isRadioButtonsPreserved = loader.readBooleanFromDictionary(dictionary, "PreserveRB", true);
PDFActionSetOCGState::StateChangeItems items; PDFActionSetOCGState::StateChangeItems items;
PDFObject stateArrayObject = document->getObject(dictionary->get("State")); PDFObject stateArrayObject = storage->getObject(dictionary->get("State"));
if (stateArrayObject.isArray()) if (stateArrayObject.isArray())
{ {
constexpr const std::array<std::pair<const char*, PDFActionSetOCGState::SwitchType>, 3> types = { constexpr const std::array<std::pair<const char*, PDFActionSetOCGState::SwitchType>, 3> types = {
@ -258,23 +258,23 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
if (dictionary->hasKey("R")) if (dictionary->hasKey("R"))
{ {
rendition = PDFRendition::parse(document, dictionary->get("R")); rendition = PDFRendition::parse(storage, dictionary->get("R"));
} }
PDFObject javascriptObject = document->getObject(dictionary->get("JS")); PDFObject javascriptObject = storage->getObject(dictionary->get("JS"));
if (javascriptObject.isString()) if (javascriptObject.isString())
{ {
javascript = PDFEncoding::convertTextString(javascriptObject.getString()); javascript = PDFEncoding::convertTextString(javascriptObject.getString());
} }
else if (javascriptObject.isStream()) else if (javascriptObject.isStream())
{ {
javascript = PDFEncoding::convertTextString(document->getDecodedStream(javascriptObject.getStream())); javascript = PDFEncoding::convertTextString(storage->getDecodedStream(javascriptObject.getStream()));
} }
return PDFActionPtr(new PDFActionRendition(qMove(rendition), annotation, operation, qMove(javascript))); return PDFActionPtr(new PDFActionRendition(qMove(rendition), annotation, operation, qMove(javascript)));
} }
else if (name == "Trans") else if (name == "Trans")
{ {
return PDFActionPtr(new PDFActionTransition(PDFPageTransition::parse(document, dictionary->get("Trans")))); return PDFActionPtr(new PDFActionTransition(PDFPageTransition::parse(storage, dictionary->get("Trans"))));
} }
else if (name == "GoTo3DView") else if (name == "GoTo3DView")
{ {
@ -283,14 +283,14 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
else if (name == "JavaScript") else if (name == "JavaScript")
{ {
QByteArray textJavaScript; QByteArray textJavaScript;
const PDFObject& javaScriptObject = document->getObject(dictionary->get("JS")); const PDFObject& javaScriptObject = storage->getObject(dictionary->get("JS"));
if (javaScriptObject.isString()) if (javaScriptObject.isString())
{ {
textJavaScript = javaScriptObject.getString(); textJavaScript = javaScriptObject.getString();
} }
else if (javaScriptObject.isStream()) else if (javaScriptObject.isStream())
{ {
textJavaScript = document->getDecodedStream(javaScriptObject.getStream()); textJavaScript = storage->getDecodedStream(javaScriptObject.getStream());
} }
return PDFActionPtr(new PDFActionJavaScript(PDFEncoding::convertTextString(textJavaScript))); return PDFActionPtr(new PDFActionJavaScript(PDFEncoding::convertTextString(textJavaScript)));
} }
@ -311,10 +311,10 @@ void PDFAction::fillActionList(std::vector<const PDFAction*>& actionList) const
} }
} }
PDFDestination PDFDestination::parse(const PDFDocument* document, PDFObject object) PDFDestination PDFDestination::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFDestination result; PDFDestination result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isName() || object.isString()) if (object.isName() || object.isString())
{ {
@ -330,7 +330,7 @@ PDFDestination PDFDestination::parse(const PDFDocument* document, PDFObject obje
return result; return result;
} }
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
// First parse page number/page index // First parse page number/page index
PDFObject pageNumberObject = array->getItem(0); PDFObject pageNumberObject = array->getItem(0);

View File

@ -34,6 +34,7 @@ namespace pdf
{ {
class PDFAction; class PDFAction;
class PDFDocument; class PDFDocument;
class PDFObjectStorage;
enum class ActionType enum class ActionType
{ {
@ -87,9 +88,9 @@ public:
/// Parses the destination from the object. If object contains invalid destination, /// Parses the destination from the object. If object contains invalid destination,
/// then empty destination is returned. If object is empty, empty destination is returned. /// then empty destination is returned. If object is empty, empty destination is returned.
/// \param document Document /// \param storage Object storage
/// \param object Destination object /// \param object Destination object
static PDFDestination parse(const PDFDocument* document, PDFObject object); static PDFDestination parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
DestinationType m_destinationType = DestinationType::Invalid; DestinationType m_destinationType = DestinationType::Invalid;
@ -120,9 +121,9 @@ public:
/// Tries to parse the action. If serious error occurs, then exception is thrown. /// Tries to parse the action. If serious error occurs, then exception is thrown.
/// If \p object is null object, then nullptr is returned. /// If \p object is null object, then nullptr is returned.
/// \param document Document /// \param storage Object storage
/// \param object Object containing the action /// \param object Object containing the action
static PDFActionPtr parse(const PDFDocument* document, PDFObject object); static PDFActionPtr parse(const PDFObjectStorage* storage, PDFObject object);
/// Calls the lambda function with action as parameter, then following /// Calls the lambda function with action as parameter, then following
/// the 'Next' entry, as described by PDF 1.7 specification. /// the 'Next' entry, as described by PDF 1.7 specification.
@ -132,7 +133,7 @@ public:
std::vector<const PDFAction*> getActionList() const; std::vector<const PDFAction*> getActionList() const;
private: private:
static PDFActionPtr parseImpl(const PDFDocument* document, PDFObject object, std::set<PDFObjectReference>& usedReferences); static PDFActionPtr parseImpl(const PDFObjectStorage* storage, PDFObject object, std::set<PDFObjectReference>& usedReferences);
void fillActionList(std::vector<const PDFAction*>& actionList) const; void fillActionList(std::vector<const PDFAction*>& actionList) const;

View File

@ -22,21 +22,22 @@
#include "pdfdrawspacecontroller.h" #include "pdfdrawspacecontroller.h"
#include "pdfcms.h" #include "pdfcms.h"
#include "pdfwidgetutils.h" #include "pdfwidgetutils.h"
#include "pdfpagecontentprocessor.h"
namespace pdf namespace pdf
{ {
PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document, PDFObject object) PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationBorder result; PDFAnnotationBorder result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isArray()) if (object.isArray())
{ {
const PDFArray* array = object.getArray(); const PDFArray* array = object.getArray();
if (array->getCount() >= 3) if (array->getCount() >= 3)
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_definition = Definition::Simple; result.m_definition = Definition::Simple;
result.m_hCornerRadius = loader.readNumber(array->getItem(0), 0.0); result.m_hCornerRadius = loader.readNumber(array->getItem(0), 0.0);
result.m_vCornerRadius = loader.readNumber(array->getItem(1), 0.0); result.m_vCornerRadius = loader.readNumber(array->getItem(1), 0.0);
@ -52,13 +53,13 @@ PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document
return result; return result;
} }
PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFDocument* document, PDFObject object) PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationBorder result; PDFAnnotationBorder result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_definition = Definition::BorderStyle; result.m_definition = Definition::BorderStyle;
result.m_width = loader.readNumberFromDictionary(dictionary, "W", 1.0); result.m_width = loader.readNumberFromDictionary(dictionary, "W", 1.0);
@ -76,13 +77,13 @@ PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFDocument* document, PD
return result; return result;
} }
PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFDocument* document, PDFObject object) PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationBorderEffect result; PDFAnnotationBorderEffect result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_intensity = loader.readNumberFromDictionary(dictionary, "I", 0.0); result.m_intensity = loader.readNumberFromDictionary(dictionary, "I", 0.0);
constexpr const std::array<std::pair<const char*, Effect>, 2> effects = { constexpr const std::array<std::pair<const char*, Effect>, 2> effects = {
@ -96,16 +97,16 @@ PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFDocument* do
return result; return result;
} }
PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFDocument* document, PDFObject object) PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAppeareanceStreams result; PDFAppeareanceStreams result;
auto processSubdicitonary = [&result, document](Appearance appearance, PDFObject subdictionaryObject) auto processSubdicitonary = [&result, storage](Appearance appearance, PDFObject subdictionaryObject)
{ {
subdictionaryObject = document->getObject(subdictionaryObject); subdictionaryObject = storage->getObject(subdictionaryObject);
if (subdictionaryObject.isDictionary()) if (subdictionaryObject.isDictionary())
{ {
const PDFDictionary* subdictionary = document->getDictionaryFromObject(subdictionaryObject); const PDFDictionary* subdictionary = storage->getDictionaryFromObject(subdictionaryObject);
for (size_t i = 0; i < subdictionary->getCount(); ++i) for (size_t i = 0; i < subdictionary->getCount(); ++i)
{ {
result.m_appearanceStreams[std::make_pair(appearance, subdictionary->getKey(i))] = subdictionary->getValue(i); result.m_appearanceStreams[std::make_pair(appearance, subdictionary->getKey(i))] = subdictionary->getValue(i);
@ -117,7 +118,7 @@ PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFDocument* document,
} }
}; };
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
processSubdicitonary(Appearance::Normal, dictionary->get("N")); processSubdicitonary(Appearance::Normal, dictionary->get("N"));
processSubdicitonary(Appearance::Rollover, dictionary->get("R")); processSubdicitonary(Appearance::Rollover, dictionary->get("R"));
@ -158,17 +159,27 @@ PDFAnnotation::PDFAnnotation() :
} }
PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object) void PDFAnnotation::draw(AnnotationDrawParameters& parameters) const
{
Q_UNUSED(parameters);
}
std::vector<PDFAppeareanceStreams::Key> PDFAnnotation::getDrawKeys() const
{
return { PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Normal, QByteArray() } };
}
PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationPtr result; PDFAnnotationPtr result;
const PDFDictionary* dictionary = document->getDictionaryFromObject(object); const PDFDictionary* dictionary = storage->getDictionaryFromObject(object);
if (!dictionary) if (!dictionary)
{ {
return result; return result;
} }
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
QRectF annotationsRectangle = loader.readRectangle(dictionary->get("Rect"), QRectF()); QRectF annotationsRectangle = loader.readRectangle(dictionary->get("Rect"), QRectF());
@ -189,13 +200,13 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFLinkAnnotation* linkAnnotation = new PDFLinkAnnotation; PDFLinkAnnotation* linkAnnotation = new PDFLinkAnnotation;
result.reset(linkAnnotation); result.reset(linkAnnotation);
linkAnnotation->m_action = PDFAction::parse(document, dictionary->get("A")); linkAnnotation->m_action = PDFAction::parse(storage, dictionary->get("A"));
if (!linkAnnotation->m_action) if (!linkAnnotation->m_action)
{ {
PDFDestination destination = PDFDestination::parse(document, dictionary->get("Dest")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("Dest"));
linkAnnotation->m_action.reset(new PDFActionGoTo(destination)); linkAnnotation->m_action.reset(new PDFActionGoTo(destination));
} }
linkAnnotation->m_previousAction = PDFAction::parse(document, dictionary->get("PA")); linkAnnotation->m_previousAction = PDFAction::parse(storage, dictionary->get("PA"));
constexpr const std::array<std::pair<const char*, LinkHighlightMode>, 4> highlightMode = { constexpr const std::array<std::pair<const char*, LinkHighlightMode>, 4> highlightMode = {
std::pair<const char*, LinkHighlightMode>{ "N", LinkHighlightMode::None }, std::pair<const char*, LinkHighlightMode>{ "N", LinkHighlightMode::None },
@ -205,7 +216,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
}; };
linkAnnotation->m_highlightMode = loader.readEnumByName(dictionary->get("H"), highlightMode.begin(), highlightMode.end(), LinkHighlightMode::Invert); linkAnnotation->m_highlightMode = loader.readEnumByName(dictionary->get("H"), highlightMode.begin(), highlightMode.end(), LinkHighlightMode::Invert);
linkAnnotation->m_activationRegion = parseQuadrilaterals(document, dictionary->get("QuadPoints"), annotationsRectangle); linkAnnotation->m_activationRegion = parseQuadrilaterals(storage, dictionary->get("QuadPoints"), annotationsRectangle);
} }
else if (subtype == "FreeText") else if (subtype == "FreeText")
{ {
@ -220,9 +231,9 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
freeTextAnnotation->m_defaultAppearance = loader.readStringFromDictionary(dictionary, "DA"); freeTextAnnotation->m_defaultAppearance = loader.readStringFromDictionary(dictionary, "DA");
freeTextAnnotation->m_justification = static_cast<PDFFreeTextAnnotation::Justification>(loader.readIntegerFromDictionary(dictionary, "Q", 0)); freeTextAnnotation->m_justification = static_cast<PDFFreeTextAnnotation::Justification>(loader.readIntegerFromDictionary(dictionary, "Q", 0));
freeTextAnnotation->m_defaultStyleString = loader.readTextStringFromDictionary(dictionary, "DS", QString()); freeTextAnnotation->m_defaultStyleString = loader.readTextStringFromDictionary(dictionary, "DS", QString());
freeTextAnnotation->m_calloutLine = PDFAnnotationCalloutLine::parse(document, dictionary->get("CL")); freeTextAnnotation->m_calloutLine = PDFAnnotationCalloutLine::parse(storage, dictionary->get("CL"));
freeTextAnnotation->m_intent = loader.readEnumByName(dictionary->get("IT"), intents.begin(), intents.end(), PDFFreeTextAnnotation::Intent::None); freeTextAnnotation->m_intent = loader.readEnumByName(dictionary->get("IT"), intents.begin(), intents.end(), PDFFreeTextAnnotation::Intent::None);
freeTextAnnotation->m_effect = PDFAnnotationBorderEffect::parse(document, dictionary->get("BE")); freeTextAnnotation->m_effect = PDFAnnotationBorderEffect::parse(storage, dictionary->get("BE"));
std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD"); std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD");
if (differenceRectangle.size() == 4) if (differenceRectangle.size() == 4)
@ -266,7 +277,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
lineAnnotation->m_captionRendered = loader.readBooleanFromDictionary(dictionary, "Cap", false); lineAnnotation->m_captionRendered = loader.readBooleanFromDictionary(dictionary, "Cap", false);
lineAnnotation->m_intent = (loader.readNameFromDictionary(dictionary, "IT") == "LineDimension") ? PDFLineAnnotation::Intent::Dimension : PDFLineAnnotation::Intent::Arrow; lineAnnotation->m_intent = (loader.readNameFromDictionary(dictionary, "IT") == "LineDimension") ? PDFLineAnnotation::Intent::Dimension : PDFLineAnnotation::Intent::Arrow;
lineAnnotation->m_captionPosition = (loader.readNameFromDictionary(dictionary, "CP") == "Top") ? PDFLineAnnotation::CaptionPosition::Top : PDFLineAnnotation::CaptionPosition::Inline; lineAnnotation->m_captionPosition = (loader.readNameFromDictionary(dictionary, "CP") == "Top") ? PDFLineAnnotation::CaptionPosition::Top : PDFLineAnnotation::CaptionPosition::Inline;
lineAnnotation->m_measureDictionary = document->getObject(dictionary->get("Measure")); lineAnnotation->m_measureDictionary = storage->getObject(dictionary->get("Measure"));
std::vector<PDFReal> captionOffset = loader.readNumberArrayFromDictionary(dictionary, "CO"); std::vector<PDFReal> captionOffset = loader.readNumberArrayFromDictionary(dictionary, "CO");
if (captionOffset.size() == 2) if (captionOffset.size() == 2)
@ -280,7 +291,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
result.reset(annotation); result.reset(annotation);
annotation->m_interiorColor = loader.readNumberArrayFromDictionary(dictionary, "IC"); annotation->m_interiorColor = loader.readNumberArrayFromDictionary(dictionary, "IC");
annotation->m_effect = PDFAnnotationBorderEffect::parse(document, dictionary->get("BE")); annotation->m_effect = PDFAnnotationBorderEffect::parse(storage, dictionary->get("BE"));
std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD"); std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD");
if (differenceRectangle.size() == 4) if (differenceRectangle.size() == 4)
@ -313,7 +324,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
} }
annotation->m_interiorColor = loader.readNumberArrayFromDictionary(dictionary, "IC"); annotation->m_interiorColor = loader.readNumberArrayFromDictionary(dictionary, "IC");
annotation->m_effect = PDFAnnotationBorderEffect::parse(document, dictionary->get("BE")); annotation->m_effect = PDFAnnotationBorderEffect::parse(storage, dictionary->get("BE"));
constexpr const std::array<std::pair<const char*, PDFPolygonalGeometryAnnotation::Intent>, 3> intents = { constexpr const std::array<std::pair<const char*, PDFPolygonalGeometryAnnotation::Intent>, 3> intents = {
std::pair<const char*, PDFPolygonalGeometryAnnotation::Intent>{ "PolygonCloud", PDFPolygonalGeometryAnnotation::Intent::Cloud }, std::pair<const char*, PDFPolygonalGeometryAnnotation::Intent>{ "PolygonCloud", PDFPolygonalGeometryAnnotation::Intent::Cloud },
@ -322,7 +333,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
}; };
annotation->m_intent = loader.readEnumByName(dictionary->get("IT"), intents.begin(), intents.end(), PDFPolygonalGeometryAnnotation::Intent::None); annotation->m_intent = loader.readEnumByName(dictionary->get("IT"), intents.begin(), intents.end(), PDFPolygonalGeometryAnnotation::Intent::None);
annotation->m_measure = document->getObject(dictionary->get("Measure")); annotation->m_measure = storage->getObject(dictionary->get("Measure"));
} }
else if (subtype == "Highlight" || else if (subtype == "Highlight" ||
subtype == "Underline" || subtype == "Underline" ||
@ -346,7 +357,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFHighlightAnnotation* annotation = new PDFHighlightAnnotation(type); PDFHighlightAnnotation* annotation = new PDFHighlightAnnotation(type);
result.reset(annotation); result.reset(annotation);
annotation->m_highlightArea = parseQuadrilaterals(document, dictionary->get("QuadPoints"), annotationsRectangle); annotation->m_highlightArea = parseQuadrilaterals(storage, dictionary->get("QuadPoints"), annotationsRectangle);
} }
else if (subtype == "Caret") else if (subtype == "Caret")
{ {
@ -394,7 +405,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFInkAnnotation* annotation = new PDFInkAnnotation(); PDFInkAnnotation* annotation = new PDFInkAnnotation();
result.reset(annotation); result.reset(annotation);
PDFObject inkList = document->getObject(dictionary->get("InkList")); PDFObject inkList = storage->getObject(dictionary->get("InkList"));
if (inkList.isArray()) if (inkList.isArray())
{ {
const PDFArray* inkListArray = inkList.getArray(); const PDFArray* inkListArray = inkList.getArray();
@ -432,7 +443,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFFileAttachmentAnnotation* annotation = new PDFFileAttachmentAnnotation(); PDFFileAttachmentAnnotation* annotation = new PDFFileAttachmentAnnotation();
result.reset(annotation); result.reset(annotation);
annotation->m_fileSpecification = PDFFileSpecification::parse(document, dictionary->get("FS")); annotation->m_fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("FS"));
constexpr const std::array<std::pair<const char*, PDFFileAttachmentAnnotation::Icon>, 4> icons = { constexpr const std::array<std::pair<const char*, PDFFileAttachmentAnnotation::Icon>, 4> icons = {
std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "Graph", PDFFileAttachmentAnnotation::Icon::Graph }, std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "Graph", PDFFileAttachmentAnnotation::Icon::Graph },
@ -448,7 +459,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFSoundAnnotation* annotation = new PDFSoundAnnotation(); PDFSoundAnnotation* annotation = new PDFSoundAnnotation();
result.reset(annotation); result.reset(annotation);
annotation->m_sound = PDFSound::parse(document, dictionary->get("Sound")); annotation->m_sound = PDFSound::parse(storage, dictionary->get("Sound"));
constexpr const std::array<std::pair<const char*, PDFSoundAnnotation::Icon>, 2> icons = { constexpr const std::array<std::pair<const char*, PDFSoundAnnotation::Icon>, 2> icons = {
std::pair<const char*, PDFSoundAnnotation::Icon>{ "Speaker", PDFSoundAnnotation::Icon::Speaker }, std::pair<const char*, PDFSoundAnnotation::Icon>{ "Speaker", PDFSoundAnnotation::Icon::Speaker },
@ -463,9 +474,9 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
result.reset(annotation); result.reset(annotation);
annotation->m_movieTitle = loader.readStringFromDictionary(dictionary, "T"); annotation->m_movieTitle = loader.readStringFromDictionary(dictionary, "T");
annotation->m_movie = PDFMovie::parse(document, dictionary->get("Movie")); annotation->m_movie = PDFMovie::parse(storage, dictionary->get("Movie"));
PDFObject activation = document->getObject(dictionary->get("A")); PDFObject activation = storage->getObject(dictionary->get("A"));
if (activation.isBool()) if (activation.isBool())
{ {
annotation->m_playMovie = activation.getBool(); annotation->m_playMovie = activation.getBool();
@ -473,7 +484,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
else if (activation.isDictionary()) else if (activation.isDictionary())
{ {
annotation->m_playMovie = true; annotation->m_playMovie = true;
annotation->m_movieActivation = PDFMovieActivation::parse(document, activation); annotation->m_movieActivation = PDFMovieActivation::parse(storage, activation);
} }
} }
else if (subtype == "Screen") else if (subtype == "Screen")
@ -482,9 +493,9 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
result.reset(annotation); result.reset(annotation);
annotation->m_screenTitle = loader.readTextStringFromDictionary(dictionary, "T", QString()); annotation->m_screenTitle = loader.readTextStringFromDictionary(dictionary, "T", QString());
annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(document, dictionary->get("MK")); annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(storage, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(document, dictionary->get("A")); annotation->m_action = PDFAction::parse(storage, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(document, dictionary->get("AA")); annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(storage, dictionary->get("AA"));
} }
else if (subtype == "Widget") else if (subtype == "Widget")
{ {
@ -500,9 +511,9 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
}; };
annotation->m_highlightMode = loader.readEnumByName(dictionary->get("H"), highlightModes.begin(), highlightModes.end(), PDFWidgetAnnotation::HighlightMode::Invert); annotation->m_highlightMode = loader.readEnumByName(dictionary->get("H"), highlightModes.begin(), highlightModes.end(), PDFWidgetAnnotation::HighlightMode::Invert);
annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(document, dictionary->get("MK")); annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(storage, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(document, dictionary->get("A")); annotation->m_action = PDFAction::parse(storage, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(document, dictionary->get("AA")); annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(storage, dictionary->get("AA"));
} }
else if (subtype == "PrinterMark") else if (subtype == "PrinterMark")
{ {
@ -519,7 +530,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFWatermarkAnnotation* annotation = new PDFWatermarkAnnotation(); PDFWatermarkAnnotation* annotation = new PDFWatermarkAnnotation();
result.reset(annotation); result.reset(annotation);
if (const PDFDictionary* fixedPrintDictionary = document->getDictionaryFromObject(dictionary->get("FixedPrint"))) if (const PDFDictionary* fixedPrintDictionary = storage->getDictionaryFromObject(dictionary->get("FixedPrint")))
{ {
annotation->m_matrix = loader.readMatrixFromDictionary(fixedPrintDictionary, "Matrix", QMatrix()); annotation->m_matrix = loader.readMatrixFromDictionary(fixedPrintDictionary, "Matrix", QMatrix());
annotation->m_relativeHorizontalOffset = loader.readNumberFromDictionary(fixedPrintDictionary, "H", 0.0); annotation->m_relativeHorizontalOffset = loader.readNumberFromDictionary(fixedPrintDictionary, "H", 0.0);
@ -547,13 +558,13 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
} }
result->m_flags = Flags(loader.readIntegerFromDictionary(dictionary, "F", 0)); result->m_flags = Flags(loader.readIntegerFromDictionary(dictionary, "F", 0));
result->m_appearanceStreams = PDFAppeareanceStreams::parse(document, dictionary->get("AP")); result->m_appearanceStreams = PDFAppeareanceStreams::parse(storage, dictionary->get("AP"));
result->m_appearanceState = loader.readNameFromDictionary(dictionary, "AS"); result->m_appearanceState = loader.readNameFromDictionary(dictionary, "AS");
result->m_annotationBorder = PDFAnnotationBorder::parseBS(document, dictionary->get("BS")); result->m_annotationBorder = PDFAnnotationBorder::parseBS(storage, dictionary->get("BS"));
if (!result->m_annotationBorder.isValid()) if (!result->m_annotationBorder.isValid())
{ {
result->m_annotationBorder = PDFAnnotationBorder::parseBorder(document, dictionary->get("Border")); result->m_annotationBorder = PDFAnnotationBorder::parseBorder(storage, dictionary->get("Border"));
} }
result->m_color = loader.readNumberArrayFromDictionary(dictionary, "C"); result->m_color = loader.readNumberArrayFromDictionary(dictionary, "C");
result->m_structParent = loader.readIntegerFromDictionary(dictionary, "StructParent", 0); result->m_structParent = loader.readIntegerFromDictionary(dictionary, "StructParent", 0);
@ -570,18 +581,18 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
markupAnnotation->m_subject = loader.readTextStringFromDictionary(dictionary, "Subj", QString()); markupAnnotation->m_subject = loader.readTextStringFromDictionary(dictionary, "Subj", QString());
markupAnnotation->m_replyType = (loader.readNameFromDictionary(dictionary, "RT") == "Group") ? PDFMarkupAnnotation::ReplyType::Group : PDFMarkupAnnotation::ReplyType::Reply; markupAnnotation->m_replyType = (loader.readNameFromDictionary(dictionary, "RT") == "Group") ? PDFMarkupAnnotation::ReplyType::Group : PDFMarkupAnnotation::ReplyType::Reply;
markupAnnotation->m_intent = loader.readNameFromDictionary(dictionary, "IT"); markupAnnotation->m_intent = loader.readNameFromDictionary(dictionary, "IT");
markupAnnotation->m_externalData = document->getObject(dictionary->get("ExData")); markupAnnotation->m_externalData = storage->getObject(dictionary->get("ExData"));
} }
return result; return result;
} }
PDFAnnotationQuadrilaterals PDFAnnotation::parseQuadrilaterals(const PDFDocument* document, PDFObject quadrilateralsObject, const QRectF annotationRect) PDFAnnotationQuadrilaterals PDFAnnotation::parseQuadrilaterals(const PDFObjectStorage* storage, PDFObject quadrilateralsObject, const QRectF annotationRect)
{ {
QPainterPath path; QPainterPath path;
std::vector<QLineF> underlines; std::vector<QLineF> underlines;
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
std::vector<PDFReal> points = loader.readNumberArray(quadrilateralsObject); std::vector<PDFReal> points = loader.readNumberArray(quadrilateralsObject);
const size_t quadrilateralCount = points.size() % 8; const size_t quadrilateralCount = points.size() % 8;
path.reserve(int(quadrilateralCount) + 5); path.reserve(int(quadrilateralCount) + 5);
@ -639,9 +650,89 @@ AnnotationLineEnding PDFAnnotation::convertNameToLineEnding(const QByteArray& na
return AnnotationLineEnding::None; return AnnotationLineEnding::None;
} }
PDFAnnotationCalloutLine PDFAnnotationCalloutLine::parse(const PDFDocument* document, PDFObject object) QColor PDFAnnotation::getStrokeColor() const
{ {
PDFDocumentDataLoaderDecorator loader(document); return getDrawColorFromAnnotationColor(getColor());
}
QColor PDFAnnotation::getFillColor() const
{
return QColor();
}
QColor PDFAnnotation::getDrawColorFromAnnotationColor(const std::vector<PDFReal>& color) const
{
switch (color.size())
{
case 1:
{
const PDFReal gray = color.back();
return QColor::fromRgbF(gray, gray, gray, 1.0);
}
case 3:
{
const PDFReal r = color[0];
const PDFReal g = color[1];
const PDFReal b = color[2];
return QColor::fromRgbF(r, g, b, 1.0);
}
case 4:
{
const PDFReal c = color[0];
const PDFReal m = color[1];
const PDFReal y = color[2];
const PDFReal k = color[3];
return QColor::fromCmykF(c, m, y, k, 1.0);
}
default:
break;
}
return QColor(Qt::black);
}
QPen PDFAnnotation::getPen() const
{
QColor strokeColor = getStrokeColor();
const PDFAnnotationBorder& border = getBorder();
if (qFuzzyIsNull(border.getWidth()))
{
// No border is drawn
return Qt::NoPen;
}
QPen pen(strokeColor);
pen.setWidthF(border.getWidth());
if (!border.getDashPattern().empty())
{
PDFLineDashPattern lineDashPattern(border.getDashPattern(), 0.0);
pen.setStyle(Qt::CustomDashLine);
pen.setDashPattern(QVector<PDFReal>::fromStdVector(lineDashPattern.getDashArray()));
pen.setDashOffset(lineDashPattern.getDashOffset());
}
return pen;
}
QBrush PDFAnnotation::getBrush() const
{
QColor color = getFillColor();
if (color.isValid())
{
return QBrush(color, Qt::SolidPattern);
}
return QBrush(Qt::NoBrush);
}
PDFAnnotationCalloutLine PDFAnnotationCalloutLine::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFDocumentDataLoaderDecorator loader(storage);
std::vector<PDFReal> points = loader.readNumberArray(object); std::vector<PDFReal> points = loader.readNumberArray(object);
switch (points.size()) switch (points.size())
@ -659,13 +750,13 @@ PDFAnnotationCalloutLine PDFAnnotationCalloutLine::parse(const PDFDocument* docu
return PDFAnnotationCalloutLine(); return PDFAnnotationCalloutLine();
} }
PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::parse(const PDFDocument* document, PDFObject object) PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationAppearanceCharacteristics result; PDFAnnotationAppearanceCharacteristics result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_rotation = loader.readIntegerFromDictionary(dictionary, "R", 0); result.m_rotation = loader.readIntegerFromDictionary(dictionary, "R", 0);
result.m_borderColor = loader.readNumberArrayFromDictionary(dictionary, "BC"); result.m_borderColor = loader.readNumberArrayFromDictionary(dictionary, "BC");
@ -673,22 +764,22 @@ PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::p
result.m_normalCaption = loader.readTextStringFromDictionary(dictionary, "CA", QString()); result.m_normalCaption = loader.readTextStringFromDictionary(dictionary, "CA", QString());
result.m_rolloverCaption = loader.readTextStringFromDictionary(dictionary, "RC", QString()); result.m_rolloverCaption = loader.readTextStringFromDictionary(dictionary, "RC", QString());
result.m_downCaption = loader.readTextStringFromDictionary(dictionary, "AC", QString()); result.m_downCaption = loader.readTextStringFromDictionary(dictionary, "AC", QString());
result.m_normalIcon = document->getObject(dictionary->get("I")); result.m_normalIcon = storage->getObject(dictionary->get("I"));
result.m_rolloverIcon = document->getObject(dictionary->get("RI")); result.m_rolloverIcon = storage->getObject(dictionary->get("RI"));
result.m_downIcon = document->getObject(dictionary->get("IX")); result.m_downIcon = storage->getObject(dictionary->get("IX"));
result.m_iconFit = PDFAnnotationIconFitInfo::parse(document, dictionary->get("IF")); result.m_iconFit = PDFAnnotationIconFitInfo::parse(storage, dictionary->get("IF"));
result.m_pushButtonMode = static_cast<PushButtonMode>(loader.readIntegerFromDictionary(dictionary, "TP", PDFInteger(PDFAnnotationAppearanceCharacteristics::PushButtonMode::NoIcon))); result.m_pushButtonMode = static_cast<PushButtonMode>(loader.readIntegerFromDictionary(dictionary, "TP", PDFInteger(PDFAnnotationAppearanceCharacteristics::PushButtonMode::NoIcon)));
} }
return result; return result;
} }
PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFDocument* document, PDFObject object) PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationIconFitInfo info; PDFAnnotationIconFitInfo info;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
constexpr const std::array<std::pair<const char*, PDFAnnotationIconFitInfo::ScaleCondition>, 4> scaleConditions = { constexpr const std::array<std::pair<const char*, PDFAnnotationIconFitInfo::ScaleCondition>, 4> scaleConditions = {
std::pair<const char*, PDFAnnotationIconFitInfo::ScaleCondition>{ "A", PDFAnnotationIconFitInfo::ScaleCondition::Always }, std::pair<const char*, PDFAnnotationIconFitInfo::ScaleCondition>{ "A", PDFAnnotationIconFitInfo::ScaleCondition::Always },
@ -717,22 +808,22 @@ PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFDocument* docu
return info; return info;
} }
PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFDocument* document, PDFObject object) PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFAnnotationAdditionalActions result; PDFAnnotationAdditionalActions result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
result.m_actions[CursorEnter] = PDFAction::parse(document, dictionary->get("E")); result.m_actions[CursorEnter] = PDFAction::parse(storage, dictionary->get("E"));
result.m_actions[CursorLeave] = PDFAction::parse(document, dictionary->get("X")); result.m_actions[CursorLeave] = PDFAction::parse(storage, dictionary->get("X"));
result.m_actions[MousePressed] = PDFAction::parse(document, dictionary->get("D")); result.m_actions[MousePressed] = PDFAction::parse(storage, dictionary->get("D"));
result.m_actions[MouseReleased] = PDFAction::parse(document, dictionary->get("U")); result.m_actions[MouseReleased] = PDFAction::parse(storage, dictionary->get("U"));
result.m_actions[FocusIn] = PDFAction::parse(document, dictionary->get("Fo")); result.m_actions[FocusIn] = PDFAction::parse(storage, dictionary->get("Fo"));
result.m_actions[FocusOut] = PDFAction::parse(document, dictionary->get("Bl")); result.m_actions[FocusOut] = PDFAction::parse(storage, dictionary->get("Bl"));
result.m_actions[PageOpened] = PDFAction::parse(document, dictionary->get("PO")); result.m_actions[PageOpened] = PDFAction::parse(storage, dictionary->get("PO"));
result.m_actions[PageClosed] = PDFAction::parse(document, dictionary->get("PC")); result.m_actions[PageClosed] = PDFAction::parse(storage, dictionary->get("PC"));
result.m_actions[PageShow] = PDFAction::parse(document, dictionary->get("PV")); result.m_actions[PageShow] = PDFAction::parse(storage, dictionary->get("PV"));
result.m_actions[PageHide] = PDFAction::parse(document, dictionary->get("PI")); result.m_actions[PageHide] = PDFAction::parse(storage, dictionary->get("PI"));
} }
return result; return result;
@ -931,7 +1022,7 @@ PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(
annotations.annotations.reserve(pageAnnotations.size()); annotations.annotations.reserve(pageAnnotations.size());
for (PDFObjectReference annotationReference : pageAnnotations) for (PDFObjectReference annotationReference : pageAnnotations)
{ {
PDFAnnotationPtr annotationPtr = PDFAnnotation::parse(m_document, m_document->getObjectByReference(annotationReference)); PDFAnnotationPtr annotationPtr = PDFAnnotation::parse(&m_document->getStorage(), m_document->getObjectByReference(annotationReference));
if (annotationPtr) if (annotationPtr)
{ {
PageAnnotation annotation; PageAnnotation annotation;
@ -956,4 +1047,78 @@ void PDFAnnotationManager::setTarget(Target target)
m_target = target; m_target = target;
} }
void PDFSimpleGeometryAnnotation::draw(AnnotationDrawParameters& parameters) const
{
Q_ASSERT(parameters.painter);
parameters.boundingRectangle = getRectangle();
QPainter& painter = *parameters.painter;
painter.setPen(getPen());
painter.setBrush(getBrush());
switch (getType())
{
case AnnotationType::Square:
{
const PDFAnnotationBorder& border = getBorder();
const PDFReal hCornerRadius = border.getHorizontalCornerRadius();
const PDFReal vCornerRadius = border.getVerticalCornerRadius();
const bool isRounded = !qFuzzyIsNull(hCornerRadius) || !qFuzzyIsNull(vCornerRadius);
if (isRounded)
{
painter.drawRoundedRect(getRectangle(), hCornerRadius, vCornerRadius, Qt::AbsoluteSize);
}
else
{
painter.drawRect(getRectangle());
}
break;
}
case AnnotationType::Circle:
{
painter.drawEllipse(getRectangle());
break;
}
default:
{
Q_ASSERT(false);
break;
}
}
}
QColor PDFSimpleGeometryAnnotation::getFillColor() const
{
QColor color = getDrawColorFromAnnotationColor(getInteriorColor());
if (color.isValid())
{
color.setAlphaF(getOpacity());
}
return color;
}
QColor PDFMarkupAnnotation::getStrokeColor() const
{
QColor color = PDFAnnotation::getStrokeColor();
if (color.isValid())
{
color.setAlphaF(m_opacity);
}
return color;
}
QColor PDFMarkupAnnotation::getFillColor() const
{
QColor color = PDFAnnotation::getFillColor();
if (color.isValid())
{
color.setAlphaF(m_opacity);
}
return color;
}
} // namespace pdf } // namespace pdf

View File

@ -31,7 +31,7 @@
namespace pdf namespace pdf
{ {
class PDFDocument; class PDFObjectStorage;
class PDFDrawWidgetProxy; class PDFDrawWidgetProxy;
using TextAlignment = Qt::Alignment; using TextAlignment = Qt::Alignment;
@ -105,15 +105,15 @@ public:
/// Parses the annotation border from the array. If object contains invalid annotation border, /// Parses the annotation border from the array. If object contains invalid annotation border,
/// then default annotation border is returned. If object is empty, empty annotation border is returned. /// then default annotation border is returned. If object is empty, empty annotation border is returned.
/// \param document Document /// \param storage Object storage
/// \param object Border object /// \param object Border object
static PDFAnnotationBorder parseBorder(const PDFDocument* document, PDFObject object); static PDFAnnotationBorder parseBorder(const PDFObjectStorage* storage, PDFObject object);
/// Parses the annotation border from the BS dictionary. If object contains invalid annotation border, /// Parses the annotation border from the BS dictionary. If object contains invalid annotation border,
/// then default annotation border is returned. If object is empty, empty annotation border is returned. /// then default annotation border is returned. If object is empty, empty annotation border is returned.
/// \param document Document /// \param storage Object storage
/// \param object Border object /// \param object Border object
static PDFAnnotationBorder parseBS(const PDFDocument* document, PDFObject object); static PDFAnnotationBorder parseBS(const PDFObjectStorage* storage, PDFObject object);
/// Returns true, if object is correctly defined /// Returns true, if object is correctly defined
bool isValid() const { return m_definition != Definition::Invalid; } bool isValid() const { return m_definition != Definition::Invalid; }
@ -150,9 +150,9 @@ public:
/// Parses the annotation border effect from the object. If object contains invalid annotation border effect, /// Parses the annotation border effect from the object. If object contains invalid annotation border effect,
/// then default annotation border effect is returned. If object is empty, also default annotation border effect is returned. /// then default annotation border effect is returned. If object is empty, also default annotation border effect is returned.
/// \param document Document /// \param storage Object storage
/// \param object Border effect object /// \param object Border effect object
static PDFAnnotationBorderEffect parse(const PDFDocument* document, PDFObject object); static PDFAnnotationBorderEffect parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
Effect m_effect = Effect::None; Effect m_effect = Effect::None;
@ -179,9 +179,9 @@ public:
/// Parses annotation appearance streams from the object. If object is invalid, then /// Parses annotation appearance streams from the object. If object is invalid, then
/// empty appearance stream is constructed. /// empty appearance stream is constructed.
/// \param document Document /// \param storage Object storage
/// \param object Appearance streams object /// \param object Appearance streams object
static PDFAppeareanceStreams parse(const PDFDocument* document, PDFObject object); static PDFAppeareanceStreams parse(const PDFObjectStorage* storage, PDFObject object);
/// Tries to search for appearance stream for given appearance. If no appearance is found, /// Tries to search for appearance stream for given appearance. If no appearance is found,
/// then null object is returned. /// then null object is returned.
@ -248,9 +248,9 @@ public:
/// Parses annotation callout line from the object. If object is invalid, then /// Parses annotation callout line from the object. If object is invalid, then
/// invalid callout line is constructed. /// invalid callout line is constructed.
/// \param document Document /// \param storage Object storage
/// \param object Callout line object /// \param object Callout line object
static PDFAnnotationCalloutLine parse(const PDFDocument* document, PDFObject object); static PDFAnnotationCalloutLine parse(const PDFObjectStorage* storage, PDFObject object);
bool isValid() const { return m_type != Type::Invalid; } bool isValid() const { return m_type != Type::Invalid; }
Type getType() const { return m_type; } Type getType() const { return m_type; }
@ -284,9 +284,9 @@ public:
/// Parses annotation appearance icon fit info from the object. If object is invalid, then /// Parses annotation appearance icon fit info from the object. If object is invalid, then
/// default appearance icon fit info is constructed. /// default appearance icon fit info is constructed.
/// \param document Document /// \param storage Object storage
/// \param object Appearance icon fit info object /// \param object Appearance icon fit info object
static PDFAnnotationIconFitInfo parse(const PDFDocument* document, PDFObject object); static PDFAnnotationIconFitInfo parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
ScaleCondition m_scaleCondition = ScaleCondition::Always; ScaleCondition m_scaleCondition = ScaleCondition::Always;
@ -329,9 +329,9 @@ public:
/// Parses annotation appearance characteristics from the object. If object is invalid, then /// Parses annotation appearance characteristics from the object. If object is invalid, then
/// default appearance characteristics is constructed. /// default appearance characteristics is constructed.
/// \param document Document /// \param storage Object storage
/// \param object Appearance characteristics object /// \param object Appearance characteristics object
static PDFAnnotationAppearanceCharacteristics parse(const PDFDocument* document, PDFObject object); static PDFAnnotationAppearanceCharacteristics parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
PDFInteger m_rotation = 0; PDFInteger m_rotation = 0;
@ -376,9 +376,9 @@ public:
/// Parses annotation additional actions from the object. If object is invalid, then /// Parses annotation additional actions from the object. If object is invalid, then
/// empty additional actions is constructed. /// empty additional actions is constructed.
/// \param document Document /// \param storage Object storage
/// \param object Additional actions object /// \param object Additional actions object
static PDFAnnotationAdditionalActions parse(const PDFDocument* document, PDFObject object); static PDFAnnotationAdditionalActions parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
std::array<PDFActionPtr, End> m_actions; std::array<PDFActionPtr, End> m_actions;
@ -390,6 +390,22 @@ class PDFTextAnnotation;
using PDFAnnotationPtr = QSharedPointer<PDFAnnotation>; using PDFAnnotationPtr = QSharedPointer<PDFAnnotation>;
struct AnnotationDrawParameters
{
/// Painter, onto which is annotation graphics drawn
QPainter* painter = nullptr;
/// Output parameter. Marks annotation's graphics bounding
/// rectangle (it can be different/adjusted from original
/// annotation bounding rectangle, in that case, it must be adjusted).
/// If this rectangle is invalid, then appearance content stream
/// is assumed to be empty.
QRectF boundingRectangle;
/// Appeareance mode (normal/rollover/down, and appearance state)
PDFAppeareanceStreams::Key key;
};
/// Base class for all annotation types. Represents PDF annotation object. /// Base class for all annotation types. Represents PDF annotation object.
/// Annotations are various enhancements to pages graphical representation, /// Annotations are various enhancements to pages graphical representation,
/// such as graphics, text, highlight or multimedia content, such as sounds, /// such as graphics, text, highlight or multimedia content, such as sounds,
@ -421,6 +437,17 @@ public:
virtual PDFMarkupAnnotation* asMarkupAnnotation() { return nullptr; } virtual PDFMarkupAnnotation* asMarkupAnnotation() { return nullptr; }
virtual const PDFMarkupAnnotation* asMarkupAnnotation() const { return nullptr; } virtual const PDFMarkupAnnotation* asMarkupAnnotation() const { return nullptr; }
/// Draws the annotation using parameters. Annotation is drawn onto painter,
/// but actual graphics can be drawn outside of annotation's rectangle.
/// In that case, adjusted annotation's rectangle is passed to the parameters.
/// Painter must use annotation's coordinate system (for example, line points
/// must match in both in painter and this annotation).
/// \param parameters Graphics parameters
virtual void draw(AnnotationDrawParameters& parameters) const;
/// Returns a list of appearance states, which must be created for this annotation
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys() const;
const QRectF& getRectangle() const { return m_rectangle; } const QRectF& getRectangle() const { return m_rectangle; }
const QString& getContents() const { return m_contents; } const QString& getContents() const { return m_contents; }
PDFObjectReference getPageReference() const { return m_pageReference; } PDFObjectReference getPageReference() const { return m_pageReference; }
@ -436,24 +463,39 @@ public:
PDFObjectReference getOptionalContent() const { return m_optionalContentReference; } PDFObjectReference getOptionalContent() const { return m_optionalContentReference; }
/// Parses annotation from the object. If error occurs, then nullptr is returned. /// Parses annotation from the object. If error occurs, then nullptr is returned.
/// \param document Document /// \param storage Object storage
/// \param object Annotation object /// \param object Annotation object
static PDFAnnotationPtr parse(const PDFDocument* document, PDFObject object); static PDFAnnotationPtr parse(const PDFObjectStorage* storage, PDFObject object);
/// Parses quadrilaterals and fills them in the painter path. If no quadrilaterals are defined, /// Parses quadrilaterals and fills them in the painter path. If no quadrilaterals are defined,
/// then annotation rectangle is used. If annotation rectangle is also invalid, /// then annotation rectangle is used. If annotation rectangle is also invalid,
/// then empty painter path is used. /// then empty painter path is used.
/// \param document Document /// \param storage Object storage
/// \param quadrilateralsObject Object with quadrilaterals definition /// \param quadrilateralsObject Object with quadrilaterals definition
/// \param annotationRect Annotation rectangle /// \param annotationRect Annotation rectangle
static PDFAnnotationQuadrilaterals parseQuadrilaterals(const PDFDocument* document, PDFObject quadrilateralsObject, const QRectF annotationRect); static PDFAnnotationQuadrilaterals parseQuadrilaterals(const PDFObjectStorage* storage, PDFObject quadrilateralsObject, const QRectF annotationRect);
/// Converts name to line ending. If appropriate line ending for name is not found, /// Converts name to line ending. If appropriate line ending for name is not found,
/// then None line ending is returned. /// then None line ending is returned.
/// \param name Name of the line ending /// \param name Name of the line ending
static AnnotationLineEnding convertNameToLineEnding(const QByteArray& name); static AnnotationLineEnding convertNameToLineEnding(const QByteArray& name);
protected:
virtual QColor getStrokeColor() const;
virtual QColor getFillColor() const;
/// Returns draw color from defined annotation color
QColor getDrawColorFromAnnotationColor(const std::vector<PDFReal>& color) const;
/// Returns pen from border settings and annotation color
QPen getPen() const;
/// Returns brush from interior color. If annotation doesn't have
/// a brush, then empty brush is returned.
QBrush getBrush() const;
private: private:
QRectF m_rectangle; ///< Annotation rectangle, in page coordinates, "Rect" entry QRectF m_rectangle; ///< Annotation rectangle, in page coordinates, "Rect" entry
QString m_contents; ///< Text to be displayed to the user (or alternate text), "Content" entry QString m_contents; ///< Text to be displayed to the user (or alternate text), "Content" entry
PDFObjectReference m_pageReference; ///< Reference to annotation's page, "P" entry PDFObjectReference m_pageReference; ///< Reference to annotation's page, "P" entry
@ -497,8 +539,12 @@ public:
const QByteArray& getIntent() const { return m_intent; } const QByteArray& getIntent() const { return m_intent; }
const PDFObject& getExternalData() const { return m_externalData; } const PDFObject& getExternalData() const { return m_externalData; }
protected:
virtual QColor getStrokeColor() const override;
virtual QColor getFillColor() const override;
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_windowTitle; QString m_windowTitle;
PDFObjectReference m_popupAnnotation; PDFObjectReference m_popupAnnotation;
@ -541,7 +587,7 @@ public:
const QString& getStateModel() const { return m_stateModel; } const QString& getStateModel() const { return m_stateModel; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
bool m_open = false; bool m_open = false;
QByteArray m_iconName; QByteArray m_iconName;
@ -572,7 +618,7 @@ public:
const PDFAnnotationQuadrilaterals& getActivationRegion() const { return m_activationRegion; } const PDFAnnotationQuadrilaterals& getActivationRegion() const { return m_activationRegion; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFActionPtr m_action; PDFActionPtr m_action;
LinkHighlightMode m_highlightMode = LinkHighlightMode::Invert; LinkHighlightMode m_highlightMode = LinkHighlightMode::Invert;
@ -614,7 +660,7 @@ public:
AnnotationLineEnding getEndLineEnding() const { return m_endLineEnding; } AnnotationLineEnding getEndLineEnding() const { return m_endLineEnding; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QByteArray m_defaultAppearance; QByteArray m_defaultAppearance;
Justification m_justification = Justification::Left; Justification m_justification = Justification::Left;
@ -663,7 +709,7 @@ public:
const QPointF& getCaptionOffset() const { return m_captionOffset; } const QPointF& getCaptionOffset() const { return m_captionOffset; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QLineF m_line; QLineF m_line;
AnnotationLineEnding m_startLineEnding = AnnotationLineEnding::None; AnnotationLineEnding m_startLineEnding = AnnotationLineEnding::None;
@ -693,13 +739,17 @@ public:
} }
virtual AnnotationType getType() const override { return m_type; } virtual AnnotationType getType() const override { return m_type; }
virtual void draw(AnnotationDrawParameters& parameters) const override;
const std::vector<PDFReal>& getInteriorColor() const { return m_interiorColor; } const std::vector<PDFReal>& getInteriorColor() const { return m_interiorColor; }
const PDFAnnotationBorderEffect& getBorderEffect() const { return m_effect; } const PDFAnnotationBorderEffect& getBorderEffect() const { return m_effect; }
const QRectF& getGeometryRectangle() const { return m_geometryRectangle; } const QRectF& getGeometryRectangle() const { return m_geometryRectangle; }
protected:
virtual QColor getFillColor() const override;
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type; AnnotationType m_type;
std::vector<PDFReal> m_interiorColor; std::vector<PDFReal> m_interiorColor;
@ -738,7 +788,7 @@ public:
const PDFObject& getMeasure() const { return m_measure; } const PDFObject& getMeasure() const { return m_measure; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type; AnnotationType m_type;
std::vector<QPointF> m_vertices; std::vector<QPointF> m_vertices;
@ -766,7 +816,7 @@ public:
const PDFAnnotationQuadrilaterals& getHiglightArea() const { return m_highlightArea; } const PDFAnnotationQuadrilaterals& getHiglightArea() const { return m_highlightArea; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type; AnnotationType m_type;
PDFAnnotationQuadrilaterals m_highlightArea; PDFAnnotationQuadrilaterals m_highlightArea;
@ -790,7 +840,7 @@ public:
Symbol getSymbol() const { return m_symbol; } Symbol getSymbol() const { return m_symbol; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QRectF m_caretRectangle; QRectF m_caretRectangle;
Symbol m_symbol = Symbol::None; Symbol m_symbol = Symbol::None;
@ -826,7 +876,7 @@ public:
Stamp getStamp() const { return m_stamp; } Stamp getStamp() const { return m_stamp; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
Stamp m_stamp = Stamp::Draft; Stamp m_stamp = Stamp::Draft;
}; };
@ -842,7 +892,7 @@ public:
const QPainterPath& getInkPath() const { return m_inkPath; } const QPainterPath& getInkPath() const { return m_inkPath; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QPainterPath m_inkPath; QPainterPath m_inkPath;
}; };
@ -860,7 +910,7 @@ public:
bool isOpened() const { return m_opened; } bool isOpened() const { return m_opened; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
bool m_opened = false; bool m_opened = false;
}; };
@ -887,7 +937,7 @@ public:
Icon getIcon() const { return m_icon; } Icon getIcon() const { return m_icon; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFFileSpecification m_fileSpecification; PDFFileSpecification m_fileSpecification;
Icon m_icon = Icon::PushPin; Icon m_icon = Icon::PushPin;
@ -912,7 +962,7 @@ public:
Icon getIcon() const { return m_icon; } Icon getIcon() const { return m_icon; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFSound m_sound; PDFSound m_sound;
Icon m_icon = Icon::Speaker; Icon m_icon = Icon::Speaker;
@ -933,7 +983,7 @@ public:
const PDFMovieActivation& getMovieActivation() const { return m_movieActivation; } const PDFMovieActivation& getMovieActivation() const { return m_movieActivation; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_movieTitle; QString m_movieTitle;
bool m_playMovie = true; bool m_playMovie = true;
@ -956,7 +1006,7 @@ public:
const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; } const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_screenTitle; QString m_screenTitle;
PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics; PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics;
@ -989,7 +1039,7 @@ public:
const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; } const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
HighlightMode m_highlightMode = HighlightMode::Invert; HighlightMode m_highlightMode = HighlightMode::Invert;
PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics; PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics;
@ -1031,7 +1081,7 @@ public:
PDFReal getRelativeVerticalOffset() const { return m_relativeVerticalOffset; } PDFReal getRelativeVerticalOffset() const { return m_relativeVerticalOffset; }
private: private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object); friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QMatrix m_matrix; QMatrix m_matrix;
PDFReal m_relativeHorizontalOffset = 0.0; PDFReal m_relativeHorizontalOffset = 0.0;

View File

@ -95,11 +95,11 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
PDFObject openAction = document->getObject(catalogDictionary->get("OpenAction")); PDFObject openAction = document->getObject(catalogDictionary->get("OpenAction"));
if (openAction.isArray()) if (openAction.isArray())
{ {
catalogObject.m_openAction.reset(new PDFActionGoTo(PDFDestination::parse(document, openAction))); catalogObject.m_openAction.reset(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), openAction)));
} }
if (openAction.isDictionary()) if (openAction.isDictionary())
{ {
catalogObject.m_openAction = PDFAction::parse(document, openAction); catalogObject.m_openAction = PDFAction::parse(&document->getStorage(), openAction);
} }
} }
@ -136,20 +136,20 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
if (const PDFDictionary* namesDictionary = document->getDictionaryFromObject(catalogDictionary->get("Names"))) if (const PDFDictionary* namesDictionary = document->getDictionaryFromObject(catalogDictionary->get("Names")))
{ {
auto parseDestination = [](const PDFDocument* document, PDFObject object) auto parseDestination = [](const PDFObjectStorage* storage, PDFObject object)
{ {
object = document->getObject(object); object = storage->getObject(object);
if (object.isDictionary()) if (object.isDictionary())
{ {
object = object.getDictionary()->get("D"); object = object.getDictionary()->get("D");
} }
return PDFDestination::parse(document, qMove(object)); return PDFDestination::parse(storage, qMove(object));
}; };
catalogObject.m_destinations = PDFNameTreeLoader<PDFDestination>::parse(document, namesDictionary->get("Dests"), parseDestination); catalogObject.m_destinations = PDFNameTreeLoader<PDFDestination>::parse(&document->getStorage(), namesDictionary->get("Dests"), parseDestination);
catalogObject.m_javaScriptActions = PDFNameTreeLoader<PDFActionPtr>::parse(document, namesDictionary->get("JavaScript"), &PDFAction::parse); catalogObject.m_javaScriptActions = PDFNameTreeLoader<PDFActionPtr>::parse(&document->getStorage(), namesDictionary->get("JavaScript"), &PDFAction::parse);
catalogObject.m_embeddedFiles = PDFNameTreeLoader<PDFFileSpecification>::parse(document, namesDictionary->get("EmbeddedFiles"), &PDFFileSpecification::parse); catalogObject.m_embeddedFiles = PDFNameTreeLoader<PDFFileSpecification>::parse(&document->getStorage(), namesDictionary->get("EmbeddedFiles"), &PDFFileSpecification::parse);
} }
// Examine "Dests" dictionary // Examine "Dests" dictionary
@ -158,7 +158,7 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
const size_t count = destsDictionary->getCount(); const size_t count = destsDictionary->getCount();
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
{ {
catalogObject.m_destinations[destsDictionary->getKey(i)] = PDFDestination::parse(document, destsDictionary->getValue(i)); catalogObject.m_destinations[destsDictionary->getKey(i)] = PDFDestination::parse(&document->getStorage(), destsDictionary->getValue(i));
} }
} }

View File

@ -40,9 +40,14 @@ static constexpr const char* PDF_DOCUMENT_INFO_ENTRY_TRAPPED_TRUE = "True";
static constexpr const char* PDF_DOCUMENT_INFO_ENTRY_TRAPPED_FALSE = "False"; static constexpr const char* PDF_DOCUMENT_INFO_ENTRY_TRAPPED_FALSE = "False";
static constexpr const char* PDF_DOCUMENT_INFO_ENTRY_TRAPPED_UNKNOWN = "Unknown"; static constexpr const char* PDF_DOCUMENT_INFO_ENTRY_TRAPPED_UNKNOWN = "Unknown";
QByteArray PDFObjectStorage::getDecodedStream(const PDFStream* stream) const
{
return PDFStreamFilterStorage::getDecodedStream(stream, std::bind(QOverload<const PDFObject&>::of(&PDFObjectStorage::getObject), this, std::placeholders::_1), getSecurityHandler());
}
QByteArray PDFDocument::getDecodedStream(const PDFStream* stream) const QByteArray PDFDocument::getDecodedStream(const PDFStream* stream) const
{ {
return PDFStreamFilterStorage::getDecodedStream(stream, std::bind(&PDFDocument::getObject, this, std::placeholders::_1), m_pdfObjectStorage.getSecurityHandler()); return m_pdfObjectStorage.getDecodedStream(stream);
} }
const PDFDictionary* PDFDocument::getTrailerDictionary() const const PDFDictionary* PDFDocument::getTrailerDictionary() const
@ -242,9 +247,15 @@ void PDFObjectStorage::updateTrailerDictionary(PDFObject trailerDictionary)
m_trailerDictionary = PDFObjectManipulator::merge(m_trailerDictionary, trailerDictionary, PDFObjectManipulator::RemoveNullObjects); m_trailerDictionary = PDFObjectManipulator::merge(m_trailerDictionary, trailerDictionary, PDFObjectManipulator::RemoveNullObjects);
} }
PDFDocumentDataLoaderDecorator::PDFDocumentDataLoaderDecorator(const PDFDocument* document)
: m_storage(&document->getStorage())
{
}
QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object) QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object)
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isName()) if (dereferencedObject.isName())
{ {
return dereferencedObject.getString(); return dereferencedObject.getString();
@ -255,7 +266,7 @@ QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object)
QByteArray PDFDocumentDataLoaderDecorator::readString(const PDFObject& object) QByteArray PDFDocumentDataLoaderDecorator::readString(const PDFObject& object)
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isString()) if (dereferencedObject.isString())
{ {
return dereferencedObject.getString(); return dereferencedObject.getString();
@ -266,7 +277,7 @@ QByteArray PDFDocumentDataLoaderDecorator::readString(const PDFObject& object)
PDFInteger PDFDocumentDataLoaderDecorator::readInteger(const PDFObject& object, PDFInteger defaultValue) const PDFInteger PDFDocumentDataLoaderDecorator::readInteger(const PDFObject& object, PDFInteger defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isInt()) if (dereferencedObject.isInt())
{ {
return dereferencedObject.getInteger(); return dereferencedObject.getInteger();
@ -277,7 +288,7 @@ PDFInteger PDFDocumentDataLoaderDecorator::readInteger(const PDFObject& object,
PDFReal PDFDocumentDataLoaderDecorator::readNumber(const PDFObject& object, PDFReal defaultValue) const PDFReal PDFDocumentDataLoaderDecorator::readNumber(const PDFObject& object, PDFReal defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isReal()) if (dereferencedObject.isReal())
{ {
@ -292,7 +303,7 @@ PDFReal PDFDocumentDataLoaderDecorator::readNumber(const PDFObject& object, PDFR
bool PDFDocumentDataLoaderDecorator::readBoolean(const PDFObject& object, bool defaultValue) const bool PDFDocumentDataLoaderDecorator::readBoolean(const PDFObject& object, bool defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isBool()) if (dereferencedObject.isBool())
{ {
@ -304,7 +315,7 @@ bool PDFDocumentDataLoaderDecorator::readBoolean(const PDFObject& object, bool d
QString PDFDocumentDataLoaderDecorator::readTextString(const PDFObject& object, const QString& defaultValue) const QString PDFDocumentDataLoaderDecorator::readTextString(const PDFObject& object, const QString& defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isString()) if (dereferencedObject.isString())
{ {
return PDFEncoding::convertTextString(dereferencedObject.getString()); return PDFEncoding::convertTextString(dereferencedObject.getString());
@ -315,7 +326,7 @@ QString PDFDocumentDataLoaderDecorator::readTextString(const PDFObject& object,
QRectF PDFDocumentDataLoaderDecorator::readRectangle(const PDFObject& object, const QRectF& defaultValue) const QRectF PDFDocumentDataLoaderDecorator::readRectangle(const PDFObject& object, const QRectF& defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -324,7 +335,7 @@ QRectF PDFDocumentDataLoaderDecorator::readRectangle(const PDFObject& object, co
std::array<PDFReal, 4> items; std::array<PDFReal, 4> items;
for (size_t i = 0; i < 4; ++i) for (size_t i = 0; i < 4; ++i)
{ {
const PDFObject& object = m_document->getObject(array->getItem(i)); const PDFObject& object = m_storage->getObject(array->getItem(i));
if (object.isReal()) if (object.isReal())
{ {
items[i] = object.getReal(); items[i] = object.getReal();
@ -441,7 +452,7 @@ std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArr
std::vector<PDFReal> PDFDocumentDataLoaderDecorator::readNumberArray(const PDFObject& object, std::vector<PDFReal> defaultValue) const std::vector<PDFReal> PDFDocumentDataLoaderDecorator::readNumberArray(const PDFObject& object, std::vector<PDFReal> defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -469,7 +480,7 @@ std::vector<PDFReal> PDFDocumentDataLoaderDecorator::readNumberArray(const PDFOb
std::vector<PDFInteger> PDFDocumentDataLoaderDecorator::readIntegerArray(const PDFObject& object) const std::vector<PDFInteger> PDFDocumentDataLoaderDecorator::readIntegerArray(const PDFObject& object) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -512,7 +523,7 @@ PDFObjectReference PDFDocumentDataLoaderDecorator::readReferenceFromDictionary(c
std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArray(const PDFObject& object) const std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArray(const PDFObject& object) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -544,7 +555,7 @@ std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArr
std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readNameArray(const PDFObject& object) const std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readNameArray(const PDFObject& object) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -626,7 +637,7 @@ std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readStringArrayFromDicti
std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readStringArray(const PDFObject& object) const std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readStringArray(const PDFObject& object) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();

View File

@ -69,6 +69,20 @@ public:
/// then null object is returned (no exception is thrown). /// then null object is returned (no exception is thrown).
const PDFObject& getObject(PDFObjectReference reference) const; const PDFObject& getObject(PDFObjectReference reference) const;
/// If object is reference, the dereference attempt is performed
/// and object is returned. If it is not a reference, then self
/// is returned. If dereference attempt fails, then null object
/// is returned (no exception is thrown).
const PDFObject& getObject(const PDFObject& object) const;
/// Returns dictionary from an object. If object is not a dictionary,
/// then nullptr is returned (no exception is thrown).
const PDFDictionary* getDictionaryFromObject(const PDFObject& object) const;
/// Returns object by reference. If dereference attempt fails, then null object
/// is returned (no exception is thrown).
const PDFObject& getObjectByReference(PDFObjectReference reference) const;
/// Returns array of objects stored in this storage /// Returns array of objects stored in this storage
const PDFObjects& getObjects() const { return m_objects; } const PDFObjects& getObjects() const { return m_objects; }
@ -98,6 +112,11 @@ public:
/// \param trailerDictionary New trailer dictionary /// \param trailerDictionary New trailer dictionary
void updateTrailerDictionary(PDFObject trailerDictionary); void updateTrailerDictionary(PDFObject trailerDictionary);
/// Returns the decoded stream. If stream data cannot be decoded,
/// then empty byte array is returned.
/// \param stream Stream to be decoded
QByteArray getDecodedStream(const PDFStream* stream) const;
private: private:
PDFObjects m_objects; PDFObjects m_objects;
PDFObject m_trailerDictionary; PDFObject m_trailerDictionary;
@ -112,7 +131,8 @@ private:
class PDFDocumentDataLoaderDecorator class PDFDocumentDataLoaderDecorator
{ {
public: public:
inline explicit PDFDocumentDataLoaderDecorator(const PDFDocument* document) : m_document(document) { } explicit PDFDocumentDataLoaderDecorator(const PDFDocument* document);
inline explicit PDFDocumentDataLoaderDecorator(const PDFObjectStorage* storage) : m_storage(storage) { }
inline ~PDFDocumentDataLoaderDecorator() = default; inline ~PDFDocumentDataLoaderDecorator() = default;
/// Reads a name from the object, if it is possible. If object is not a name, /// Reads a name from the object, if it is possible. If object is not a name,
@ -159,7 +179,7 @@ public:
template<typename Enum, typename Iterator> template<typename Enum, typename Iterator>
Enum readEnumByName(const PDFObject& object, Iterator begin, Iterator end, Enum defaultValue) const Enum readEnumByName(const PDFObject& object, Iterator begin, Iterator end, Enum defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isName() || dereferencedObject.isString()) if (dereferencedObject.isName() || dereferencedObject.isString())
{ {
QByteArray name = dereferencedObject.getString(); QByteArray name = dereferencedObject.getString();
@ -184,7 +204,7 @@ public:
template<typename T> template<typename T>
void readNumberArray(const PDFObject& object, T first, T last) void readNumberArray(const PDFObject& object, T first, T last)
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray()) if (dereferencedObject.isArray())
{ {
const PDFArray* array = dereferencedObject.getArray(); const PDFArray* array = dereferencedObject.getArray();
@ -318,7 +338,7 @@ public:
std::vector<QByteArray> readStringArrayFromDictionary(const PDFDictionary* dictionary, const char* key) const; std::vector<QByteArray> readStringArrayFromDictionary(const PDFDictionary* dictionary, const char* key) const;
private: private:
const PDFDocument* m_document; const PDFObjectStorage* m_storage;
}; };
/// PDF document main class. /// PDF document main class.
@ -458,6 +478,40 @@ const PDFObject& PDFDocument::getObjectByReference(PDFObjectReference reference)
return m_pdfObjectStorage.getObject(reference); return m_pdfObjectStorage.getObject(reference);
} }
inline
const PDFObject& PDFObjectStorage::getObject(const PDFObject& object) const
{
if (object.isReference())
{
// Try to dereference the object
return getObject(object.getReference());
}
return object;
}
inline
const PDFDictionary* PDFObjectStorage::getDictionaryFromObject(const PDFObject& object) const
{
const PDFObject& dereferencedObject = getObject(object);
if (dereferencedObject.isDictionary())
{
return dereferencedObject.getDictionary();
}
else if (dereferencedObject.isStream())
{
return dereferencedObject.getStream()->getDictionary();
}
return nullptr;
}
inline
const PDFObject& PDFObjectStorage::getObjectByReference(PDFObjectReference reference) const
{
return getObject(reference);
}
} // namespace pdf } // namespace pdf
#endif // PDFDOCUMENT_H #endif // PDFDOCUMENT_H

View File

@ -18,10 +18,165 @@
#include "pdfdocumentbuilder.h" #include "pdfdocumentbuilder.h"
#include "pdfencoding.h" #include "pdfencoding.h"
#include "pdfconstants.h" #include "pdfconstants.h"
#include "pdfdocumentreader.h"
#include "pdfvisitor.h"
#include <QBuffer>
#include <QPainter>
#include <QPdfWriter>
namespace pdf namespace pdf
{ {
class PDFCollectReferencesVisitor : public PDFAbstractVisitor
{
public:
explicit PDFCollectReferencesVisitor(std::set<PDFObjectReference>& references) :
m_references(references)
{
}
virtual void visitArray(const PDFArray* array) override;
virtual void visitDictionary(const PDFDictionary* dictionary) override;
virtual void visitStream(const PDFStream* stream) override;
virtual void visitReference(const PDFObjectReference reference) override;
private:
std::set<PDFObjectReference>& m_references;
};
void PDFCollectReferencesVisitor::visitArray(const PDFArray* array)
{
acceptArray(array);
}
void PDFCollectReferencesVisitor::visitDictionary(const PDFDictionary* dictionary)
{
for (size_t i = 0, count = dictionary->getCount(); i < count; ++i)
{
dictionary->getValue(i).accept(this);
}
}
void PDFCollectReferencesVisitor::visitStream(const PDFStream* stream)
{
visitDictionary(stream->getDictionary());
}
void PDFCollectReferencesVisitor::visitReference(const PDFObjectReference reference)
{
m_references.insert(reference);
}
class PDFReplaceReferencesVisitor : public PDFAbstractVisitor
{
public:
explicit PDFReplaceReferencesVisitor(const std::map<PDFObjectReference, PDFObjectReference>& replacements) :
m_replacements(replacements)
{
m_objectStack.reserve(32);
}
virtual void visitNull() override;
virtual void visitBool(bool value) override;
virtual void visitInt(PDFInteger value) override;
virtual void visitReal(PDFReal value) override;
virtual void visitString(const PDFString* string) override;
virtual void visitName(const PDFString* name) override;
virtual void visitArray(const PDFArray* array) override;
virtual void visitDictionary(const PDFDictionary* dictionary) override;
virtual void visitStream(const PDFStream* stream) override;
virtual void visitReference(const PDFObjectReference reference) override;
PDFObject getObject();
private:
const std::map<PDFObjectReference, PDFObjectReference>& m_replacements;
std::vector<PDFObject> m_objectStack;
};
void PDFReplaceReferencesVisitor::visitNull()
{
m_objectStack.push_back(PDFObject::createNull());
}
void PDFReplaceReferencesVisitor::visitBool(bool value)
{
m_objectStack.push_back(PDFObject::createBool(value));
}
void PDFReplaceReferencesVisitor::visitInt(PDFInteger value)
{
m_objectStack.push_back(PDFObject::createInteger(value));
}
void PDFReplaceReferencesVisitor::visitReal(PDFReal value)
{
m_objectStack.push_back(PDFObject::createReal(value));
}
void PDFReplaceReferencesVisitor::visitString(const PDFString* string)
{
m_objectStack.push_back(PDFObject::createString(std::make_shared<PDFString>(*string)));
}
void PDFReplaceReferencesVisitor::visitName(const PDFString* name)
{
m_objectStack.push_back(PDFObject::createName(std::make_shared<PDFString>(*name)));
}
void PDFReplaceReferencesVisitor::visitArray(const PDFArray* array)
{
acceptArray(array);
// We have all objects on the stack
Q_ASSERT(array->getCount() <= m_objectStack.size());
auto it = std::next(m_objectStack.cbegin(), m_objectStack.size() - array->getCount());
std::vector<PDFObject> objects(it, m_objectStack.cend());
PDFObject object = PDFObject::createArray(std::make_shared<PDFArray>(qMove(objects)));
m_objectStack.erase(it, m_objectStack.cend());
m_objectStack.push_back(object);
}
void PDFReplaceReferencesVisitor::visitDictionary(const PDFDictionary* dictionary)
{
Q_ASSERT(dictionary);
std::vector<PDFDictionary::DictionaryEntry> entries;
entries.reserve(dictionary->getCount());
for (size_t i = 0, count = dictionary->getCount(); i < count; ++i)
{
dictionary->getValue(i).accept(this);
entries.emplace_back(dictionary->getKey(i), m_objectStack.back());
m_objectStack.pop_back();
}
m_objectStack.push_back(PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(entries))));
}
void PDFReplaceReferencesVisitor::visitStream(const PDFStream* stream)
{
// Replace references in the dictionary
visitDictionary(stream->getDictionary());
PDFObject dictionaryObject = m_objectStack.back();
m_objectStack.pop_back();
m_objectStack.push_back(PDFObject::createStream(std::make_shared<PDFStream>(PDFDictionary(*dictionaryObject.getDictionary()), QByteArray(*stream->getContent()))));
}
void PDFReplaceReferencesVisitor::visitReference(const PDFObjectReference reference)
{
m_objectStack.push_back(PDFObject::createReference(m_replacements.at(reference)));
}
PDFObject PDFReplaceReferencesVisitor::getObject()
{
Q_ASSERT(m_objectStack.size() == 1);
return qMove(m_objectStack.back());
}
void PDFObjectFactory::beginArray() void PDFObjectFactory::beginArray()
{ {
m_items.emplace_back(ItemType::Array, PDFArray()); m_items.emplace_back(ItemType::Array, PDFArray());
@ -64,6 +219,12 @@ void PDFObjectFactory::endDictionaryItem()
std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object))); std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object)));
} }
PDFObjectFactory& PDFObjectFactory::operator<<(const PDFObject& object)
{
addObject(object);
return *this;
}
PDFObjectFactory& PDFObjectFactory::operator<<(AnnotationBorderStyle style) PDFObjectFactory& PDFObjectFactory::operator<<(AnnotationBorderStyle style)
{ {
switch (style) switch (style)
@ -477,6 +638,157 @@ std::array<PDFReal, 4> PDFDocumentBuilder::getAnnotationReductionRectangle(const
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) }; return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
} }
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
{
PDFAnnotationPtr annotation = PDFAnnotation::parse(&m_storage, m_storage.getObject(annotationReference));
if (!annotation)
{
return;
}
const PDFDictionary* pageDictionary = m_storage.getDictionaryFromObject(m_storage.getObject(annotation->getPageReference()));
if (!pageDictionary)
{
return;
}
PDFDocumentDataLoaderDecorator loader(&m_storage);
QRectF mediaBox = loader.readRectangle(pageDictionary->get("MediaBox"), QRectF());
if (!mediaBox.isValid())
{
return;
}
std::vector<PDFAppeareanceStreams::Key> keys = annotation->getDrawKeys();
std::map<PDFAppeareanceStreams::Key, PDFObjectReference> appearanceStreams;
QRectF boundingRectangle;
for (const PDFAppeareanceStreams::Key& key : keys)
{
PDFContentStreamBuilder builder(mediaBox.size(), PDFContentStreamBuilder::CoordinateSystem::PDF);
AnnotationDrawParameters parameters;
parameters.key = key;
parameters.painter = builder.begin();
annotation->draw(parameters);
PDFContentStreamBuilder::ContentStream contentStream = builder.end(parameters.painter);
if (!parameters.boundingRectangle.isValid() || !contentStream.pageObject.isValid())
{
// Invalid stream, do nothing
continue;
}
boundingRectangle = boundingRectangle.united(parameters.boundingRectangle);
std::vector<PDFObject> copiedObjects = copyFrom({ contentStream.resources, contentStream.contents }, contentStream.document.getStorage(), true);
Q_ASSERT(copiedObjects.size() == 2);
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
PDFObjectReference formReference = copiedObjects[1].getReference();
// Create form object
PDFObjectFactory formFactory;
formFactory.beginDictionary();
formFactory.beginDictionaryItem("Type");
formFactory << WrapName("XObject");
formFactory.endDictionaryItem();
formFactory.beginDictionaryItem("Subtype");
formFactory << WrapName("Form");
formFactory.endDictionaryItem();
formFactory.beginDictionaryItem("BBox");
formFactory << parameters.boundingRectangle;
formFactory.endDictionaryItem();
formFactory.beginDictionaryItem("Resources");
formFactory << resourcesReference;
formFactory.endDictionaryItem();
formFactory.endDictionary();
mergeTo(formReference, formFactory.takeObject());
appearanceStreams[key] = formReference;
}
if (!appearanceStreams.empty())
{
PDFObjectFactory asDictionaryFactory;
asDictionaryFactory.beginDictionary();
auto it = appearanceStreams.cbegin();
while (it != appearanceStreams.cend())
{
const PDFAppeareanceStreams::Key& key = it->first;
auto itEnd = std::next(it);
while (itEnd != appearanceStreams.cend() && itEnd->first.first == key.first)
{
++itEnd;
}
QByteArray name;
switch (key.first)
{
case PDFAppeareanceStreams::Appearance::Normal:
name = "N";
break;
case PDFAppeareanceStreams::Appearance::Rollover:
name = "R";
break;
case PDFAppeareanceStreams::Appearance::Down:
name = "D";
break;
default:
Q_ASSERT(false);
break;
}
asDictionaryFactory.beginDictionaryItem(name);
const size_t streamCount = std::distance(it, itEnd);
if (streamCount == 1)
{
asDictionaryFactory << it->second;
}
else
{
asDictionaryFactory.beginDictionary();
for (; it != itEnd; ++it)
{
asDictionaryFactory.beginDictionaryItem(it->first.second);
asDictionaryFactory << it->second;
asDictionaryFactory.endDictionaryItem();
}
asDictionaryFactory.endDictionary();
}
asDictionaryFactory.endDictionaryItem();
it = itEnd;
}
asDictionaryFactory.endDictionary();
PDFObjectFactory annotationFactory;
annotationFactory.beginDictionary();
annotationFactory.beginDictionaryItem("Rect");
annotationFactory << boundingRectangle;
annotationFactory.endDictionaryItem();
annotationFactory.beginDictionaryItem("AP");
annotationFactory << asDictionaryFactory.takeObject();
annotationFactory.endDictionaryItem();
annotationFactory.endDictionary();
mergeTo(annotationReference, annotationFactory.takeObject());
}
}
PDFObjectReference PDFDocumentBuilder::addObject(PDFObject object) PDFObjectReference PDFDocumentBuilder::addObject(PDFObject object)
{ {
return m_storage.addObject(PDFObjectManipulator::removeNullObjects(object)); return m_storage.addObject(PDFObjectManipulator::removeNullObjects(object));
@ -585,6 +897,134 @@ void PDFDocumentBuilder::updateDocumentInfo(PDFObject info)
mergeTo(infoReference, info); mergeTo(infoReference, info);
} }
std::vector<PDFObject> PDFDocumentBuilder::copyFrom(const std::vector<PDFObject>& objects, const PDFObjectStorage& storage, bool createReferences)
{
// 1) Collect all references, which we must copy
std::set<PDFObjectReference> references;
PDFCollectReferencesVisitor collectReferencesVisitor(references);
for (const PDFObject& object : objects)
{
object.accept(&collectReferencesVisitor);
}
// 2) Make room for new objects, together with mapping
std::map<PDFObjectReference, PDFObjectReference> referenceMapping;
for (const PDFObjectReference& reference : references)
{
referenceMapping[reference] = addObject(PDFObject::createNull());
}
// 3) Copy objects from other object to this one
for (const PDFObjectReference& sourceReference : references)
{
const PDFObjectReference targetReference = referenceMapping.at(sourceReference);
PDFReplaceReferencesVisitor replaceReferencesVisitor(referenceMapping);
storage.getObject(sourceReference).accept(&replaceReferencesVisitor);
m_storage.setObject(targetReference, replaceReferencesVisitor.getObject());
}
std::vector<PDFObject> result;
result.reserve(objects.size());
for (const PDFObject& object : objects)
{
if (object.isReference())
{
result.push_back(PDFObject::createReference(referenceMapping.at(object.getReference())));
}
else
{
PDFReplaceReferencesVisitor replaceReferencesVisitor(referenceMapping);
object.accept(&replaceReferencesVisitor);
if (createReferences)
{
result.push_back(PDFObject::createReference(addObject(replaceReferencesVisitor.getObject())));
}
else
{
result.push_back(replaceReferencesVisitor.getObject());
}
}
}
return result;
}
PDFContentStreamBuilder::PDFContentStreamBuilder(QSizeF size, CoordinateSystem coordinateSystem) :
m_size(size),
m_coordinateSystem(coordinateSystem),
m_buffer(nullptr),
m_pdfWriter(nullptr),
m_painter(nullptr)
{
}
PDFContentStreamBuilder::~PDFContentStreamBuilder()
{
Q_ASSERT(!m_buffer);
Q_ASSERT(!m_pdfWriter);
Q_ASSERT(!m_painter);
}
QPainter* PDFContentStreamBuilder::begin()
{
Q_ASSERT(!m_buffer);
Q_ASSERT(!m_pdfWriter);
Q_ASSERT(!m_painter);
m_buffer = new QBuffer();
m_buffer->open(QBuffer::ReadWrite);
m_pdfWriter = new QPdfWriter(m_buffer);
m_pdfWriter->setPdfVersion(QPdfWriter::PdfVersion_1_6);
m_pdfWriter->setPageSize(QPageSize(m_size, QPageSize::Point));
m_pdfWriter->setResolution(m_pdfWriter->logicalDpiX());
m_pdfWriter->setPageMargins(QMarginsF());
m_painter = new QPainter(m_pdfWriter);
if (m_coordinateSystem == CoordinateSystem::PDF)
{
m_painter->translate(0, m_size.height());
m_painter->scale(0.0, -1.0);
}
return m_painter;
}
PDFContentStreamBuilder::ContentStream PDFContentStreamBuilder::end(QPainter* painter)
{
ContentStream result;
Q_ASSERT(m_painter == painter);
m_painter->end();
delete m_painter;
m_painter = nullptr;
delete m_pdfWriter;
m_pdfWriter = nullptr;
QByteArray bufferData = m_buffer->buffer();
m_buffer->close();
delete m_buffer;
m_buffer = nullptr;
PDFDocumentReader reader(nullptr, nullptr);
result.document = reader.readFromBuffer(bufferData);
if (result.document.getCatalog()->getPageCount() > 0)
{
const PDFPage* page = result.document.getCatalog()->getPage(0);
result.pageObject = page->getPageReference();
result.resources = page->getResources();
result.contents = page->getContents();
}
return result;
}
/* START GENERATED CODE */ /* START GENERATED CODE */
PDFObjectReference PDFDocumentBuilder::appendPage(QRectF mediaBox) PDFObjectReference PDFDocumentBuilder::appendPage(QRectF mediaBox)
@ -701,6 +1141,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationCircle(PDFObjectReference
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -762,6 +1203,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReferen
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -845,6 +1287,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReferen
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -908,6 +1351,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -956,6 +1400,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1042,6 +1487,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLine(PDFObjectReference p
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1148,6 +1594,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLine(PDFObjectReference p
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1189,6 +1636,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLink(PDFObjectReference p
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationReference);
return annotationReference; return annotationReference;
} }
@ -1271,6 +1719,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPolygon(PDFObjectReferenc
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1350,6 +1799,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPolyline(PDFObjectReferen
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1389,6 +1839,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPopup(PDFObjectReference
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject upgradedParentAnnotation = objectBuilder.takeObject(); PDFObject upgradedParentAnnotation = objectBuilder.takeObject();
mergeTo(parentAnnotation, upgradedParentAnnotation); mergeTo(parentAnnotation, upgradedParentAnnotation);
updateAnnotationAppearanceStreams(popupAnnotation);
return popupAnnotation; return popupAnnotation;
} }
@ -1457,6 +1908,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquare(PDFObjectReference
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1520,6 +1972,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1568,6 +2021,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1631,6 +2085,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationStrikeout(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1679,6 +2134,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationStrikeout(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1751,6 +2207,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationText(PDFObjectReference p
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
mergeTo(annotationObject, updateAnnotationPopup); mergeTo(annotationObject, updateAnnotationPopup);
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1814,6 +2271,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }
@ -1862,6 +2320,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
objectBuilder.endDictionary(); objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject(); PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject; return annotationObject;
} }

View File

@ -22,6 +22,8 @@
#include "pdfdocument.h" #include "pdfdocument.h"
#include "pdfannotation.h" #include "pdfannotation.h"
class QPdfWriter;
namespace pdf namespace pdf
{ {
@ -108,6 +110,7 @@ public:
PDFObjectFactory& operator<<(const QPointF& point); PDFObjectFactory& operator<<(const QPointF& point);
PDFObjectFactory& operator<<(const QDateTime& dateTime); PDFObjectFactory& operator<<(const QDateTime& dateTime);
PDFObjectFactory& operator<<(AnnotationBorderStyle style); PDFObjectFactory& operator<<(AnnotationBorderStyle style);
PDFObjectFactory& operator<<(const PDFObject& object);
/// Treat containers - write them as array /// Treat containers - write them as array
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))> template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
@ -174,6 +177,63 @@ private:
std::vector<Item> m_items; std::vector<Item> m_items;
}; };
/// This class can create content streams, using the Qt's QPainter
/// to draw graphics elements on it. Content stream can have various
/// resources, which can, if selected be dereferenced, so content
/// stream is encapsulated and doesn't contain references.
class PDFFORQTLIBSHARED_EXPORT PDFContentStreamBuilder
{
public:
enum class CoordinateSystem
{
Qt, ///< Qt's coordinate system, (0, 0) is top left
PDF ///< PDF's coordinate system, (0, 0) is top right
};
/// Create new content stream builder, with given size and given coordinate system.
explicit PDFContentStreamBuilder(QSizeF size, CoordinateSystem coordinateSystem);
~PDFContentStreamBuilder();
struct ContentStream
{
/// Page object, which has been created by this content stream builder
PDFObjectReference pageObject;
/// Contents of the created page
PDFObject contents;
/// Resources of the created page
PDFObject resources;
/// Temporary document, which has been created by this builder
PDFDocument document;
};
/// Starts painting on a new content stream. This function returns painter,
/// onto which can be graphics drawn. Painter respects selected coordinate system.
/// Calling begin multiple times, without subsequent calls to end function,
/// is invalid and can result in undefined behaviour.
/// \return Painter, onto which can be graphic content drawn
QPainter* begin();
/// Finishes painting on a new content stream. This function returns content
/// stream object, which is associated with this page. This function
/// must be called with painter, which has been returned with call to begin function.
/// \param painter Painter, which was returned with function begin()
ContentStream end(QPainter* painter);
/// Returns actually used coordinate system
CoordinateSystem getCoordinateSystem() const { return m_coordinateSystem; }
private:
QSizeF m_size;
CoordinateSystem m_coordinateSystem;
QBuffer* m_buffer;
QPdfWriter* m_pdfWriter;
QPainter* m_painter;
};
class PDFFORQTLIBSHARED_EXPORT PDFDocumentBuilder class PDFFORQTLIBSHARED_EXPORT PDFDocumentBuilder
{ {
public: public:
@ -212,6 +272,11 @@ public:
/// Returns annotation bounding rectangle /// Returns annotation bounding rectangle
std::array<PDFReal, 4> getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const; std::array<PDFReal, 4> getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const;
/// If reference \p annotationReference points to supported annotation,
/// then this function updates annotation's appearance streams.
/// \param annotationReference Reference to the annotation
void updateAnnotationAppearanceStreams(PDFObjectReference annotationReference);
/* START GENERATED CODE */ /* START GENERATED CODE */
/// Appends a new page after last page. /// Appends a new page after last page.
@ -763,6 +828,15 @@ private:
PDFObjectReference getCatalogReference() const; PDFObjectReference getCatalogReference() const;
void updateDocumentInfo(PDFObject info); void updateDocumentInfo(PDFObject info);
/// Copies objects from another storage. Objects have adjusted references to match
/// this storage references and objects are added after the last objects of active storage.
/// This function can also automatically create references from direct objects passed
/// by parameter \p objects, if \p createReferences is set to true.
/// \param objects Objects, which we want to copy from another storage
/// \param storage Storage, from which we are copying from
/// \param createReferences Create references from \p objects
std::vector<PDFObject> copyFrom(const std::vector<PDFObject>& objects, const PDFObjectStorage& storage, bool createReferences);
PDFObjectStorage m_storage; PDFObjectStorage m_storage;
PDFVersion m_version; PDFVersion m_version;
}; };

View File

@ -104,10 +104,10 @@ const PDFEmbeddedFile* PDFFileSpecification::getPlatformFile() const
return nullptr; return nullptr;
} }
PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PDFObject object) PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFFileSpecification result; PDFFileSpecification result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isString()) if (object.isString())
{ {
@ -115,7 +115,7 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PD
} }
else if (object.isDictionary()) else if (object.isDictionary())
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
const PDFDictionary* dictionary = object.getDictionary(); const PDFDictionary* dictionary = object.getDictionary();
PDFObject collectionObject = dictionary->get("Cl"); PDFObject collectionObject = dictionary->get("Cl");
@ -129,13 +129,13 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PD
result.m_description = loader.readTextStringFromDictionary(dictionary, "Desc", QString()); result.m_description = loader.readTextStringFromDictionary(dictionary, "Desc", QString());
result.m_collection = collectionObject.isReference() ? collectionObject.getReference() : PDFObjectReference(); result.m_collection = collectionObject.isReference() ? collectionObject.getReference() : PDFObjectReference();
PDFObject embeddedFiles = document->getObject(dictionary->get("EF")); PDFObject embeddedFiles = storage->getObject(dictionary->get("EF"));
if (embeddedFiles.isDictionary()) if (embeddedFiles.isDictionary())
{ {
const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary(); const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary();
for (size_t i = 0; i < embeddedFilesDictionary->getCount(); ++i) for (size_t i = 0; i < embeddedFilesDictionary->getCount(); ++i)
{ {
result.m_embeddedFiles[embeddedFilesDictionary->getKey(i)] = PDFEmbeddedFile::parse(document, embeddedFilesDictionary->getValue(i)); result.m_embeddedFiles[embeddedFilesDictionary->getKey(i)] = PDFEmbeddedFile::parse(storage, embeddedFilesDictionary->getValue(i));
} }
} }
} }
@ -143,20 +143,20 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PD
return result; return result;
} }
PDFEmbeddedFile PDFEmbeddedFile::parse(const PDFDocument* document, PDFObject object) PDFEmbeddedFile PDFEmbeddedFile::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFEmbeddedFile result; PDFEmbeddedFile result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isStream()) if (object.isStream())
{ {
const PDFStream* stream = object.getStream(); const PDFStream* stream = object.getStream();
const PDFDictionary* dictionary = stream->getDictionary(); const PDFDictionary* dictionary = stream->getDictionary();
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_stream = object; result.m_stream = object;
result.m_subtype = loader.readNameFromDictionary(dictionary, "Subtype"); result.m_subtype = loader.readNameFromDictionary(dictionary, "Subtype");
const PDFObject& paramsObject = document->getObject(dictionary->get("Params")); const PDFObject& paramsObject = storage->getObject(dictionary->get("Params"));
if (paramsObject.isDictionary()) if (paramsObject.isDictionary())
{ {
const PDFDictionary* paramsDictionary = paramsObject.getDictionary(); const PDFDictionary* paramsDictionary = paramsObject.getDictionary();

View File

@ -24,7 +24,7 @@
namespace pdf namespace pdf
{ {
class PDFDocument; class PDFObjectStorage;
class PDFEmbeddedFile class PDFEmbeddedFile
{ {
@ -39,7 +39,7 @@ public:
const QByteArray& getChecksum() const { return m_checksum; } const QByteArray& getChecksum() const { return m_checksum; }
const PDFStream* getStream() const { return m_stream.getStream(); } const PDFStream* getStream() const { return m_stream.getStream(); }
static PDFEmbeddedFile parse(const PDFDocument* document, PDFObject object); static PDFEmbeddedFile parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
PDFObject m_stream; PDFObject m_stream;
@ -75,7 +75,7 @@ public:
PDFObjectReference getCollection() const { return m_collection; } PDFObjectReference getCollection() const { return m_collection; }
const std::map<QByteArray, PDFEmbeddedFile>& getEmbeddedFiles() const { return m_embeddedFiles; } const std::map<QByteArray, PDFEmbeddedFile>& getEmbeddedFiles() const { return m_embeddedFiles; }
static PDFFileSpecification parse(const PDFDocument* document, PDFObject object); static PDFFileSpecification parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
/// Name of the file system used to interpret this file specification, /// Name of the file system used to interpret this file specification,

View File

@ -23,11 +23,11 @@
namespace pdf namespace pdf
{ {
PDFSound PDFSound::parse(const PDFDocument* document, PDFObject object) PDFSound PDFSound::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFSound result; PDFSound result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isStream()) if (object.isStream())
{ {
const PDFStream* stream = object.getStream(); const PDFStream* stream = object.getStream();
@ -41,24 +41,24 @@ PDFSound PDFSound::parse(const PDFDocument* document, PDFObject object)
}; };
// Jakub Melka: parse the sound without exceptions // Jakub Melka: parse the sound without exceptions
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F")); result.m_fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
result.m_samplingRate = loader.readNumberFromDictionary(dictionary, "R", 0.0); result.m_samplingRate = loader.readNumberFromDictionary(dictionary, "R", 0.0);
result.m_channels = loader.readIntegerFromDictionary(dictionary, "C", 1); result.m_channels = loader.readIntegerFromDictionary(dictionary, "C", 1);
result.m_bitsPerSample = loader.readIntegerFromDictionary(dictionary, "B", 8); result.m_bitsPerSample = loader.readIntegerFromDictionary(dictionary, "B", 8);
result.m_format = loader.readEnumByName(dictionary->get("E"), formats.cbegin(), formats.cend(), Format::Raw); result.m_format = loader.readEnumByName(dictionary->get("E"), formats.cbegin(), formats.cend(), Format::Raw);
result.m_soundCompression = loader.readNameFromDictionary(dictionary, "CO"); result.m_soundCompression = loader.readNameFromDictionary(dictionary, "CO");
result.m_soundCompressionParameters = document->getObject(dictionary->get("CP")); result.m_soundCompressionParameters = storage->getObject(dictionary->get("CP"));
result.m_streamObject = object; result.m_streamObject = object;
} }
return result; return result;
} }
PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object) PDFRendition PDFRendition::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFRendition result; PDFRendition result;
object = document->getObject(object); object = storage->getObject(object);
const PDFDictionary* renditionDictionary = nullptr; const PDFDictionary* renditionDictionary = nullptr;
if (object.isDictionary()) if (object.isDictionary())
{ {
@ -76,17 +76,17 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
std::pair<const char*, Type>{ "SR", Type::Selector } std::pair<const char*, Type>{ "SR", Type::Selector }
}; };
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_type = loader.readEnumByName(renditionDictionary->get("S"), types.cbegin(), types.cend(), Type::Invalid); result.m_type = loader.readEnumByName(renditionDictionary->get("S"), types.cbegin(), types.cend(), Type::Invalid);
result.m_name = loader.readTextStringFromDictionary(renditionDictionary, "N", QString()); result.m_name = loader.readTextStringFromDictionary(renditionDictionary, "N", QString());
auto readMediaCriteria = [renditionDictionary, document](const char* entry) auto readMediaCriteria = [renditionDictionary, storage](const char* entry)
{ {
PDFObject dictionaryObject = document->getObject(renditionDictionary->get(entry)); PDFObject dictionaryObject = storage->getObject(renditionDictionary->get(entry));
if (dictionaryObject.isDictionary()) if (dictionaryObject.isDictionary())
{ {
const PDFDictionary* dictionary = dictionaryObject.getDictionary(); const PDFDictionary* dictionary = dictionaryObject.getDictionary();
return PDFMediaCriteria::parse(document, dictionary->get("C")); return PDFMediaCriteria::parse(storage, dictionary->get("C"));
} }
return PDFMediaCriteria(); return PDFMediaCriteria();
@ -100,9 +100,9 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
case Type::Media: case Type::Media:
{ {
MediaRenditionData data; MediaRenditionData data;
data.clip = PDFMediaClip::parse(document, renditionDictionary->get("C")); data.clip = PDFMediaClip::parse(storage, renditionDictionary->get("C"));
data.playParameters = PDFMediaPlayParameters::parse(document, renditionDictionary->get("P")); data.playParameters = PDFMediaPlayParameters::parse(storage, renditionDictionary->get("P"));
data.screenParameters = PDFMediaScreenParameters::parse(document, renditionDictionary->get("SP")); data.screenParameters = PDFMediaScreenParameters::parse(storage, renditionDictionary->get("SP"));
result.m_data = qMove(data); result.m_data = qMove(data);
break; break;
@ -122,22 +122,22 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
return result; return result;
} }
PDFMediaMinimumBitDepth PDFMediaMinimumBitDepth::parse(const PDFDocument* document, PDFObject object) PDFMediaMinimumBitDepth PDFMediaMinimumBitDepth::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
return PDFMediaMinimumBitDepth(loader.readIntegerFromDictionary(dictionary, "V", -1), loader.readIntegerFromDictionary(dictionary, "M", 0)); return PDFMediaMinimumBitDepth(loader.readIntegerFromDictionary(dictionary, "V", -1), loader.readIntegerFromDictionary(dictionary, "M", 0));
} }
return PDFMediaMinimumBitDepth(-1, -1); return PDFMediaMinimumBitDepth(-1, -1);
} }
PDFMediaMinimumScreenSize PDFMediaMinimumScreenSize::parse(const PDFDocument* document, PDFObject object) PDFMediaMinimumScreenSize PDFMediaMinimumScreenSize::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
std::vector<PDFInteger> values = loader.readIntegerArrayFromDictionary(dictionary, "V"); std::vector<PDFInteger> values = loader.readIntegerArrayFromDictionary(dictionary, "V");
if (values.size() == 2) if (values.size() == 2)
{ {
@ -148,11 +148,11 @@ PDFMediaMinimumScreenSize PDFMediaMinimumScreenSize::parse(const PDFDocument* do
return PDFMediaMinimumScreenSize(-1, -1, -1); return PDFMediaMinimumScreenSize(-1, -1, -1);
} }
PDFMediaSoftwareIdentifier PDFMediaSoftwareIdentifier::parse(const PDFDocument* document, PDFObject object) PDFMediaSoftwareIdentifier PDFMediaSoftwareIdentifier::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
return PDFMediaSoftwareIdentifier(loader.readTextStringFromDictionary(dictionary, "U", QString()).toLatin1(), return PDFMediaSoftwareIdentifier(loader.readTextStringFromDictionary(dictionary, "U", QString()).toLatin1(),
loader.readIntegerArrayFromDictionary(dictionary, "L"), loader.readIntegerArrayFromDictionary(dictionary, "L"),
loader.readIntegerArrayFromDictionary(dictionary, "H"), loader.readIntegerArrayFromDictionary(dictionary, "H"),
@ -164,13 +164,13 @@ PDFMediaSoftwareIdentifier PDFMediaSoftwareIdentifier::parse(const PDFDocument*
return PDFMediaSoftwareIdentifier(QByteArray(), { }, { }, true, true, { }); return PDFMediaSoftwareIdentifier(QByteArray(), { }, { }, true, true, { });
} }
PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject object) PDFMediaCriteria PDFMediaCriteria::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFMediaCriteria criteria; PDFMediaCriteria criteria;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
auto readBoolean = [&loader, dictionary](const char* name, std::optional<bool>& value) auto readBoolean = [&loader, dictionary](const char* name, std::optional<bool>& value)
{ {
if (dictionary->hasKey(name)) if (dictionary->hasKey(name))
@ -189,15 +189,15 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
} }
if (dictionary->hasKey("D")) if (dictionary->hasKey("D"))
{ {
criteria.m_minimumBitDepth = PDFMediaMinimumBitDepth::parse(document, dictionary->get("D")); criteria.m_minimumBitDepth = PDFMediaMinimumBitDepth::parse(storage, dictionary->get("D"));
} }
if (dictionary->hasKey("Z")) if (dictionary->hasKey("Z"))
{ {
criteria.m_minimumScreenSize = PDFMediaMinimumScreenSize::parse(document, dictionary->get("Z")); criteria.m_minimumScreenSize = PDFMediaMinimumScreenSize::parse(storage, dictionary->get("Z"));
} }
if (dictionary->hasKey("V")) if (dictionary->hasKey("V"))
{ {
const PDFObject& viewerObject = document->getObject(dictionary->get("V")); const PDFObject& viewerObject = storage->getObject(dictionary->get("V"));
if (viewerObject.isArray()) if (viewerObject.isArray())
{ {
std::vector<PDFMediaSoftwareIdentifier> viewers; std::vector<PDFMediaSoftwareIdentifier> viewers;
@ -205,7 +205,7 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
viewers.reserve(viewersArray->getCount()); viewers.reserve(viewersArray->getCount());
for (size_t i = 0; i < viewersArray->getCount(); ++i) for (size_t i = 0; i < viewersArray->getCount(); ++i)
{ {
viewers.emplace_back(PDFMediaSoftwareIdentifier::parse(document, viewersArray->getItem(i))); viewers.emplace_back(PDFMediaSoftwareIdentifier::parse(storage, viewersArray->getItem(i)));
} }
criteria.m_viewers = qMove(viewers); criteria.m_viewers = qMove(viewers);
} }
@ -228,11 +228,11 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
return criteria; return criteria;
} }
PDFMediaPermissions PDFMediaPermissions::parse(const PDFDocument* document, PDFObject object) PDFMediaPermissions PDFMediaPermissions::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
constexpr const std::array<std::pair<const char*, Permission>, 4> types = { constexpr const std::array<std::pair<const char*, Permission>, 4> types = {
std::pair<const char*, Permission>{ "TEMPNEVER", Permission::Never }, std::pair<const char*, Permission>{ "TEMPNEVER", Permission::Never },
std::pair<const char*, Permission>{ "TEMPEXTRACT", Permission::Extract }, std::pair<const char*, Permission>{ "TEMPEXTRACT", Permission::Extract },
@ -246,15 +246,15 @@ PDFMediaPermissions PDFMediaPermissions::parse(const PDFDocument* document, PDFO
return PDFMediaPermissions(Permission::Never); return PDFMediaPermissions(Permission::Never);
} }
PDFMediaPlayers PDFMediaPlayers::parse(const PDFDocument* document, PDFObject object) PDFMediaPlayers PDFMediaPlayers::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
auto readPlayers = [document, dictionary](const char* key) auto readPlayers = [storage, dictionary](const char* key)
{ {
std::vector<PDFMediaPlayer> result; std::vector<PDFMediaPlayer> result;
const PDFObject& playersArrayObject = document->getObject(dictionary->get(key)); const PDFObject& playersArrayObject = storage->getObject(dictionary->get(key));
if (playersArrayObject.isArray()) if (playersArrayObject.isArray())
{ {
const PDFArray* playersArray = playersArrayObject.getArray(); const PDFArray* playersArray = playersArrayObject.getArray();
@ -262,7 +262,7 @@ PDFMediaPlayers PDFMediaPlayers::parse(const PDFDocument* document, PDFObject ob
for (size_t i = 0; i < playersArray->getCount(); ++i) for (size_t i = 0; i < playersArray->getCount(); ++i)
{ {
result.emplace_back(PDFMediaPlayer::parse(document, playersArray->getItem(i))); result.emplace_back(PDFMediaPlayer::parse(storage, playersArray->getItem(i)));
} }
} }
@ -275,24 +275,24 @@ PDFMediaPlayers PDFMediaPlayers::parse(const PDFDocument* document, PDFObject ob
return PDFMediaPlayers({ }, { }, { }); return PDFMediaPlayers({ }, { }, { });
} }
PDFMediaPlayer PDFMediaPlayer::parse(const PDFDocument* document, PDFObject object) PDFMediaPlayer PDFMediaPlayer::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
return PDFMediaPlayer(PDFMediaSoftwareIdentifier::parse(document, dictionary->get("PID"))); return PDFMediaPlayer(PDFMediaSoftwareIdentifier::parse(storage, dictionary->get("PID")));
} }
return PDFMediaPlayer(PDFMediaSoftwareIdentifier(QByteArray(), { }, { }, true, true, { })); return PDFMediaPlayer(PDFMediaSoftwareIdentifier(QByteArray(), { }, { }, true, true, { }));
} }
PDFMediaOffset PDFMediaOffset::parse(const PDFDocument* document, PDFObject object) PDFMediaOffset PDFMediaOffset::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
QByteArray S = loader.readNameFromDictionary(dictionary, "S"); QByteArray S = loader.readNameFromDictionary(dictionary, "S");
if (S == "T") if (S == "T")
{ {
if (const PDFDictionary* timespanDictionary = document->getDictionaryFromObject(dictionary->get("T"))) if (const PDFDictionary* timespanDictionary = storage->getDictionaryFromObject(dictionary->get("T")))
{ {
return PDFMediaOffset(Type::Time, TimeData{ loader.readIntegerFromDictionary(timespanDictionary, "V", 0) }); return PDFMediaOffset(Type::Time, TimeData{ loader.readIntegerFromDictionary(timespanDictionary, "V", 0) });
} }
@ -310,14 +310,14 @@ PDFMediaOffset PDFMediaOffset::parse(const PDFDocument* document, PDFObject obje
return PDFMediaOffset(Type::Invalid, std::monostate()); return PDFMediaOffset(Type::Invalid, std::monostate());
} }
PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object) PDFMediaClip PDFMediaClip::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
MediaClipData clipData; MediaClipData clipData;
std::vector<MediaSectionData> sections; std::vector<MediaSectionData> sections;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
std::set<PDFObjectReference> usedReferences; std::set<PDFObjectReference> usedReferences;
while (dictionary) while (dictionary)
{ {
@ -326,23 +326,23 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
{ {
clipData.name = loader.readTextStringFromDictionary(dictionary, "N", QString()); clipData.name = loader.readTextStringFromDictionary(dictionary, "N", QString());
PDFObject fileSpecificationOrStreamObject = document->getObject(dictionary->get("D")); PDFObject fileSpecificationOrStreamObject = storage->getObject(dictionary->get("D"));
if (fileSpecificationOrStreamObject.isStream()) if (fileSpecificationOrStreamObject.isStream())
{ {
clipData.dataStream = fileSpecificationOrStreamObject; clipData.dataStream = fileSpecificationOrStreamObject;
} }
else else
{ {
clipData.fileSpecification = PDFFileSpecification::parse(document, fileSpecificationOrStreamObject); clipData.fileSpecification = PDFFileSpecification::parse(storage, fileSpecificationOrStreamObject);
} }
clipData.contentType = loader.readStringFromDictionary(dictionary, "CT"); clipData.contentType = loader.readStringFromDictionary(dictionary, "CT");
clipData.permissions = PDFMediaPermissions::parse(document, dictionary->get("P")); clipData.permissions = PDFMediaPermissions::parse(storage, dictionary->get("P"));
clipData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(document, dictionary->get("Alt")); clipData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(storage, dictionary->get("Alt"));
clipData.players = PDFMediaPlayers::parse(document, dictionary->get("PL")); clipData.players = PDFMediaPlayers::parse(storage, dictionary->get("PL"));
auto getBaseUrl = [&loader, document, dictionary](const char* name) auto getBaseUrl = [&loader, storage, dictionary](const char* name)
{ {
if (const PDFDictionary* subdictionary = document->getDictionaryFromObject(dictionary->get(name))) if (const PDFDictionary* subdictionary = storage->getDictionaryFromObject(dictionary->get(name)))
{ {
return loader.readStringFromDictionary(subdictionary, "BU"); return loader.readStringFromDictionary(subdictionary, "BU");
} }
@ -357,16 +357,16 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
{ {
MediaSectionData sectionData; MediaSectionData sectionData;
sectionData.name = loader.readTextStringFromDictionary(dictionary, "N", QString()); sectionData.name = loader.readTextStringFromDictionary(dictionary, "N", QString());
sectionData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(document, dictionary->get("Alt")); sectionData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(storage, dictionary->get("Alt"));
auto readMediaSectionBeginEnd = [document, dictionary](const char* name) auto readMediaSectionBeginEnd = [storage, dictionary](const char* name)
{ {
MediaSectionBeginEnd result; MediaSectionBeginEnd result;
if (const PDFDictionary* subdictionary = document->getDictionaryFromObject(dictionary->get(name))) if (const PDFDictionary* subdictionary = storage->getDictionaryFromObject(dictionary->get(name)))
{ {
result.offsetBegin = PDFMediaOffset::parse(document, subdictionary->get("B")); result.offsetBegin = PDFMediaOffset::parse(storage, subdictionary->get("B"));
result.offsetEnd = PDFMediaOffset::parse(document, subdictionary->get("E")); result.offsetEnd = PDFMediaOffset::parse(storage, subdictionary->get("E"));
} }
return result; return result;
@ -384,7 +384,7 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
} }
usedReferences.insert(next.getReference()); usedReferences.insert(next.getReference());
} }
dictionary = document->getDictionaryFromObject(next); dictionary = storage->getDictionaryFromObject(next);
continue; continue;
} }
@ -395,21 +395,21 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
return PDFMediaClip(qMove(clipData), qMove(sections)); return PDFMediaClip(qMove(clipData), qMove(sections));
} }
PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFDocument* document, PDFObject object) PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFMediaMultiLanguageTexts texts; PDFMediaMultiLanguageTexts texts;
object = document->getObject(object); object = storage->getObject(object);
if (object.isArray()) if (object.isArray())
{ {
const PDFArray* array = object.getArray(); const PDFArray* array = object.getArray();
if (array->getCount() % 2 == 0) if (array->getCount() % 2 == 0)
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
const size_t pairs = array->getCount() / 2; const size_t pairs = array->getCount() / 2;
for (size_t i = 0; i < pairs; ++i) for (size_t i = 0; i < pairs; ++i)
{ {
const PDFObject& languageName = document->getObject(array->getItem(2 * i)); const PDFObject& languageName = storage->getObject(array->getItem(2 * i));
const PDFObject& text = array->getItem(2 * i + 1); const PDFObject& text = array->getItem(2 * i + 1);
if (languageName.isString()) if (languageName.isString())
@ -423,28 +423,28 @@ PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFDocument*
return texts; return texts;
} }
PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFDocument* document, PDFObject object) PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFMediaPlayParameters result; PDFMediaPlayParameters result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
result.m_players = PDFMediaPlayers::parse(document, dictionary->get("PL")); result.m_players = PDFMediaPlayers::parse(storage, dictionary->get("PL"));
auto getPlayParameters = [document, dictionary](const char* name) auto getPlayParameters = [storage, dictionary](const char* name)
{ {
PlayParameters parameters; PlayParameters parameters;
if (const PDFDictionary* subdictionary = document->getDictionaryFromObject(dictionary->get(name))) if (const PDFDictionary* subdictionary = storage->getDictionaryFromObject(dictionary->get(name)))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
parameters.volume = loader.readIntegerFromDictionary(subdictionary, "V", 100); parameters.volume = loader.readIntegerFromDictionary(subdictionary, "V", 100);
parameters.controllerUserInterface = loader.readBooleanFromDictionary(subdictionary, "C", false); parameters.controllerUserInterface = loader.readBooleanFromDictionary(subdictionary, "C", false);
parameters.fitMode = static_cast<FitMode>(loader.readIntegerFromDictionary(subdictionary, "F", 5)); parameters.fitMode = static_cast<FitMode>(loader.readIntegerFromDictionary(subdictionary, "F", 5));
parameters.playAutomatically = loader.readBooleanFromDictionary(subdictionary, "A", true); parameters.playAutomatically = loader.readBooleanFromDictionary(subdictionary, "A", true);
parameters.repeat = loader.readNumberFromDictionary(dictionary, "RC", 1.0); parameters.repeat = loader.readNumberFromDictionary(dictionary, "RC", 1.0);
if (const PDFDictionary* durationDictionary = document->getDictionaryFromObject(subdictionary->get("D"))) if (const PDFDictionary* durationDictionary = storage->getDictionaryFromObject(subdictionary->get("D")))
{ {
constexpr const std::array<std::pair<const char*, Duration>, 3> durations = { constexpr const std::array<std::pair<const char*, Duration>, 3> durations = {
std::pair<const char*, Duration>{ "I", Duration::Intrinsic }, std::pair<const char*, Duration>{ "I", Duration::Intrinsic },
@ -453,7 +453,7 @@ PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFDocument* document
}; };
parameters.duration = loader.readEnumByName(durationDictionary->get("S"), durations.cbegin(), durations.cend(), Duration::Intrinsic); parameters.duration = loader.readEnumByName(durationDictionary->get("S"), durations.cbegin(), durations.cend(), Duration::Intrinsic);
if (const PDFDictionary* timeDictionary = document->getDictionaryFromObject(durationDictionary->get("T"))) if (const PDFDictionary* timeDictionary = storage->getDictionaryFromObject(durationDictionary->get("T")))
{ {
parameters.durationSeconds = loader.readNumberFromDictionary(timeDictionary, "V", 0.0); parameters.durationSeconds = loader.readNumberFromDictionary(timeDictionary, "V", 0.0);
} }
@ -469,16 +469,16 @@ PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFDocument* document
return result; return result;
} }
PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* document, PDFObject object) PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
auto getScreenParameters = [document, dictionary](const char* name) auto getScreenParameters = [storage, dictionary](const char* name)
{ {
ScreenParameters result; ScreenParameters result;
if (const PDFDictionary* screenDictionary = document->getDictionaryFromObject(dictionary->get(name))) if (const PDFDictionary* screenDictionary = storage->getDictionaryFromObject(dictionary->get(name)))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.windowType = static_cast<WindowType>(loader.readIntegerFromDictionary(screenDictionary, "W", 3)); result.windowType = static_cast<WindowType>(loader.readIntegerFromDictionary(screenDictionary, "W", 3));
result.opacity = loader.readNumberFromDictionary(screenDictionary, "O", 1.0); result.opacity = loader.readNumberFromDictionary(screenDictionary, "O", 1.0);
result.monitorSpecification = loader.readIntegerFromDictionary(screenDictionary, "M", 0); result.monitorSpecification = loader.readIntegerFromDictionary(screenDictionary, "M", 0);
@ -486,7 +486,7 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
rgb.resize(3, 1.0); rgb.resize(3, 1.0);
result.backgroundColor.setRgbF(rgb[0], rgb[1], rgb[2]); result.backgroundColor.setRgbF(rgb[0], rgb[1], rgb[2]);
if (const PDFDictionary* floatWindowDictionary = document->getDictionaryFromObject(screenDictionary->get("F"))) if (const PDFDictionary* floatWindowDictionary = storage->getDictionaryFromObject(screenDictionary->get("F")))
{ {
std::vector<PDFInteger> sizeArray = loader.readIntegerArrayFromDictionary(floatWindowDictionary, "D"); std::vector<PDFInteger> sizeArray = loader.readIntegerArrayFromDictionary(floatWindowDictionary, "D");
sizeArray.resize(2, 0); sizeArray.resize(2, 0);
@ -496,7 +496,7 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
result.floatingWindowHasTitleBar = loader.readBooleanFromDictionary(floatWindowDictionary, "T", true); result.floatingWindowHasTitleBar = loader.readBooleanFromDictionary(floatWindowDictionary, "T", true);
result.floatingWindowCloseable = loader.readBooleanFromDictionary(floatWindowDictionary, "UC", true); result.floatingWindowCloseable = loader.readBooleanFromDictionary(floatWindowDictionary, "UC", true);
result.floatingWindowResizeMode = static_cast<ResizeMode>(loader.readIntegerFromDictionary(floatWindowDictionary, "R", 0)); result.floatingWindowResizeMode = static_cast<ResizeMode>(loader.readIntegerFromDictionary(floatWindowDictionary, "R", 0));
result.floatingWindowTitle = PDFMediaMultiLanguageTexts::parse(document, floatWindowDictionary->get("TT")); result.floatingWindowTitle = PDFMediaMultiLanguageTexts::parse(storage, floatWindowDictionary->get("TT"));
switch (loader.readIntegerFromDictionary(floatWindowDictionary, "P", 4)) switch (loader.readIntegerFromDictionary(floatWindowDictionary, "P", 4))
{ {
case 0: case 0:
@ -539,14 +539,14 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
return PDFMediaScreenParameters(); return PDFMediaScreenParameters();
} }
PDFMovie PDFMovie::parse(const PDFDocument* document, PDFObject object) PDFMovie PDFMovie::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFMovie result; PDFMovie result;
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.m_movieFile = PDFFileSpecification::parse(document, dictionary->get("F")); result.m_movieFile = PDFFileSpecification::parse(storage, dictionary->get("F"));
std::vector<PDFInteger> windowSizeArray = loader.readIntegerArrayFromDictionary(dictionary, "Aspect"); std::vector<PDFInteger> windowSizeArray = loader.readIntegerArrayFromDictionary(dictionary, "Aspect");
if (windowSizeArray.size() == 2) if (windowSizeArray.size() == 2)
{ {
@ -554,7 +554,7 @@ PDFMovie PDFMovie::parse(const PDFDocument* document, PDFObject object)
} }
result.m_rotationAngle = loader.readIntegerFromDictionary(dictionary, "Rotate", 0); result.m_rotationAngle = loader.readIntegerFromDictionary(dictionary, "Rotate", 0);
PDFObject posterObject = document->getObject(dictionary->get("Poster")); PDFObject posterObject = storage->getObject(dictionary->get("Poster"));
if (posterObject.isBool()) if (posterObject.isBool())
{ {
result.m_showPoster = posterObject.getBool(); result.m_showPoster = posterObject.getBool();
@ -571,13 +571,13 @@ PDFMovie PDFMovie::parse(const PDFDocument* document, PDFObject object)
return PDFMovie(); return PDFMovie();
} }
PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObject object) PDFMovieActivation PDFMovieActivation::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFMovieActivation result; PDFMovieActivation result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
constexpr const std::array<std::pair<const char*, Mode>, 4> modes = { constexpr const std::array<std::pair<const char*, Mode>, 4> modes = {
std::pair<const char*, Mode>{ "Once", Mode::Once }, std::pair<const char*, Mode>{ "Once", Mode::Once },
@ -597,8 +597,8 @@ PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObj
relativePosition.resize(2, 0.5); relativePosition.resize(2, 0.5);
} }
result.m_start = parseMovieTime(document, dictionary->get("Start")); result.m_start = parseMovieTime(storage, dictionary->get("Start"));
result.m_duration = parseMovieTime(document, dictionary->get("Duration")); result.m_duration = parseMovieTime(storage, dictionary->get("Duration"));
result.m_rate = loader.readNumberFromDictionary(dictionary, "Rate", 1.0); result.m_rate = loader.readNumberFromDictionary(dictionary, "Rate", 1.0);
result.m_volume = loader.readNumberFromDictionary(dictionary, "Volume", 1.0); result.m_volume = loader.readNumberFromDictionary(dictionary, "Volume", 1.0);
result.m_showControls = loader.readBooleanFromDictionary(dictionary, "ShowControls", false); result.m_showControls = loader.readBooleanFromDictionary(dictionary, "ShowControls", false);
@ -612,11 +612,11 @@ PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObj
return result; return result;
} }
PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFDocument* document, PDFObject object) PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFObjectStorage* storage, PDFObject object)
{ {
MovieTime result; MovieTime result;
object = document->getObject(object); object = storage->getObject(object);
if (object.isInt()) if (object.isInt())
{ {
result.value = object.getInteger(); result.value = object.getInteger();
@ -630,10 +630,10 @@ PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFDocume
const PDFArray* objectArray = object.getArray(); const PDFArray* objectArray = object.getArray();
if (objectArray->getCount() == 2) if (objectArray->getCount() == 2)
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
result.unitsPerSecond = loader.readInteger(objectArray->getItem(1), 0); result.unitsPerSecond = loader.readInteger(objectArray->getItem(1), 0);
object = document->getObject(objectArray->getItem(0)); object = storage->getObject(objectArray->getItem(0));
if (object.isInt()) if (object.isInt())
{ {
result.value = object.getInteger(); result.value = object.getInteger();

View File

@ -28,11 +28,11 @@
namespace pdf namespace pdf
{ {
class PDFDocument; class PDFObjectStorage;
struct PDFMediaMultiLanguageTexts struct PDFMediaMultiLanguageTexts
{ {
static PDFMediaMultiLanguageTexts parse(const PDFDocument* document, PDFObject object); static PDFMediaMultiLanguageTexts parse(const PDFObjectStorage* storage, PDFObject object);
std::map<QByteArray, QString> texts; std::map<QByteArray, QString> texts;
}; };
@ -78,7 +78,7 @@ public:
} }
static PDFMediaOffset parse(const PDFDocument* document, PDFObject object); static PDFMediaOffset parse(const PDFObjectStorage* storage, PDFObject object);
const TimeData* getTimeData() const { return std::holds_alternative<TimeData>(m_data) ? &std::get<TimeData>(m_data) : nullptr; } const TimeData* getTimeData() const { return std::holds_alternative<TimeData>(m_data) ? &std::get<TimeData>(m_data) : nullptr; }
const FrameData* getFrameData() const { return std::holds_alternative<FrameData>(m_data) ? &std::get<FrameData>(m_data) : nullptr; } const FrameData* getFrameData() const { return std::holds_alternative<FrameData>(m_data) ? &std::get<FrameData>(m_data) : nullptr; }
@ -104,7 +104,7 @@ public:
} }
static PDFMediaSoftwareIdentifier parse(const PDFDocument* document, PDFObject object); static PDFMediaSoftwareIdentifier parse(const PDFObjectStorage* storage, PDFObject object);
const QByteArray& getSoftware() const { return m_software; } const QByteArray& getSoftware() const { return m_software; }
const std::vector<PDFInteger>& getLowVersion() const { return m_lowVersion; } const std::vector<PDFInteger>& getLowVersion() const { return m_lowVersion; }
@ -131,7 +131,7 @@ public:
} }
static PDFMediaPlayer parse(const PDFDocument* document, PDFObject object); static PDFMediaPlayer parse(const PDFObjectStorage* storage, PDFObject object);
const PDFMediaSoftwareIdentifier* getSoftwareIdentifier() const { return &m_softwareIdentifier; } const PDFMediaSoftwareIdentifier* getSoftwareIdentifier() const { return &m_softwareIdentifier; }
@ -154,7 +154,7 @@ public:
} }
static PDFMediaPlayers parse(const PDFDocument* document, PDFObject object); static PDFMediaPlayers parse(const PDFObjectStorage* storage, PDFObject object);
const std::vector<PDFMediaPlayer>& getPlayersMustUsed() const { return m_playersMustUsed; } const std::vector<PDFMediaPlayer>& getPlayersMustUsed() const { return m_playersMustUsed; }
const std::vector<PDFMediaPlayer>& getPlayersAlternate() const { return m_playersAlternate; } const std::vector<PDFMediaPlayer>& getPlayersAlternate() const { return m_playersAlternate; }
@ -191,7 +191,7 @@ public:
} }
static PDFMediaPermissions parse(const PDFDocument* document, PDFObject object); static PDFMediaPermissions parse(const PDFObjectStorage* storage, PDFObject object);
Permission getPermission() const { return m_permission; } Permission getPermission() const { return m_permission; }
@ -232,7 +232,7 @@ public:
PDFReal durationSeconds = 0.0; PDFReal durationSeconds = 0.0;
}; };
static PDFMediaPlayParameters parse(const PDFDocument* document, PDFObject object); static PDFMediaPlayParameters parse(const PDFObjectStorage* storage, PDFObject object);
const PDFMediaPlayers* getPlayers() const { return &m_players; } const PDFMediaPlayers* getPlayers() const { return &m_players; }
const PlayParameters* getPlayParametersMustHonored() const { return &m_mustHonored; } const PlayParameters* getPlayParametersMustHonored() const { return &m_mustHonored; }
@ -303,7 +303,7 @@ public:
} }
static PDFMediaScreenParameters parse(const PDFDocument* document, PDFObject object); static PDFMediaScreenParameters parse(const PDFObjectStorage* storage, PDFObject object);
const ScreenParameters* getScreenParametersMustHonored() const { return &m_mustHonored; } const ScreenParameters* getScreenParametersMustHonored() const { return &m_mustHonored; }
const ScreenParameters* getScreenParametersBestEffort() const { return &m_bestEffort; } const ScreenParameters* getScreenParametersBestEffort() const { return &m_bestEffort; }
@ -352,7 +352,7 @@ public:
} }
static PDFMediaClip parse(const PDFDocument* document, PDFObject object); static PDFMediaClip parse(const PDFObjectStorage* storage, PDFObject object);
const MediaClipData& getMediaClipData() const { return m_mediaClipData; } const MediaClipData& getMediaClipData() const { return m_mediaClipData; }
const std::vector<MediaSectionData>& getClipSections() const { return m_sections; } const std::vector<MediaSectionData>& getClipSections() const { return m_sections; }
@ -372,7 +372,7 @@ public:
} }
static PDFMediaMinimumBitDepth parse(const PDFDocument* document, PDFObject object); static PDFMediaMinimumBitDepth parse(const PDFObjectStorage* storage, PDFObject object);
PDFInteger getScreenMinimumBitDepth() const { return m_screenMinimumBitDepth; } PDFInteger getScreenMinimumBitDepth() const { return m_screenMinimumBitDepth; }
PDFInteger getMonitorSpecifier() const { return m_monitorSpecifier; } PDFInteger getMonitorSpecifier() const { return m_monitorSpecifier; }
@ -393,7 +393,7 @@ public:
} }
static PDFMediaMinimumScreenSize parse(const PDFDocument* document, PDFObject object); static PDFMediaMinimumScreenSize parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
PDFInteger m_minimumWidth; PDFInteger m_minimumWidth;
@ -409,7 +409,7 @@ class PDFMediaCriteria
public: public:
explicit inline PDFMediaCriteria() = default; explicit inline PDFMediaCriteria() = default;
static PDFMediaCriteria parse(const PDFDocument* document, PDFObject object); static PDFMediaCriteria parse(const PDFObjectStorage* storage, PDFObject object);
bool hasAudioDescriptions() const { return m_audioDescriptions.has_value(); } bool hasAudioDescriptions() const { return m_audioDescriptions.has_value(); }
bool hasTextCaptions() const { return m_textCaptions.has_value(); } bool hasTextCaptions() const { return m_textCaptions.has_value(); }
@ -473,7 +473,7 @@ public:
PDFObject renditions; PDFObject renditions;
}; };
static PDFRendition parse(const PDFDocument* document, PDFObject object); static PDFRendition parse(const PDFObjectStorage* storage, PDFObject object);
Type getType() const { return m_type; } Type getType() const { return m_type; }
const QString& getName() const { return m_name; } const QString& getName() const { return m_name; }
@ -519,7 +519,7 @@ public:
/// Creates a new sound from the object. If data are invalid, then invalid object /// Creates a new sound from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown. /// is returned, no exception is thrown.
static PDFSound parse(const PDFDocument* document, PDFObject object); static PDFSound parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
PDFFileSpecification m_fileSpecification; PDFFileSpecification m_fileSpecification;
@ -546,7 +546,7 @@ public:
/// Creates a new movie from the object. If data are invalid, then invalid object /// Creates a new movie from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown. /// is returned, no exception is thrown.
static PDFMovie parse(const PDFDocument* document, PDFObject object); static PDFMovie parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
PDFFileSpecification m_movieFile; PDFFileSpecification m_movieFile;
@ -590,10 +590,10 @@ public:
/// Creates a new moview from the object. If data are invalid, then invalid object /// Creates a new moview from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown. /// is returned, no exception is thrown.
static PDFMovieActivation parse(const PDFDocument* document, PDFObject object); static PDFMovieActivation parse(const PDFObjectStorage* storage, PDFObject object);
private: private:
static MovieTime parseMovieTime(const PDFDocument* document, PDFObject object); static MovieTime parseMovieTime(const PDFObjectStorage* storage, PDFObject object);
static PDFInteger parseMovieTimeFromString(const QByteArray& string); static PDFInteger parseMovieTimeFromString(const QByteArray& string);
MovieTime m_start; MovieTime m_start;

View File

@ -34,27 +34,27 @@ public:
explicit PDFNameTreeLoader() = delete; explicit PDFNameTreeLoader() = delete;
using MappedObjects = std::map<QByteArray, Type>; using MappedObjects = std::map<QByteArray, Type>;
using LoadMethod = std::function<Type(const PDFDocument*, const PDFObject&)>; using LoadMethod = std::function<Type(const PDFObjectStorage*, const PDFObject&)>;
/// Parses the name tree and loads its items into the map. Some errors are ignored, /// Parses the name tree and loads its items into the map. Some errors are ignored,
/// e.g. when kid is null. Objects are retrieved by \p loadMethod. /// e.g. when kid is null. Objects are retrieved by \p loadMethod.
/// \param document Document /// \param storage Object storage
/// \param root Root of the name tree /// \param root Root of the name tree
/// \param loadMethod Parsing method, which retrieves parsed object /// \param loadMethod Parsing method, which retrieves parsed object
static MappedObjects parse(const PDFDocument* document, const PDFObject& root, const LoadMethod& loadMethod) static MappedObjects parse(const PDFObjectStorage* storage, const PDFObject& root, const LoadMethod& loadMethod)
{ {
MappedObjects result; MappedObjects result;
parseImpl(result, document, root, loadMethod); parseImpl(result, storage, root, loadMethod);
return result; return result;
} }
private: private:
static void parseImpl(MappedObjects& objects, const PDFDocument* document, const PDFObject& root, const LoadMethod& loadMethod) static void parseImpl(MappedObjects& objects, const PDFObjectStorage* storage, const PDFObject& root, const LoadMethod& loadMethod)
{ {
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(root)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(root))
{ {
// Jakub Melka: First, load the objects into the map // Jakub Melka: First, load the objects into the map
const PDFObject& namedItems = document->getObject(dictionary->get("Names")); const PDFObject& namedItems = storage->getObject(dictionary->get("Names"));
if (namedItems.isArray()) if (namedItems.isArray())
{ {
const PDFArray* namedItemsArray = namedItems.getArray(); const PDFArray* namedItemsArray = namedItems.getArray();
@ -64,25 +64,25 @@ private:
const size_t numberIndex = 2 * i; const size_t numberIndex = 2 * i;
const size_t valueIndex = 2 * i + 1; const size_t valueIndex = 2 * i + 1;
const PDFObject& name = document->getObject(namedItemsArray->getItem(numberIndex)); const PDFObject& name = storage->getObject(namedItemsArray->getItem(numberIndex));
if (!name.isString()) if (!name.isString())
{ {
continue; continue;
} }
objects[name.getString()] = loadMethod(document, namedItemsArray->getItem(valueIndex)); objects[name.getString()] = loadMethod(storage, namedItemsArray->getItem(valueIndex));
} }
} }
// Then, follow the kids // Then, follow the kids
const PDFObject& kids = document->getObject(dictionary->get("Kids")); const PDFObject& kids = storage->getObject(dictionary->get("Kids"));
if (kids.isArray()) if (kids.isArray())
{ {
const PDFArray* kidsArray = kids.getArray(); const PDFArray* kidsArray = kids.getArray();
const size_t count = kidsArray->getCount(); const size_t count = kidsArray->getCount();
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
{ {
parseImpl(objects, document, kidsArray->getItem(i), loadMethod); parseImpl(objects, storage, kidsArray->getItem(i), loadMethod);
} }
} }
} }

View File

@ -70,10 +70,10 @@ void PDFOutlineItem::parseImpl(const PDFDocument* document,
{ {
currentOutlineItem->setTitle(PDFEncoding::convertTextString(titleObject.getString())); currentOutlineItem->setTitle(PDFEncoding::convertTextString(titleObject.getString()));
} }
currentOutlineItem->setAction(PDFAction::parse(document, dictionary->get("A"))); currentOutlineItem->setAction(PDFAction::parse(&document->getStorage(), dictionary->get("A")));
if (!currentOutlineItem->getAction() && dictionary->hasKey("Dest")) if (!currentOutlineItem->getAction() && dictionary->hasKey("Dest"))
{ {
currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(document, dictionary->get("Dest"))))); currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), dictionary->get("Dest")))));
} }
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(document);

View File

@ -44,6 +44,37 @@ class PDFOptionalContentActivity;
static constexpr const char* PDF_RESOURCE_EXTGSTATE = "ExtGState"; static constexpr const char* PDF_RESOURCE_EXTGSTATE = "ExtGState";
class PDFLineDashPattern
{
public:
explicit inline PDFLineDashPattern() = default;
explicit inline PDFLineDashPattern(const std::vector<PDFReal>& dashArray, PDFReal dashOffset) :
m_dashArray(dashArray),
m_dashOffset(dashOffset)
{
if (m_dashArray.size() % 2 == 1)
{
m_dashArray.push_back(m_dashArray.back());
}
}
inline const std::vector<PDFReal>& getDashArray() const { return m_dashArray; }
inline void setDashArray(const std::vector<PDFReal>& dashArray) { m_dashArray = dashArray; }
inline PDFReal getDashOffset() const { return m_dashOffset; }
inline void setDashOffset(PDFReal dashOffset) { m_dashOffset = dashOffset; }
inline bool operator==(const PDFLineDashPattern& other) const { return m_dashArray == other.m_dashArray && m_dashOffset == other.m_dashOffset; }
inline bool operator!=(const PDFLineDashPattern& other) const { return !(*this == other); }
/// Is line solid? Function returns true, if yes.
bool isSolid() const { return m_dashArray.empty(); }
private:
std::vector<PDFReal> m_dashArray;
PDFReal m_dashOffset = 0.0;
};
/// Process the contents of the page. /// Process the contents of the page.
class PDFPageContentProcessor : public PDFRenderErrorReporter class PDFPageContentProcessor : public PDFRenderErrorReporter
{ {
@ -193,34 +224,6 @@ public:
protected: protected:
class PDFLineDashPattern
{
public:
explicit inline PDFLineDashPattern() = default;
explicit inline PDFLineDashPattern(const std::vector<PDFReal>& dashArray, PDFReal dashOffset) :
m_dashArray(dashArray),
m_dashOffset(dashOffset)
{
}
inline const std::vector<PDFReal>& getDashArray() const { return m_dashArray; }
inline void setDashArray(const std::vector<PDFReal>& dashArray) { m_dashArray = dashArray; }
inline PDFReal getDashOffset() const { return m_dashOffset; }
inline void setDashOffset(PDFReal dashOffset) { m_dashOffset = dashOffset; }
inline bool operator==(const PDFLineDashPattern& other) const { return m_dashArray == other.m_dashArray && m_dashOffset == other.m_dashOffset; }
inline bool operator!=(const PDFLineDashPattern& other) const { return !(*this == other); }
/// Is line solid? Function returns true, if yes.
bool isSolid() const { return m_dashArray.empty(); }
private:
std::vector<PDFReal> m_dashArray;
PDFReal m_dashOffset = 0.0;
};
struct PDFTransparencyGroup struct PDFTransparencyGroup
{ {
PDFColorSpacePointer colorSpacePointer; PDFColorSpacePointer colorSpacePointer;

View File

@ -21,13 +21,13 @@
namespace pdf namespace pdf
{ {
PDFPageTransition PDFPageTransition::parse(const PDFDocument* document, PDFObject object) PDFPageTransition PDFPageTransition::parse(const PDFObjectStorage* storage, PDFObject object)
{ {
PDFPageTransition result; PDFPageTransition result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object)) if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
{ {
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(storage);
constexpr const std::array<std::pair<const char*, Style>, 12> styles = { constexpr const std::array<std::pair<const char*, Style>, 12> styles = {
std::pair<const char*, Style>{ "Split", Style::Split }, std::pair<const char*, Style>{ "Split", Style::Split },

View File

@ -22,7 +22,7 @@
namespace pdf namespace pdf
{ {
class PDFDocument; class PDFObjectStorage;
/// Page transition during presentation settings. /// Page transition during presentation settings.
class PDFPageTransition class PDFPageTransition
@ -57,7 +57,7 @@ public:
Outward Outward
}; };
static PDFPageTransition parse(const PDFDocument* document, PDFObject object); static PDFPageTransition parse(const PDFObjectStorage* storage, PDFObject object);
Style getStyle() const { return m_style; } Style getStyle() const { return m_style; }
PDFReal getDuration() const { return m_duration; } PDFReal getDuration() const { return m_duration; }

View File

@ -398,6 +398,7 @@ return pageReference;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -600,6 +601,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -874,6 +876,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -1077,6 +1080,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -1231,6 +1235,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -1520,6 +1525,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -1879,6 +1885,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -2025,6 +2032,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationReference);
return annotationReference;</property> return annotationReference;</property>
</QObject> </QObject>
</property> </property>
@ -2317,6 +2325,7 @@ return annotationReference;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -2584,6 +2593,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -2722,6 +2732,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">mergeTo(parentAnnotation, upgradedParentAnnotation); <property name="code">mergeTo(parentAnnotation, upgradedParentAnnotation);
updateAnnotationAppearanceStreams(popupAnnotation);
return popupAnnotation;</property> return popupAnnotation;</property>
</QObject> </QObject>
</property> </property>
@ -2953,6 +2964,7 @@ return popupAnnotation;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -3156,6 +3168,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -3310,6 +3323,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -3513,6 +3527,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -3667,6 +3682,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -3909,6 +3925,7 @@ return annotationObject;</property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">mergeTo(annotationObject, updateAnnotationPopup); <property name="code">mergeTo(annotationObject, updateAnnotationPopup);
appendTo(page, pageAnnots); appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -4112,6 +4129,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>
@ -4266,6 +4284,7 @@ return annotationObject;</property>
<property name="variableName"></property> <property name="variableName"></property>
<property name="variableType">_void</property> <property name="variableType">_void</property>
<property name="code">appendTo(page, pageAnnots); <property name="code">appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;</property> return annotationObject;</property>
</QObject> </QObject>
</property> </property>