From 3ac4a1d44584ad92e572641793bd6924becae8ce Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sat, 5 Sep 2020 18:38:46 +0200 Subject: [PATCH] Update actions accordin to PDF 2.0 specification --- PdfForQtLib/sources/pdfaction.cpp | 32 ++++++++++++- PdfForQtLib/sources/pdfaction.h | 66 ++++++++++++++++++++++++-- PdfForQtLib/sources/pdfannotation.cpp | 2 +- PdfForQtLib/sources/pdfcatalog.cpp | 2 +- PdfForQtLib/sources/pdfoutline.cpp | 2 +- PdfForQtViewer/pdfviewermainwindow.cpp | 2 +- 6 files changed, 97 insertions(+), 9 deletions(-) diff --git a/PdfForQtLib/sources/pdfaction.cpp b/PdfForQtLib/sources/pdfaction.cpp index 8a60a11..dd3ffeb 100644 --- a/PdfForQtLib/sources/pdfaction.cpp +++ b/PdfForQtLib/sources/pdfaction.cpp @@ -76,13 +76,15 @@ PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject obj if (name == "GoTo") // Goto action { PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D")); - return PDFActionPtr(new PDFActionGoTo(qMove(destination))); + PDFDestination structureDestination = PDFDestination::parse(storage, dictionary->get("SD")); + return PDFActionPtr(new PDFActionGoTo(qMove(destination), qMove(structureDestination))); } else if (name == "GoToR") { PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D")); + PDFDestination structureDestination = PDFDestination::parse(storage, dictionary->get("SD")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F")); - return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false))); + return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(structureDestination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false))); } else if (name == "GoToE") { @@ -90,6 +92,11 @@ PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject obj 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 == "GoToDp") + { + PDFObjectReference documentPart = loader.readReferenceFromDictionary(dictionary, "Dp"); + return PDFActionPtr(new PDFActionGoToDp(documentPart)); + } else if (name == "Launch") { PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F")); @@ -294,6 +301,22 @@ PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject obj } return PDFActionPtr(new PDFActionJavaScript(PDFEncoding::convertTextString(textJavaScript))); } + else if (name == "RichMediaExecute") + { + PDFObjectReference richMediaAnnotation = loader.readReferenceFromDictionary(dictionary, "TA"); + PDFObjectReference richMediaInstance = loader.readReferenceFromDictionary(dictionary, "TI"); + + QString command; + PDFObject arguments; + + if (const PDFDictionary* commandDictionary = storage->getDictionaryFromObject(dictionary->get("CMD"))) + { + command = loader.readTextStringFromDictionary(commandDictionary, "C", QString()); + arguments = commandDictionary->get("A"); + } + + return PDFActionPtr(new PDFActionRichMediaExecute(richMediaAnnotation, richMediaInstance, qMove(command), qMove(arguments))); + } else if (name == "SubmitForm") { PDFFormAction::FieldScope fieldScope = PDFFormAction::FieldScope::All; @@ -478,4 +501,9 @@ PDFFormAction::FieldList PDFFormAction::parseFieldList(const PDFObjectStorage* s return result; } +QString PDFActionURI::getURIString() const +{ + return QString::fromUtf8(m_URI); +} + } // namespace pdf diff --git a/PdfForQtLib/sources/pdfaction.h b/PdfForQtLib/sources/pdfaction.h index ec75ea3..ebfe8a5 100644 --- a/PdfForQtLib/sources/pdfaction.h +++ b/PdfForQtLib/sources/pdfaction.h @@ -41,6 +41,7 @@ enum class ActionType GoTo, GoToR, GoToE, + GoToDp, Launch, Thread, URI, @@ -55,7 +56,8 @@ enum class ActionType JavaScript, SubmitForm, ResetForm, - ImportDataForm + ImportDataForm, + RichMediaExecute }; enum class DestinationType @@ -146,24 +148,31 @@ private: std::vector m_nextActions; }; +/// Regular go-to action. Can contain also structure destinations, both regular page destination +/// and structure destination are present, because if structure destination fails, then +/// page destination can be used as fallback resolution. class PDFActionGoTo : public PDFAction { public: - explicit inline PDFActionGoTo(PDFDestination destination) : m_destination(qMove(destination)) { } + explicit inline PDFActionGoTo(PDFDestination destination, PDFDestination structureDestination) : + m_destination(qMove(destination)), m_structureDestination(qMove(structureDestination)) { } virtual ActionType getType() const override { return ActionType::GoTo; } const PDFDestination& getDestination() const { return m_destination; } + const PDFDestination& getStructureDestination() const { return m_structureDestination; } private: PDFDestination m_destination; + PDFDestination m_structureDestination; }; class PDFActionGoToR : public PDFAction { public: - explicit inline PDFActionGoToR(PDFDestination destination, PDFFileSpecification fileSpecification, bool newWindow) : + explicit inline PDFActionGoToR(PDFDestination destination, PDFDestination structureDestination, PDFFileSpecification fileSpecification, bool newWindow) : m_destination(qMove(destination)), + m_structureDestination(qMove(structureDestination)), m_fileSpecification(qMove(fileSpecification)), m_newWindow(newWindow) { @@ -173,11 +182,13 @@ public: virtual ActionType getType() const override { return ActionType::GoToR; } const PDFDestination& getDestination() const { return m_destination; } + const PDFDestination& getStructureDestination() const { return m_structureDestination; } const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; } bool isNewWindow() const { return m_newWindow; } private: PDFDestination m_destination; + PDFDestination m_structureDestination; PDFFileSpecification m_fileSpecification; bool m_newWindow = false; }; @@ -208,6 +219,21 @@ private: PDFObject m_target; }; +/// Go to document part +class PDFActionGoToDp : public PDFAction +{ +public: + explicit inline PDFActionGoToDp(PDFObjectReference documentPart) : + m_documentPart(documentPart) { } + + virtual ActionType getType() const override { return ActionType::GoToDp; } + + PDFObjectReference getDocumentPart() const { return m_documentPart; } + +private: + PDFObjectReference m_documentPart; +}; + class PDFActionLaunch : public PDFAction { public: @@ -282,6 +308,10 @@ public: const QByteArray& getURI() const { return m_URI; } bool isMap() const { return m_isMap; } + /// Returns URI as string in unicode. If pdf document conforms + /// to PDF specification, URI is UTF-8 encoded string. + QString getURIString() const; + private: QByteArray m_URI; bool m_isMap; @@ -520,6 +550,36 @@ private: QString m_javaScript; }; +class PDFActionRichMediaExecute : public PDFAction +{ +public: + explicit PDFActionRichMediaExecute(PDFObjectReference richMediaAnnotation, + PDFObjectReference richMediaInstance, + QString command, + PDFObject arguments) : + m_richMediaAnnotation(richMediaAnnotation), + m_richMediaInstance(richMediaInstance), + m_command(qMove(command)), + m_arguments(qMove(arguments)) + { + + } + + virtual ActionType getType() const override { return ActionType::RichMediaExecute; } + + PDFObjectReference getRichMediaAnnotation() const { return m_richMediaAnnotation; } + PDFObjectReference getRichMediaInstance() const { return m_richMediaInstance; } + QString getCommand() const { return m_command; } + PDFObject getArguments() const { return m_arguments; } + +private: + PDFObjectReference m_richMediaAnnotation; + PDFObjectReference m_richMediaInstance; + QString m_command; + PDFObject m_arguments; +}; + + class PDFFormAction : public PDFAction { public: diff --git a/PdfForQtLib/sources/pdfannotation.cpp b/PdfForQtLib/sources/pdfannotation.cpp index c5027f9..0f16006 100644 --- a/PdfForQtLib/sources/pdfannotation.cpp +++ b/PdfForQtLib/sources/pdfannotation.cpp @@ -319,7 +319,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject if (!linkAnnotation->m_action) { PDFDestination destination = PDFDestination::parse(storage, dictionary->get("Dest")); - linkAnnotation->m_action.reset(new PDFActionGoTo(destination)); + linkAnnotation->m_action.reset(new PDFActionGoTo(destination, PDFDestination())); } linkAnnotation->m_previousAction = PDFAction::parse(storage, dictionary->get("PA")); diff --git a/PdfForQtLib/sources/pdfcatalog.cpp b/PdfForQtLib/sources/pdfcatalog.cpp index bd17b43..56810a8 100644 --- a/PdfForQtLib/sources/pdfcatalog.cpp +++ b/PdfForQtLib/sources/pdfcatalog.cpp @@ -198,7 +198,7 @@ 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->getStorage(), openAction))); + catalogObject.m_openAction.reset(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), openAction), PDFDestination())); } if (openAction.isDictionary()) { diff --git a/PdfForQtLib/sources/pdfoutline.cpp b/PdfForQtLib/sources/pdfoutline.cpp index dc8f751..9758e62 100644 --- a/PdfForQtLib/sources/pdfoutline.cpp +++ b/PdfForQtLib/sources/pdfoutline.cpp @@ -73,7 +73,7 @@ void PDFOutlineItem::parseImpl(const PDFDocument* document, currentOutlineItem->setAction(PDFAction::parse(&document->getStorage(), dictionary->get("A"))); if (!currentOutlineItem->getAction() && dictionary->hasKey("Dest")) { - currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), dictionary->get("Dest"))))); + currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), dictionary->get("Dest")), PDFDestination()))); } PDFDocumentDataLoaderDecorator loader(document); diff --git a/PdfForQtViewer/pdfviewermainwindow.cpp b/PdfForQtViewer/pdfviewermainwindow.cpp index 36079c9..6f63ef9 100644 --- a/PdfForQtViewer/pdfviewermainwindow.cpp +++ b/PdfForQtViewer/pdfviewermainwindow.cpp @@ -516,7 +516,7 @@ void PDFViewerMainWindow::onActionTriggered(const pdf::PDFAction* action) const pdf::PDFActionURI* typedAction = dynamic_cast(currentAction); QByteArray URI = m_pdfDocument->getCatalog()->getBaseURI() + typedAction->getURI(); - QString urlString = QString::fromLatin1(URI); + QString urlString = QString::fromUtf8(URI); QString message = tr("Would you like to open URL '%1'?").arg(urlString); if (QMessageBox::question(this, tr("Open URL"), message) == QMessageBox::Yes) {