Update actions accordin to PDF 2.0 specification

This commit is contained in:
Jakub Melka
2020-09-05 18:38:46 +02:00
parent 784525d4cd
commit 3ac4a1d445
6 changed files with 97 additions and 9 deletions

View File

@ -76,13 +76,15 @@ PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject obj
if (name == "GoTo") // Goto action if (name == "GoTo") // Goto action
{ {
PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D")); 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") else if (name == "GoToR")
{ {
PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("D"));
PDFDestination structureDestination = PDFDestination::parse(storage, dictionary->get("SD"));
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F")); PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F"));
return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false))); return PDFActionPtr(new PDFActionGoToR(qMove(destination), qMove(structureDestination), qMove(fileSpecification), loader.readBooleanFromDictionary(dictionary, "NewWindow", false)));
} }
else if (name == "GoToE") else if (name == "GoToE")
{ {
@ -90,6 +92,11 @@ PDFActionPtr PDFAction::parseImpl(const PDFObjectStorage* storage, PDFObject obj
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F")); 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")))); 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") else if (name == "Launch")
{ {
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("F")); 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))); 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") else if (name == "SubmitForm")
{ {
PDFFormAction::FieldScope fieldScope = PDFFormAction::FieldScope::All; PDFFormAction::FieldScope fieldScope = PDFFormAction::FieldScope::All;
@ -478,4 +501,9 @@ PDFFormAction::FieldList PDFFormAction::parseFieldList(const PDFObjectStorage* s
return result; return result;
} }
QString PDFActionURI::getURIString() const
{
return QString::fromUtf8(m_URI);
}
} // namespace pdf } // namespace pdf

View File

@ -41,6 +41,7 @@ enum class ActionType
GoTo, GoTo,
GoToR, GoToR,
GoToE, GoToE,
GoToDp,
Launch, Launch,
Thread, Thread,
URI, URI,
@ -55,7 +56,8 @@ enum class ActionType
JavaScript, JavaScript,
SubmitForm, SubmitForm,
ResetForm, ResetForm,
ImportDataForm ImportDataForm,
RichMediaExecute
}; };
enum class DestinationType enum class DestinationType
@ -146,24 +148,31 @@ private:
std::vector<PDFActionPtr> m_nextActions; std::vector<PDFActionPtr> 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 class PDFActionGoTo : public PDFAction
{ {
public: 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; } virtual ActionType getType() const override { return ActionType::GoTo; }
const PDFDestination& getDestination() const { return m_destination; } const PDFDestination& getDestination() const { return m_destination; }
const PDFDestination& getStructureDestination() const { return m_structureDestination; }
private: private:
PDFDestination m_destination; PDFDestination m_destination;
PDFDestination m_structureDestination;
}; };
class PDFActionGoToR : public PDFAction class PDFActionGoToR : public PDFAction
{ {
public: 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_destination(qMove(destination)),
m_structureDestination(qMove(structureDestination)),
m_fileSpecification(qMove(fileSpecification)), m_fileSpecification(qMove(fileSpecification)),
m_newWindow(newWindow) m_newWindow(newWindow)
{ {
@ -173,11 +182,13 @@ public:
virtual ActionType getType() const override { return ActionType::GoToR; } virtual ActionType getType() const override { return ActionType::GoToR; }
const PDFDestination& getDestination() const { return m_destination; } const PDFDestination& getDestination() const { return m_destination; }
const PDFDestination& getStructureDestination() const { return m_structureDestination; }
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; } const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
bool isNewWindow() const { return m_newWindow; } bool isNewWindow() const { return m_newWindow; }
private: private:
PDFDestination m_destination; PDFDestination m_destination;
PDFDestination m_structureDestination;
PDFFileSpecification m_fileSpecification; PDFFileSpecification m_fileSpecification;
bool m_newWindow = false; bool m_newWindow = false;
}; };
@ -208,6 +219,21 @@ private:
PDFObject m_target; 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 class PDFActionLaunch : public PDFAction
{ {
public: public:
@ -282,6 +308,10 @@ public:
const QByteArray& getURI() const { return m_URI; } const QByteArray& getURI() const { return m_URI; }
bool isMap() const { return m_isMap; } 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: private:
QByteArray m_URI; QByteArray m_URI;
bool m_isMap; bool m_isMap;
@ -520,6 +550,36 @@ private:
QString m_javaScript; 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 class PDFFormAction : public PDFAction
{ {
public: public:

View File

@ -319,7 +319,7 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject
if (!linkAnnotation->m_action) if (!linkAnnotation->m_action)
{ {
PDFDestination destination = PDFDestination::parse(storage, dictionary->get("Dest")); PDFDestination destination = PDFDestination::parse(storage, dictionary->get("Dest"));
linkAnnotation->m_action.reset(new PDFActionGoTo(destination)); linkAnnotation->m_action.reset(new PDFActionGoTo(destination, PDFDestination()));
} }
linkAnnotation->m_previousAction = PDFAction::parse(storage, dictionary->get("PA")); linkAnnotation->m_previousAction = PDFAction::parse(storage, dictionary->get("PA"));

View File

@ -198,7 +198,7 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
PDFObject openAction = document->getObject(catalogDictionary->get("OpenAction")); PDFObject openAction = document->getObject(catalogDictionary->get("OpenAction"));
if (openAction.isArray()) if (openAction.isArray())
{ {
catalogObject.m_openAction.reset(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), openAction))); catalogObject.m_openAction.reset(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), openAction), PDFDestination()));
} }
if (openAction.isDictionary()) if (openAction.isDictionary())
{ {

View File

@ -73,7 +73,7 @@ void PDFOutlineItem::parseImpl(const PDFDocument* document,
currentOutlineItem->setAction(PDFAction::parse(&document->getStorage(), dictionary->get("A"))); currentOutlineItem->setAction(PDFAction::parse(&document->getStorage(), dictionary->get("A")));
if (!currentOutlineItem->getAction() && dictionary->hasKey("Dest")) if (!currentOutlineItem->getAction() && dictionary->hasKey("Dest"))
{ {
currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), dictionary->get("Dest"))))); currentOutlineItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::parse(&document->getStorage(), dictionary->get("Dest")), PDFDestination())));
} }
PDFDocumentDataLoaderDecorator loader(document); PDFDocumentDataLoaderDecorator loader(document);

View File

@ -516,7 +516,7 @@ void PDFViewerMainWindow::onActionTriggered(const pdf::PDFAction* action)
const pdf::PDFActionURI* typedAction = dynamic_cast<const pdf::PDFActionURI*>(currentAction); const pdf::PDFActionURI* typedAction = dynamic_cast<const pdf::PDFActionURI*>(currentAction);
QByteArray URI = m_pdfDocument->getCatalog()->getBaseURI() + typedAction->getURI(); 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); QString message = tr("Would you like to open URL '%1'?").arg(urlString);
if (QMessageBox::question(this, tr("Open URL"), message) == QMessageBox::Yes) if (QMessageBox::question(this, tr("Open URL"), message) == QMessageBox::Yes)
{ {