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");
builder.setAnnotationBorderStyle(annotation, pdf::PDFAnnotationBorder::Style::Inset, 2.718);
builder.setAnnotationBorder(annotation, 5.0, 3.0, 2.0);
builder.setAnnotationColor(annotation, Qt::black);
}
}

View File

@ -23,10 +23,10 @@
namespace pdf
{
PDFActionPtr PDFAction::parse(const PDFDocument* document, PDFObject object)
PDFActionPtr PDFAction::parse(const PDFObjectStorage* storage, PDFObject object)
{
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)
@ -46,7 +46,7 @@ std::vector<const PDFAction*> PDFAction::getActionList() const
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())
{
@ -56,7 +56,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
throw PDFException(PDFTranslationContext::tr("Circular dependence in actions found."));
}
usedReferences.insert(reference);
object = document->getObjectByReference(reference);
object = storage->getObjectByReference(reference);
}
if (object.isNull())
@ -69,34 +69,34 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
throw PDFException(PDFTranslationContext::tr("Invalid action."));
}
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
const PDFDictionary* dictionary = object.getDictionary();
QByteArray name = loader.readNameFromDictionary(dictionary, "S");
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)));
}
else if (name == "GoToR")
{
PDFDestination destination = PDFDestination::parse(document, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false)));
}
else if (name == "GoToE")
{
PDFDestination destination = PDFDestination::parse(document, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToE(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false), document->getObject(dictionary->get("T"))));
PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToE(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false), storage->getObject(dictionary->get("T"))));
}
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);
PDFActionLaunch::Win win;
const PDFObject& winDictionaryObject = document->getObject(dictionary->get("Win"));
const PDFObject& winDictionaryObject = storage->getObject(dictionary->get("Win"));
if (winDictionaryObject.isDictionary())
{
const PDFDictionary* winDictionary = winDictionaryObject.getDictionary();
@ -110,7 +110,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
}
else if (name == "Thread")
{
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
PDFActionThread::Thread thread;
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 isRepeat = loader.readBooleanFromDictionary(dictionary, "Repeat", 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")
{
@ -220,7 +220,7 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
const bool isRadioButtonsPreserved = loader.readBooleanFromDictionary(dictionary, "PreserveRB", true);
PDFActionSetOCGState::StateChangeItems items;
PDFObject stateArrayObject = document->getObject(dictionary->get("State"));
PDFObject stateArrayObject = storage->getObject(dictionary->get("State"));
if (stateArrayObject.isArray())
{
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"))
{
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())
{
javascript = PDFEncoding::convertTextString(javascriptObject.getString());
}
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)));
}
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")
{
@ -283,14 +283,14 @@ PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object,
else if (name == "JavaScript")
{
QByteArray textJavaScript;
const PDFObject& javaScriptObject = document->getObject(dictionary->get("JS"));
const PDFObject& javaScriptObject = storage->getObject(dictionary->get("JS"));
if (javaScriptObject.isString())
{
textJavaScript = javaScriptObject.getString();
}
else if (javaScriptObject.isStream())
{
textJavaScript = document->getDecodedStream(javaScriptObject.getStream());
textJavaScript = storage->getDecodedStream(javaScriptObject.getStream());
}
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;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isName() || object.isString())
{
@ -330,7 +330,7 @@ PDFDestination PDFDestination::parse(const PDFDocument* document, PDFObject obje
return result;
}
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
// First parse page number/page index
PDFObject pageNumberObject = array->getItem(0);

View File

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

View File

@ -22,21 +22,22 @@
#include "pdfdrawspacecontroller.h"
#include "pdfcms.h"
#include "pdfwidgetutils.h"
#include "pdfpagecontentprocessor.h"
namespace pdf
{
PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document, PDFObject object)
PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFObjectStorage* storage, PDFObject object)
{
PDFAnnotationBorder result;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isArray())
{
const PDFArray* array = object.getArray();
if (array->getCount() >= 3)
{
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
result.m_definition = Definition::Simple;
result.m_hCornerRadius = loader.readNumber(array->getItem(0), 0.0);
result.m_vCornerRadius = loader.readNumber(array->getItem(1), 0.0);
@ -52,13 +53,13 @@ PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document
return result;
}
PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFDocument* document, PDFObject object)
PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFObjectStorage* storage, PDFObject object)
{
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_width = loader.readNumberFromDictionary(dictionary, "W", 1.0);
@ -76,13 +77,13 @@ PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFDocument* document, PD
return result;
}
PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFDocument* document, PDFObject object)
PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFObjectStorage* storage, PDFObject object)
{
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);
constexpr const std::array<std::pair<const char*, Effect>, 2> effects = {
@ -96,16 +97,16 @@ PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFDocument* do
return result;
}
PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFDocument* document, PDFObject object)
PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFObjectStorage* storage, PDFObject object)
{
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())
{
const PDFDictionary* subdictionary = document->getDictionaryFromObject(subdictionaryObject);
const PDFDictionary* subdictionary = storage->getDictionaryFromObject(subdictionaryObject);
for (size_t i = 0; i < subdictionary->getCount(); ++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::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;
const PDFDictionary* dictionary = document->getDictionaryFromObject(object);
const PDFDictionary* dictionary = storage->getDictionaryFromObject(object);
if (!dictionary)
{
return result;
}
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
QRectF annotationsRectangle = loader.readRectangle(dictionary->get("Rect"), QRectF());
@ -189,13 +200,13 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFLinkAnnotation* linkAnnotation = new PDFLinkAnnotation;
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)
{
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_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 = {
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_activationRegion = parseQuadrilaterals(document, dictionary->get("QuadPoints"), annotationsRectangle);
linkAnnotation->m_activationRegion = parseQuadrilaterals(storage, dictionary->get("QuadPoints"), annotationsRectangle);
}
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_justification = static_cast<PDFFreeTextAnnotation::Justification>(loader.readIntegerFromDictionary(dictionary, "Q", 0));
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_effect = PDFAnnotationBorderEffect::parse(document, dictionary->get("BE"));
freeTextAnnotation->m_effect = PDFAnnotationBorderEffect::parse(storage, dictionary->get("BE"));
std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD");
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_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_measureDictionary = document->getObject(dictionary->get("Measure"));
lineAnnotation->m_measureDictionary = storage->getObject(dictionary->get("Measure"));
std::vector<PDFReal> captionOffset = loader.readNumberArrayFromDictionary(dictionary, "CO");
if (captionOffset.size() == 2)
@ -280,7 +291,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
result.reset(annotation);
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");
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_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 = {
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_measure = document->getObject(dictionary->get("Measure"));
annotation->m_measure = storage->getObject(dictionary->get("Measure"));
}
else if (subtype == "Highlight" ||
subtype == "Underline" ||
@ -346,7 +357,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFHighlightAnnotation* annotation = new PDFHighlightAnnotation(type);
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")
{
@ -394,7 +405,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFInkAnnotation* annotation = new PDFInkAnnotation();
result.reset(annotation);
PDFObject inkList = document->getObject(dictionary->get("InkList"));
PDFObject inkList = storage->getObject(dictionary->get("InkList"));
if (inkList.isArray())
{
const PDFArray* inkListArray = inkList.getArray();
@ -432,7 +443,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFFileAttachmentAnnotation* annotation = new PDFFileAttachmentAnnotation();
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 = {
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();
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 = {
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);
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())
{
annotation->m_playMovie = activation.getBool();
@ -473,7 +484,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
else if (activation.isDictionary())
{
annotation->m_playMovie = true;
annotation->m_movieActivation = PDFMovieActivation::parse(document, activation);
annotation->m_movieActivation = PDFMovieActivation::parse(storage, activation);
}
}
else if (subtype == "Screen")
@ -482,9 +493,9 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
result.reset(annotation);
annotation->m_screenTitle = loader.readTextStringFromDictionary(dictionary, "T", QString());
annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(document, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(document, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(document, dictionary->get("AA"));
annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(storage, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(storage, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(storage, dictionary->get("AA"));
}
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_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(document, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(document, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(document, dictionary->get("AA"));
annotation->m_appearanceCharacteristics = PDFAnnotationAppearanceCharacteristics::parse(storage, dictionary->get("MK"));
annotation->m_action = PDFAction::parse(storage, dictionary->get("A"));
annotation->m_additionalActions = PDFAnnotationAdditionalActions::parse(storage, dictionary->get("AA"));
}
else if (subtype == "PrinterMark")
{
@ -519,7 +530,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject obj
PDFWatermarkAnnotation* annotation = new PDFWatermarkAnnotation();
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_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_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_annotationBorder = PDFAnnotationBorder::parseBS(document, dictionary->get("BS"));
result->m_annotationBorder = PDFAnnotationBorder::parseBS(storage, dictionary->get("BS"));
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_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_replyType = (loader.readNameFromDictionary(dictionary, "RT") == "Group") ? PDFMarkupAnnotation::ReplyType::Group : PDFMarkupAnnotation::ReplyType::Reply;
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;
}
PDFAnnotationQuadrilaterals PDFAnnotation::parseQuadrilaterals(const PDFDocument* document, PDFObject quadrilateralsObject, const QRectF annotationRect)
PDFAnnotationQuadrilaterals PDFAnnotation::parseQuadrilaterals(const PDFObjectStorage* storage, PDFObject quadrilateralsObject, const QRectF annotationRect)
{
QPainterPath path;
std::vector<QLineF> underlines;
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
std::vector<PDFReal> points = loader.readNumberArray(quadrilateralsObject);
const size_t quadrilateralCount = points.size() % 8;
path.reserve(int(quadrilateralCount) + 5);
@ -639,9 +650,89 @@ AnnotationLineEnding PDFAnnotation::convertNameToLineEnding(const QByteArray& na
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);
switch (points.size())
@ -659,13 +750,13 @@ PDFAnnotationCalloutLine PDFAnnotationCalloutLine::parse(const PDFDocument* docu
return PDFAnnotationCalloutLine();
}
PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::parse(const PDFDocument* document, PDFObject object)
PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::parse(const PDFObjectStorage* storage, PDFObject object)
{
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_borderColor = loader.readNumberArrayFromDictionary(dictionary, "BC");
@ -673,22 +764,22 @@ PDFAnnotationAppearanceCharacteristics PDFAnnotationAppearanceCharacteristics::p
result.m_normalCaption = loader.readTextStringFromDictionary(dictionary, "CA", QString());
result.m_rolloverCaption = loader.readTextStringFromDictionary(dictionary, "RC", QString());
result.m_downCaption = loader.readTextStringFromDictionary(dictionary, "AC", QString());
result.m_normalIcon = document->getObject(dictionary->get("I"));
result.m_rolloverIcon = document->getObject(dictionary->get("RI"));
result.m_downIcon = document->getObject(dictionary->get("IX"));
result.m_iconFit = PDFAnnotationIconFitInfo::parse(document, dictionary->get("IF"));
result.m_normalIcon = storage->getObject(dictionary->get("I"));
result.m_rolloverIcon = storage->getObject(dictionary->get("RI"));
result.m_downIcon = storage->getObject(dictionary->get("IX"));
result.m_iconFit = PDFAnnotationIconFitInfo::parse(storage, dictionary->get("IF"));
result.m_pushButtonMode = static_cast<PushButtonMode>(loader.readIntegerFromDictionary(dictionary, "TP", PDFInteger(PDFAnnotationAppearanceCharacteristics::PushButtonMode::NoIcon)));
}
return result;
}
PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFDocument* document, PDFObject object)
PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFObjectStorage* storage, PDFObject object)
{
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 = {
std::pair<const char*, PDFAnnotationIconFitInfo::ScaleCondition>{ "A", PDFAnnotationIconFitInfo::ScaleCondition::Always },
@ -717,22 +808,22 @@ PDFAnnotationIconFitInfo PDFAnnotationIconFitInfo::parse(const PDFDocument* docu
return info;
}
PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFDocument* document, PDFObject object)
PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFObjectStorage* storage, PDFObject object)
{
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[CursorLeave] = PDFAction::parse(document, dictionary->get("X"));
result.m_actions[MousePressed] = PDFAction::parse(document, dictionary->get("D"));
result.m_actions[MouseReleased] = PDFAction::parse(document, dictionary->get("U"));
result.m_actions[FocusIn] = PDFAction::parse(document, dictionary->get("Fo"));
result.m_actions[FocusOut] = PDFAction::parse(document, dictionary->get("Bl"));
result.m_actions[PageOpened] = PDFAction::parse(document, dictionary->get("PO"));
result.m_actions[PageClosed] = PDFAction::parse(document, dictionary->get("PC"));
result.m_actions[PageShow] = PDFAction::parse(document, dictionary->get("PV"));
result.m_actions[PageHide] = PDFAction::parse(document, dictionary->get("PI"));
result.m_actions[CursorEnter] = PDFAction::parse(storage, dictionary->get("E"));
result.m_actions[CursorLeave] = PDFAction::parse(storage, dictionary->get("X"));
result.m_actions[MousePressed] = PDFAction::parse(storage, dictionary->get("D"));
result.m_actions[MouseReleased] = PDFAction::parse(storage, dictionary->get("U"));
result.m_actions[FocusIn] = PDFAction::parse(storage, dictionary->get("Fo"));
result.m_actions[FocusOut] = PDFAction::parse(storage, dictionary->get("Bl"));
result.m_actions[PageOpened] = PDFAction::parse(storage, dictionary->get("PO"));
result.m_actions[PageClosed] = PDFAction::parse(storage, dictionary->get("PC"));
result.m_actions[PageShow] = PDFAction::parse(storage, dictionary->get("PV"));
result.m_actions[PageHide] = PDFAction::parse(storage, dictionary->get("PI"));
}
return result;
@ -931,7 +1022,7 @@ PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(
annotations.annotations.reserve(pageAnnotations.size());
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)
{
PageAnnotation annotation;
@ -956,4 +1047,78 @@ void PDFAnnotationManager::setTarget(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

View File

@ -31,7 +31,7 @@
namespace pdf
{
class PDFDocument;
class PDFObjectStorage;
class PDFDrawWidgetProxy;
using TextAlignment = Qt::Alignment;
@ -105,15 +105,15 @@ public:
/// 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.
/// \param document Document
/// \param storage Object storage
/// \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,
/// 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
static PDFAnnotationBorder parseBS(const PDFDocument* document, PDFObject object);
static PDFAnnotationBorder parseBS(const PDFObjectStorage* storage, PDFObject object);
/// Returns true, if object is correctly defined
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,
/// 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
static PDFAnnotationBorderEffect parse(const PDFDocument* document, PDFObject object);
static PDFAnnotationBorderEffect parse(const PDFObjectStorage* storage, PDFObject object);
private:
Effect m_effect = Effect::None;
@ -179,9 +179,9 @@ public:
/// Parses annotation appearance streams from the object. If object is invalid, then
/// empty appearance stream is constructed.
/// \param document Document
/// \param storage Object storage
/// \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,
/// then null object is returned.
@ -248,9 +248,9 @@ public:
/// Parses annotation callout line from the object. If object is invalid, then
/// invalid callout line is constructed.
/// \param document Document
/// \param storage Object storage
/// \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; }
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
/// default appearance icon fit info is constructed.
/// \param document Document
/// \param storage Object storage
/// \param object Appearance icon fit info object
static PDFAnnotationIconFitInfo parse(const PDFDocument* document, PDFObject object);
static PDFAnnotationIconFitInfo parse(const PDFObjectStorage* storage, PDFObject object);
private:
ScaleCondition m_scaleCondition = ScaleCondition::Always;
@ -329,9 +329,9 @@ public:
/// Parses annotation appearance characteristics from the object. If object is invalid, then
/// default appearance characteristics is constructed.
/// \param document Document
/// \param storage Object storage
/// \param object Appearance characteristics object
static PDFAnnotationAppearanceCharacteristics parse(const PDFDocument* document, PDFObject object);
static PDFAnnotationAppearanceCharacteristics parse(const PDFObjectStorage* storage, PDFObject object);
private:
PDFInteger m_rotation = 0;
@ -376,9 +376,9 @@ public:
/// Parses annotation additional actions from the object. If object is invalid, then
/// empty additional actions is constructed.
/// \param document Document
/// \param storage Object storage
/// \param object Additional actions object
static PDFAnnotationAdditionalActions parse(const PDFDocument* document, PDFObject object);
static PDFAnnotationAdditionalActions parse(const PDFObjectStorage* storage, PDFObject object);
private:
std::array<PDFActionPtr, End> m_actions;
@ -390,6 +390,22 @@ class PDFTextAnnotation;
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.
/// Annotations are various enhancements to pages graphical representation,
/// such as graphics, text, highlight or multimedia content, such as sounds,
@ -421,6 +437,17 @@ public:
virtual PDFMarkupAnnotation* asMarkupAnnotation() { 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 QString& getContents() const { return m_contents; }
PDFObjectReference getPageReference() const { return m_pageReference; }
@ -436,24 +463,39 @@ public:
PDFObjectReference getOptionalContent() const { return m_optionalContentReference; }
/// Parses annotation from the object. If error occurs, then nullptr is returned.
/// \param document Document
/// \param storage Object storage
/// \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,
/// then annotation rectangle is used. If annotation rectangle is also invalid,
/// then empty painter path is used.
/// \param document Document
/// \param storage Object storage
/// \param quadrilateralsObject Object with quadrilaterals definition
/// \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,
/// then None line ending is returned.
/// \param name Name of the line ending
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:
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
PDFObjectReference m_pageReference; ///< Reference to annotation's page, "P" entry
@ -497,8 +539,12 @@ public:
const QByteArray& getIntent() const { return m_intent; }
const PDFObject& getExternalData() const { return m_externalData; }
protected:
virtual QColor getStrokeColor() const override;
virtual QColor getFillColor() const override;
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_windowTitle;
PDFObjectReference m_popupAnnotation;
@ -541,7 +587,7 @@ public:
const QString& getStateModel() const { return m_stateModel; }
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;
QByteArray m_iconName;
@ -572,7 +618,7 @@ public:
const PDFAnnotationQuadrilaterals& getActivationRegion() const { return m_activationRegion; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFActionPtr m_action;
LinkHighlightMode m_highlightMode = LinkHighlightMode::Invert;
@ -614,7 +660,7 @@ public:
AnnotationLineEnding getEndLineEnding() const { return m_endLineEnding; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QByteArray m_defaultAppearance;
Justification m_justification = Justification::Left;
@ -663,7 +709,7 @@ public:
const QPointF& getCaptionOffset() const { return m_captionOffset; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QLineF m_line;
AnnotationLineEnding m_startLineEnding = AnnotationLineEnding::None;
@ -693,13 +739,17 @@ public:
}
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 PDFAnnotationBorderEffect& getBorderEffect() const { return m_effect; }
const QRectF& getGeometryRectangle() const { return m_geometryRectangle; }
protected:
virtual QColor getFillColor() const override;
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type;
std::vector<PDFReal> m_interiorColor;
@ -738,7 +788,7 @@ public:
const PDFObject& getMeasure() const { return m_measure; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type;
std::vector<QPointF> m_vertices;
@ -766,7 +816,7 @@ public:
const PDFAnnotationQuadrilaterals& getHiglightArea() const { return m_highlightArea; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
AnnotationType m_type;
PDFAnnotationQuadrilaterals m_highlightArea;
@ -790,7 +840,7 @@ public:
Symbol getSymbol() const { return m_symbol; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QRectF m_caretRectangle;
Symbol m_symbol = Symbol::None;
@ -826,7 +876,7 @@ public:
Stamp getStamp() const { return m_stamp; }
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;
};
@ -842,7 +892,7 @@ public:
const QPainterPath& getInkPath() const { return m_inkPath; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QPainterPath m_inkPath;
};
@ -860,7 +910,7 @@ public:
bool isOpened() const { return m_opened; }
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;
};
@ -887,7 +937,7 @@ public:
Icon getIcon() const { return m_icon; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFFileSpecification m_fileSpecification;
Icon m_icon = Icon::PushPin;
@ -912,7 +962,7 @@ public:
Icon getIcon() const { return m_icon; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
PDFSound m_sound;
Icon m_icon = Icon::Speaker;
@ -933,7 +983,7 @@ public:
const PDFMovieActivation& getMovieActivation() const { return m_movieActivation; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_movieTitle;
bool m_playMovie = true;
@ -956,7 +1006,7 @@ public:
const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QString m_screenTitle;
PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics;
@ -989,7 +1039,7 @@ public:
const PDFAnnotationAdditionalActions& getAdditionalActions() const { return m_additionalActions; }
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;
PDFAnnotationAppearanceCharacteristics m_appearanceCharacteristics;
@ -1031,7 +1081,7 @@ public:
PDFReal getRelativeVerticalOffset() const { return m_relativeVerticalOffset; }
private:
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
QMatrix m_matrix;
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"));
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())
{
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")))
{
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())
{
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_javaScriptActions = PDFNameTreeLoader<PDFActionPtr>::parse(document, namesDictionary->get("JavaScript"), &PDFAction::parse);
catalogObject.m_embeddedFiles = PDFNameTreeLoader<PDFFileSpecification>::parse(document, namesDictionary->get("EmbeddedFiles"), &PDFFileSpecification::parse);
catalogObject.m_destinations = PDFNameTreeLoader<PDFDestination>::parse(&document->getStorage(), namesDictionary->get("Dests"), parseDestination);
catalogObject.m_javaScriptActions = PDFNameTreeLoader<PDFActionPtr>::parse(&document->getStorage(), namesDictionary->get("JavaScript"), &PDFAction::parse);
catalogObject.m_embeddedFiles = PDFNameTreeLoader<PDFFileSpecification>::parse(&document->getStorage(), namesDictionary->get("EmbeddedFiles"), &PDFFileSpecification::parse);
}
// Examine "Dests" dictionary
@ -158,7 +158,7 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
const size_t count = destsDictionary->getCount();
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_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
{
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
@ -242,9 +247,15 @@ void PDFObjectStorage::updateTrailerDictionary(PDFObject trailerDictionary)
m_trailerDictionary = PDFObjectManipulator::merge(m_trailerDictionary, trailerDictionary, PDFObjectManipulator::RemoveNullObjects);
}
PDFDocumentDataLoaderDecorator::PDFDocumentDataLoaderDecorator(const PDFDocument* document)
: m_storage(&document->getStorage())
{
}
QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object)
{
const PDFObject& dereferencedObject = m_document->getObject(object);
const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isName())
{
return dereferencedObject.getString();
@ -255,7 +266,7 @@ QByteArray PDFDocumentDataLoaderDecorator::readName(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())
{
return dereferencedObject.getString();
@ -266,7 +277,7 @@ QByteArray PDFDocumentDataLoaderDecorator::readString(const PDFObject& object)
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())
{
return dereferencedObject.getInteger();
@ -277,7 +288,7 @@ PDFInteger PDFDocumentDataLoaderDecorator::readInteger(const PDFObject& object,
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())
{
@ -292,7 +303,7 @@ PDFReal PDFDocumentDataLoaderDecorator::readNumber(const PDFObject& object, PDFR
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())
{
@ -304,7 +315,7 @@ bool PDFDocumentDataLoaderDecorator::readBoolean(const PDFObject& object, bool d
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())
{
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
{
const PDFObject& dereferencedObject = m_document->getObject(object);
const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray())
{
const PDFArray* array = dereferencedObject.getArray();
@ -324,7 +335,7 @@ QRectF PDFDocumentDataLoaderDecorator::readRectangle(const PDFObject& object, co
std::array<PDFReal, 4> items;
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())
{
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
{
const PDFObject& dereferencedObject = m_document->getObject(object);
const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray())
{
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
{
const PDFObject& dereferencedObject = m_document->getObject(object);
const PDFObject& dereferencedObject = m_storage->getObject(object);
if (dereferencedObject.isArray())
{
const PDFArray* array = dereferencedObject.getArray();
@ -512,7 +523,7 @@ PDFObjectReference PDFDocumentDataLoaderDecorator::readReferenceFromDictionary(c
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())
{
const PDFArray* array = dereferencedObject.getArray();
@ -544,7 +555,7 @@ std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArr
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())
{
const PDFArray* array = dereferencedObject.getArray();
@ -626,7 +637,7 @@ std::vector<QByteArray> PDFDocumentDataLoaderDecorator::readStringArrayFromDicti
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())
{
const PDFArray* array = dereferencedObject.getArray();

View File

@ -69,6 +69,20 @@ public:
/// then null object is returned (no exception is thrown).
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
const PDFObjects& getObjects() const { return m_objects; }
@ -98,6 +112,11 @@ public:
/// \param trailerDictionary New trailer dictionary
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:
PDFObjects m_objects;
PDFObject m_trailerDictionary;
@ -112,7 +131,8 @@ private:
class PDFDocumentDataLoaderDecorator
{
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;
/// 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>
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())
{
QByteArray name = dereferencedObject.getString();
@ -184,7 +204,7 @@ public:
template<typename T>
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())
{
const PDFArray* array = dereferencedObject.getArray();
@ -318,7 +338,7 @@ public:
std::vector<QByteArray> readStringArrayFromDictionary(const PDFDictionary* dictionary, const char* key) const;
private:
const PDFDocument* m_document;
const PDFObjectStorage* m_storage;
};
/// PDF document main class.
@ -458,6 +478,40 @@ const PDFObject& PDFDocument::getObjectByReference(PDFObjectReference 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
#endif // PDFDOCUMENT_H

View File

@ -18,10 +18,165 @@
#include "pdfdocumentbuilder.h"
#include "pdfencoding.h"
#include "pdfconstants.h"
#include "pdfdocumentreader.h"
#include "pdfvisitor.h"
#include <QBuffer>
#include <QPainter>
#include <QPdfWriter>
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()
{
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)));
}
PDFObjectFactory& PDFObjectFactory::operator<<(const PDFObject& object)
{
addObject(object);
return *this;
}
PDFObjectFactory& PDFObjectFactory::operator<<(AnnotationBorderStyle 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()) };
}
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)
{
return m_storage.addObject(PDFObjectManipulator::removeNullObjects(object));
@ -585,6 +897,134 @@ void PDFDocumentBuilder::updateDocumentInfo(PDFObject 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 */
PDFObjectReference PDFDocumentBuilder::appendPage(QRectF mediaBox)
@ -701,6 +1141,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationCircle(PDFObjectReference
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -762,6 +1203,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReferen
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -845,6 +1287,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReferen
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -908,6 +1351,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -956,6 +1400,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1042,6 +1487,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLine(PDFObjectReference p
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1148,6 +1594,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLine(PDFObjectReference p
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1189,6 +1636,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationLink(PDFObjectReference p
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationReference);
return annotationReference;
}
@ -1271,6 +1719,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPolygon(PDFObjectReferenc
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1350,6 +1799,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPolyline(PDFObjectReferen
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1389,6 +1839,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationPopup(PDFObjectReference
objectBuilder.endDictionary();
PDFObject upgradedParentAnnotation = objectBuilder.takeObject();
mergeTo(parentAnnotation, upgradedParentAnnotation);
updateAnnotationAppearanceStreams(popupAnnotation);
return popupAnnotation;
}
@ -1457,6 +1908,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquare(PDFObjectReference
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1520,6 +1972,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1568,6 +2021,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1631,6 +2085,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationStrikeout(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1679,6 +2134,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationStrikeout(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1751,6 +2207,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationText(PDFObjectReference p
PDFObject pageAnnots = objectBuilder.takeObject();
mergeTo(annotationObject, updateAnnotationPopup);
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1814,6 +2271,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}
@ -1862,6 +2320,7 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
objectBuilder.endDictionary();
PDFObject pageAnnots = objectBuilder.takeObject();
appendTo(page, pageAnnots);
updateAnnotationAppearanceStreams(annotationObject);
return annotationObject;
}

View File

@ -22,6 +22,8 @@
#include "pdfdocument.h"
#include "pdfannotation.h"
class QPdfWriter;
namespace pdf
{
@ -108,6 +110,7 @@ public:
PDFObjectFactory& operator<<(const QPointF& point);
PDFObjectFactory& operator<<(const QDateTime& dateTime);
PDFObjectFactory& operator<<(AnnotationBorderStyle style);
PDFObjectFactory& operator<<(const PDFObject& object);
/// Treat containers - write them as array
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
@ -174,6 +177,63 @@ private:
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
{
public:
@ -212,6 +272,11 @@ public:
/// Returns annotation bounding rectangle
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 */
/// Appends a new page after last page.
@ -763,6 +828,15 @@ private:
PDFObjectReference getCatalogReference() const;
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;
PDFVersion m_version;
};

View File

@ -104,10 +104,10 @@ const PDFEmbeddedFile* PDFFileSpecification::getPlatformFile() const
return nullptr;
}
PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PDFObject object)
PDFFileSpecification PDFFileSpecification::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFFileSpecification result;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isString())
{
@ -115,7 +115,7 @@ PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PD
}
else if (object.isDictionary())
{
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
const PDFDictionary* dictionary = object.getDictionary();
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_collection = collectionObject.isReference() ? collectionObject.getReference() : PDFObjectReference();
PDFObject embeddedFiles = document->getObject(dictionary->get("EF"));
PDFObject embeddedFiles = storage->getObject(dictionary->get("EF"));
if (embeddedFiles.isDictionary())
{
const PDFDictionary* embeddedFilesDictionary = embeddedFiles.getDictionary();
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;
}
PDFEmbeddedFile PDFEmbeddedFile::parse(const PDFDocument* document, PDFObject object)
PDFEmbeddedFile PDFEmbeddedFile::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFEmbeddedFile result;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isStream())
{
const PDFStream* stream = object.getStream();
const PDFDictionary* dictionary = stream->getDictionary();
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
result.m_stream = object;
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())
{
const PDFDictionary* paramsDictionary = paramsObject.getDictionary();

View File

@ -24,7 +24,7 @@
namespace pdf
{
class PDFDocument;
class PDFObjectStorage;
class PDFEmbeddedFile
{
@ -39,7 +39,7 @@ public:
const QByteArray& getChecksum() const { return m_checksum; }
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:
PDFObject m_stream;
@ -75,7 +75,7 @@ public:
PDFObjectReference getCollection() const { return m_collection; }
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:
/// Name of the file system used to interpret this file specification,

View File

@ -23,11 +23,11 @@
namespace pdf
{
PDFSound PDFSound::parse(const PDFDocument* document, PDFObject object)
PDFSound PDFSound::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFSound result;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isStream())
{
const PDFStream* stream = object.getStream();
@ -41,24 +41,24 @@ PDFSound PDFSound::parse(const PDFDocument* document, PDFObject object)
};
// Jakub Melka: parse the sound without exceptions
PDFDocumentDataLoaderDecorator loader(document);
result.m_fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
PDFDocumentDataLoaderDecorator loader(storage);
result.m_fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
result.m_samplingRate = loader.readNumberFromDictionary(dictionary, "R", 0.0);
result.m_channels = loader.readIntegerFromDictionary(dictionary, "C", 1);
result.m_bitsPerSample = loader.readIntegerFromDictionary(dictionary, "B", 8);
result.m_format = loader.readEnumByName(dictionary->get("E"), formats.cbegin(), formats.cend(), Format::Raw);
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;
}
return result;
}
PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
PDFRendition PDFRendition::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFRendition result;
object = document->getObject(object);
object = storage->getObject(object);
const PDFDictionary* renditionDictionary = nullptr;
if (object.isDictionary())
{
@ -76,17 +76,17 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
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_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())
{
const PDFDictionary* dictionary = dictionaryObject.getDictionary();
return PDFMediaCriteria::parse(document, dictionary->get("C"));
return PDFMediaCriteria::parse(storage, dictionary->get("C"));
}
return PDFMediaCriteria();
@ -100,9 +100,9 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
case Type::Media:
{
MediaRenditionData data;
data.clip = PDFMediaClip::parse(document, renditionDictionary->get("C"));
data.playParameters = PDFMediaPlayParameters::parse(document, renditionDictionary->get("P"));
data.screenParameters = PDFMediaScreenParameters::parse(document, renditionDictionary->get("SP"));
data.clip = PDFMediaClip::parse(storage, renditionDictionary->get("C"));
data.playParameters = PDFMediaPlayParameters::parse(storage, renditionDictionary->get("P"));
data.screenParameters = PDFMediaScreenParameters::parse(storage, renditionDictionary->get("SP"));
result.m_data = qMove(data);
break;
@ -122,22 +122,22 @@ PDFRendition PDFRendition::parse(const PDFDocument* document, PDFObject object)
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(-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");
if (values.size() == 2)
{
@ -148,11 +148,11 @@ PDFMediaMinimumScreenSize PDFMediaMinimumScreenSize::parse(const PDFDocument* do
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(),
loader.readIntegerArrayFromDictionary(dictionary, "L"),
loader.readIntegerArrayFromDictionary(dictionary, "H"),
@ -164,13 +164,13 @@ PDFMediaSoftwareIdentifier PDFMediaSoftwareIdentifier::parse(const PDFDocument*
return PDFMediaSoftwareIdentifier(QByteArray(), { }, { }, true, true, { });
}
PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject object)
PDFMediaCriteria PDFMediaCriteria::parse(const PDFObjectStorage* storage, PDFObject object)
{
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)
{
if (dictionary->hasKey(name))
@ -189,15 +189,15 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
}
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"))
{
criteria.m_minimumScreenSize = PDFMediaMinimumScreenSize::parse(document, dictionary->get("Z"));
criteria.m_minimumScreenSize = PDFMediaMinimumScreenSize::parse(storage, dictionary->get("Z"));
}
if (dictionary->hasKey("V"))
{
const PDFObject& viewerObject = document->getObject(dictionary->get("V"));
const PDFObject& viewerObject = storage->getObject(dictionary->get("V"));
if (viewerObject.isArray())
{
std::vector<PDFMediaSoftwareIdentifier> viewers;
@ -205,7 +205,7 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
viewers.reserve(viewersArray->getCount());
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);
}
@ -228,11 +228,11 @@ PDFMediaCriteria PDFMediaCriteria::parse(const PDFDocument* document, PDFObject
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 = {
std::pair<const char*, Permission>{ "TEMPNEVER", Permission::Never },
std::pair<const char*, Permission>{ "TEMPEXTRACT", Permission::Extract },
@ -246,15 +246,15 @@ PDFMediaPermissions PDFMediaPermissions::parse(const PDFDocument* document, PDFO
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;
const PDFObject& playersArrayObject = document->getObject(dictionary->get(key));
const PDFObject& playersArrayObject = storage->getObject(dictionary->get(key));
if (playersArrayObject.isArray())
{
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)
{
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({ }, { }, { });
}
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, { }));
}
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");
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) });
}
@ -310,14 +310,14 @@ PDFMediaOffset PDFMediaOffset::parse(const PDFDocument* document, PDFObject obje
return PDFMediaOffset(Type::Invalid, std::monostate());
}
PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
PDFMediaClip PDFMediaClip::parse(const PDFObjectStorage* storage, PDFObject object)
{
MediaClipData clipData;
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;
while (dictionary)
{
@ -326,23 +326,23 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
{
clipData.name = loader.readTextStringFromDictionary(dictionary, "N", QString());
PDFObject fileSpecificationOrStreamObject = document->getObject(dictionary->get("D"));
PDFObject fileSpecificationOrStreamObject = storage->getObject(dictionary->get("D"));
if (fileSpecificationOrStreamObject.isStream())
{
clipData.dataStream = fileSpecificationOrStreamObject;
}
else
{
clipData.fileSpecification = PDFFileSpecification::parse(document, fileSpecificationOrStreamObject);
clipData.fileSpecification = PDFFileSpecification::parse(storage, fileSpecificationOrStreamObject);
}
clipData.contentType = loader.readStringFromDictionary(dictionary, "CT");
clipData.permissions = PDFMediaPermissions::parse(document, dictionary->get("P"));
clipData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(document, dictionary->get("Alt"));
clipData.players = PDFMediaPlayers::parse(document, dictionary->get("PL"));
clipData.permissions = PDFMediaPermissions::parse(storage, dictionary->get("P"));
clipData.alternateTextDescriptions = PDFMediaMultiLanguageTexts::parse(storage, dictionary->get("Alt"));
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");
}
@ -357,16 +357,16 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
{
MediaSectionData sectionData;
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;
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.offsetEnd = PDFMediaOffset::parse(document, subdictionary->get("E"));
result.offsetBegin = PDFMediaOffset::parse(storage, subdictionary->get("B"));
result.offsetEnd = PDFMediaOffset::parse(storage, subdictionary->get("E"));
}
return result;
@ -384,7 +384,7 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
}
usedReferences.insert(next.getReference());
}
dictionary = document->getDictionaryFromObject(next);
dictionary = storage->getDictionaryFromObject(next);
continue;
}
@ -395,21 +395,21 @@ PDFMediaClip PDFMediaClip::parse(const PDFDocument* document, PDFObject object)
return PDFMediaClip(qMove(clipData), qMove(sections));
}
PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFDocument* document, PDFObject object)
PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFObjectStorage* storage, PDFObject object)
{
PDFMediaMultiLanguageTexts texts;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isArray())
{
const PDFArray* array = object.getArray();
if (array->getCount() % 2 == 0)
{
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
const size_t pairs = array->getCount() / 2;
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);
if (languageName.isString())
@ -423,28 +423,28 @@ PDFMediaMultiLanguageTexts PDFMediaMultiLanguageTexts::parse(const PDFDocument*
return texts;
}
PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFDocument* document, PDFObject object)
PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFObjectStorage* storage, PDFObject object)
{
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;
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.controllerUserInterface = loader.readBooleanFromDictionary(subdictionary, "C", false);
parameters.fitMode = static_cast<FitMode>(loader.readIntegerFromDictionary(subdictionary, "F", 5));
parameters.playAutomatically = loader.readBooleanFromDictionary(subdictionary, "A", true);
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 = {
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);
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);
}
@ -469,16 +469,16 @@ PDFMediaPlayParameters PDFMediaPlayParameters::parse(const PDFDocument* document
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;
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.opacity = loader.readNumberFromDictionary(screenDictionary, "O", 1.0);
result.monitorSpecification = loader.readIntegerFromDictionary(screenDictionary, "M", 0);
@ -486,7 +486,7 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
rgb.resize(3, 1.0);
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");
sizeArray.resize(2, 0);
@ -496,7 +496,7 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
result.floatingWindowHasTitleBar = loader.readBooleanFromDictionary(floatWindowDictionary, "T", true);
result.floatingWindowCloseable = loader.readBooleanFromDictionary(floatWindowDictionary, "UC", true);
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))
{
case 0:
@ -539,14 +539,14 @@ PDFMediaScreenParameters PDFMediaScreenParameters::parse(const PDFDocument* docu
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;
PDFDocumentDataLoaderDecorator loader(document);
result.m_movieFile = PDFFileSpecification::parse(document, dictionary->get("F"));
PDFDocumentDataLoaderDecorator loader(storage);
result.m_movieFile = PDFFileSpecification::parse(storage, dictionary->get("F"));
std::vector<PDFInteger> windowSizeArray = loader.readIntegerArrayFromDictionary(dictionary, "Aspect");
if (windowSizeArray.size() == 2)
{
@ -554,7 +554,7 @@ PDFMovie PDFMovie::parse(const PDFDocument* document, PDFObject object)
}
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())
{
result.m_showPoster = posterObject.getBool();
@ -571,13 +571,13 @@ PDFMovie PDFMovie::parse(const PDFDocument* document, PDFObject object)
return PDFMovie();
}
PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObject object)
PDFMovieActivation PDFMovieActivation::parse(const PDFObjectStorage* storage, PDFObject object)
{
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 = {
std::pair<const char*, Mode>{ "Once", Mode::Once },
@ -597,8 +597,8 @@ PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObj
relativePosition.resize(2, 0.5);
}
result.m_start = parseMovieTime(document, dictionary->get("Start"));
result.m_duration = parseMovieTime(document, dictionary->get("Duration"));
result.m_start = parseMovieTime(storage, dictionary->get("Start"));
result.m_duration = parseMovieTime(storage, dictionary->get("Duration"));
result.m_rate = loader.readNumberFromDictionary(dictionary, "Rate", 1.0);
result.m_volume = loader.readNumberFromDictionary(dictionary, "Volume", 1.0);
result.m_showControls = loader.readBooleanFromDictionary(dictionary, "ShowControls", false);
@ -612,11 +612,11 @@ PDFMovieActivation PDFMovieActivation::parse(const PDFDocument* document, PDFObj
return result;
}
PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFDocument* document, PDFObject object)
PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFObjectStorage* storage, PDFObject object)
{
MovieTime result;
object = document->getObject(object);
object = storage->getObject(object);
if (object.isInt())
{
result.value = object.getInteger();
@ -630,10 +630,10 @@ PDFMovieActivation::MovieTime PDFMovieActivation::parseMovieTime(const PDFDocume
const PDFArray* objectArray = object.getArray();
if (objectArray->getCount() == 2)
{
PDFDocumentDataLoaderDecorator loader(document);
PDFDocumentDataLoaderDecorator loader(storage);
result.unitsPerSecond = loader.readInteger(objectArray->getItem(1), 0);
object = document->getObject(objectArray->getItem(0));
object = storage->getObject(objectArray->getItem(0));
if (object.isInt())
{
result.value = object.getInteger();

View File

@ -28,11 +28,11 @@
namespace pdf
{
class PDFDocument;
class PDFObjectStorage;
struct PDFMediaMultiLanguageTexts
{
static PDFMediaMultiLanguageTexts parse(const PDFDocument* document, PDFObject object);
static PDFMediaMultiLanguageTexts parse(const PDFObjectStorage* storage, PDFObject object);
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 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 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; }
@ -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>& 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; }
@ -232,7 +232,7 @@ public:
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 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* 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 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 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:
PDFInteger m_minimumWidth;
@ -409,7 +409,7 @@ class PDFMediaCriteria
public:
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 hasTextCaptions() const { return m_textCaptions.has_value(); }
@ -473,7 +473,7 @@ public:
PDFObject renditions;
};
static PDFRendition parse(const PDFDocument* document, PDFObject object);
static PDFRendition parse(const PDFObjectStorage* storage, PDFObject object);
Type getType() const { return m_type; }
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
/// is returned, no exception is thrown.
static PDFSound parse(const PDFDocument* document, PDFObject object);
static PDFSound parse(const PDFObjectStorage* storage, PDFObject object);
private:
PDFFileSpecification m_fileSpecification;
@ -546,7 +546,7 @@ public:
/// Creates a new movie from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown.
static PDFMovie parse(const PDFDocument* document, PDFObject object);
static PDFMovie parse(const PDFObjectStorage* storage, PDFObject object);
private:
PDFFileSpecification m_movieFile;
@ -590,10 +590,10 @@ public:
/// Creates a new moview from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown.
static PDFMovieActivation parse(const PDFDocument* document, PDFObject object);
static PDFMovieActivation parse(const PDFObjectStorage* storage, PDFObject object);
private:
static MovieTime parseMovieTime(const PDFDocument* document, PDFObject object);
static MovieTime parseMovieTime(const PDFObjectStorage* storage, PDFObject object);
static PDFInteger parseMovieTimeFromString(const QByteArray& string);
MovieTime m_start;

View File

@ -34,27 +34,27 @@ public:
explicit PDFNameTreeLoader() = delete;
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,
/// 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 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;
parseImpl(result, document, root, loadMethod);
parseImpl(result, storage, root, loadMethod);
return result;
}
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
const PDFObject& namedItems = document->getObject(dictionary->get("Names"));
const PDFObject& namedItems = storage->getObject(dictionary->get("Names"));
if (namedItems.isArray())
{
const PDFArray* namedItemsArray = namedItems.getArray();
@ -64,25 +64,25 @@ private:
const size_t numberIndex = 2 * i;
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())
{
continue;
}
objects[name.getString()] = loadMethod(document, namedItemsArray->getItem(valueIndex));
objects[name.getString()] = loadMethod(storage, namedItemsArray->getItem(valueIndex));
}
}
// Then, follow the kids
const PDFObject& kids = document->getObject(dictionary->get("Kids"));
const PDFObject& kids = storage->getObject(dictionary->get("Kids"));
if (kids.isArray())
{
const PDFArray* kidsArray = kids.getArray();
const size_t count = kidsArray->getCount();
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->setAction(PDFAction::parse(document, dictionary->get("A")));
currentOutlineItem->setAction(PDFAction::parse(&document->getStorage(), dictionary->get("A")));
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);

View File

@ -44,6 +44,37 @@ class PDFOptionalContentActivity;
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.
class PDFPageContentProcessor : public PDFRenderErrorReporter
{
@ -193,34 +224,6 @@ public:
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
{
PDFColorSpacePointer colorSpacePointer;

View File

@ -21,13 +21,13 @@
namespace pdf
{
PDFPageTransition PDFPageTransition::parse(const PDFDocument* document, PDFObject object)
PDFPageTransition PDFPageTransition::parse(const PDFObjectStorage* storage, PDFObject object)
{
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 = {
std::pair<const char*, Style>{ "Split", Style::Split },

View File

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

View File

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