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
{
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

View File

@ -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<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
{
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:

View File

@ -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"));

View File

@ -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())
{

View File

@ -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);

View File

@ -516,7 +516,7 @@ void PDFViewerMainWindow::onActionTriggered(const pdf::PDFAction* action)
const pdf::PDFActionURI* typedAction = dynamic_cast<const pdf::PDFActionURI*>(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)
{