mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-05-06 21:08:57 +02:00
Actions/outline basics
This commit is contained in:
parent
84d9b58476
commit
2a11fa18e0
@ -36,12 +36,15 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||||||
DESTDIR = $$OUT_PWD/..
|
DESTDIR = $$OUT_PWD/..
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
sources/pdfaction.cpp \
|
||||||
sources/pdfblendfunction.cpp \
|
sources/pdfblendfunction.cpp \
|
||||||
sources/pdfccittfaxdecoder.cpp \
|
sources/pdfccittfaxdecoder.cpp \
|
||||||
|
sources/pdffile.cpp \
|
||||||
sources/pdfitemmodels.cpp \
|
sources/pdfitemmodels.cpp \
|
||||||
sources/pdfjbig2decoder.cpp \
|
sources/pdfjbig2decoder.cpp \
|
||||||
sources/pdfobject.cpp \
|
sources/pdfobject.cpp \
|
||||||
sources/pdfoptionalcontent.cpp \
|
sources/pdfoptionalcontent.cpp \
|
||||||
|
sources/pdfoutline.cpp \
|
||||||
sources/pdfparser.cpp \
|
sources/pdfparser.cpp \
|
||||||
sources/pdfdocument.cpp \
|
sources/pdfdocument.cpp \
|
||||||
sources/pdfdocumentreader.cpp \
|
sources/pdfdocumentreader.cpp \
|
||||||
@ -68,13 +71,16 @@ SOURCES += \
|
|||||||
sources/pdfimage.cpp
|
sources/pdfimage.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
sources/pdfaction.h \
|
||||||
sources/pdfblendfunction.h \
|
sources/pdfblendfunction.h \
|
||||||
sources/pdfccittfaxdecoder.h \
|
sources/pdfccittfaxdecoder.h \
|
||||||
|
sources/pdffile.h \
|
||||||
sources/pdfitemmodels.h \
|
sources/pdfitemmodels.h \
|
||||||
sources/pdfjbig2decoder.h \
|
sources/pdfjbig2decoder.h \
|
||||||
sources/pdfmeshqualitysettings.h \
|
sources/pdfmeshqualitysettings.h \
|
||||||
sources/pdfobject.h \
|
sources/pdfobject.h \
|
||||||
sources/pdfoptionalcontent.h \
|
sources/pdfoptionalcontent.h \
|
||||||
|
sources/pdfoutline.h \
|
||||||
sources/pdfparser.h \
|
sources/pdfparser.h \
|
||||||
sources/pdfglobal.h \
|
sources/pdfglobal.h \
|
||||||
sources/pdfconstants.h \
|
sources/pdfconstants.h \
|
||||||
|
243
PdfForQtLib/sources/pdfaction.cpp
Normal file
243
PdfForQtLib/sources/pdfaction.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfaction.h"
|
||||||
|
#include "pdfdocument.h"
|
||||||
|
#include "pdfexception.h"
|
||||||
|
#include "pdfencoding.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFActionPtr PDFAction::parse(const PDFDocument* document, PDFObject object)
|
||||||
|
{
|
||||||
|
std::set<PDFObjectReference> usedReferences;
|
||||||
|
return parseImpl(document, qMove(object), usedReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFAction::apply(const std::function<void (const PDFAction*)>& callback)
|
||||||
|
{
|
||||||
|
callback(this);
|
||||||
|
|
||||||
|
for (const PDFActionPtr& nextAction : m_nextActions)
|
||||||
|
{
|
||||||
|
nextAction->apply(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFActionPtr PDFAction::parseImpl(const PDFDocument* document, PDFObject object, std::set<PDFObjectReference>& usedReferences)
|
||||||
|
{
|
||||||
|
if (object.isReference())
|
||||||
|
{
|
||||||
|
PDFObjectReference reference = object.getReference();
|
||||||
|
if (usedReferences.count(reference))
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Circular dependence in actions found."));
|
||||||
|
}
|
||||||
|
usedReferences.insert(reference);
|
||||||
|
object = document->getObjectByReference(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.isNull())
|
||||||
|
{
|
||||||
|
return PDFActionPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!object.isDictionary())
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Invalid action."));
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDocumentDataLoaderDecorator loader(document);
|
||||||
|
const PDFDictionary* dictionary = object.getDictionary();
|
||||||
|
QByteArray name = loader.readNameFromDictionary(dictionary, "S");
|
||||||
|
|
||||||
|
if (name == "GoTo") // Goto action
|
||||||
|
{
|
||||||
|
PDFDestination destination = PDFDestination::parse(document, 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"));
|
||||||
|
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"))));
|
||||||
|
}
|
||||||
|
else if (name == "Launch")
|
||||||
|
{
|
||||||
|
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
|
||||||
|
const bool newWindow = loader.readBooleanFromDictionary(dictionary, "NewWindow", false);
|
||||||
|
PDFActionLaunch::Win win;
|
||||||
|
|
||||||
|
const PDFObject& winDictionaryObject = document->getObject(dictionary->get("Win"));
|
||||||
|
if (winDictionaryObject.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* winDictionary = winDictionaryObject.getDictionary();
|
||||||
|
win.file = loader.readStringFromDictionary(winDictionary, "F");
|
||||||
|
win.directory = loader.readStringFromDictionary(winDictionary, "D");
|
||||||
|
win.operation = loader.readStringFromDictionary(winDictionary, "O");
|
||||||
|
win.parameters = loader.readStringFromDictionary(winDictionary, "P");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PDFActionPtr(new PDFActionLaunch(qMove(fileSpecification), newWindow, qMove(win)));
|
||||||
|
}
|
||||||
|
else if (name == "Thread")
|
||||||
|
{
|
||||||
|
PDFFileSpecification fileSpecification = PDFFileSpecification::parse(document, dictionary->get("F"));
|
||||||
|
PDFActionThread::Thread thread;
|
||||||
|
PDFActionThread::Bead bead;
|
||||||
|
|
||||||
|
const PDFObject& threadObject = dictionary->get("D");
|
||||||
|
if (threadObject.isReference())
|
||||||
|
{
|
||||||
|
thread = threadObject.getReference();
|
||||||
|
}
|
||||||
|
else if (threadObject.isInt())
|
||||||
|
{
|
||||||
|
thread = threadObject.getInteger();
|
||||||
|
}
|
||||||
|
else if (threadObject.isString())
|
||||||
|
{
|
||||||
|
thread = PDFEncoding::convertTextString(threadObject.getString());
|
||||||
|
}
|
||||||
|
const PDFObject& beadObject = dictionary->get("B");
|
||||||
|
if (beadObject.isReference())
|
||||||
|
{
|
||||||
|
bead = beadObject.getReference();
|
||||||
|
}
|
||||||
|
else if (beadObject.isInt())
|
||||||
|
{
|
||||||
|
bead = beadObject.getInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PDFActionPtr(new PDFActionThread(qMove(fileSpecification), qMove(thread), qMove(bead)));
|
||||||
|
}
|
||||||
|
else if (name == "URI")
|
||||||
|
{
|
||||||
|
return PDFActionPtr(new PDFActionURI(loader.readStringFromDictionary(dictionary, "URI"), loader.readBooleanFromDictionary(dictionary, "IsMap", false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return PDFActionPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDestination PDFDestination::parse(const PDFDocument* document, PDFObject object)
|
||||||
|
{
|
||||||
|
PDFDestination result;
|
||||||
|
object = document->getObject(object);
|
||||||
|
|
||||||
|
if (object.isName() || object.isString())
|
||||||
|
{
|
||||||
|
QByteArray name = object.getString();
|
||||||
|
result.m_destinationType = DestinationType::Named;
|
||||||
|
result.m_name = name;
|
||||||
|
}
|
||||||
|
else if (object.isArray())
|
||||||
|
{
|
||||||
|
const PDFArray* array = object.getArray();
|
||||||
|
if (array->getCount() < 2)
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Invalid destination - array has invalid size."));
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDocumentDataLoaderDecorator loader(document);
|
||||||
|
|
||||||
|
// First parse page number/page index
|
||||||
|
PDFObject pageNumberObject = array->getItem(0);
|
||||||
|
if (pageNumberObject.isReference())
|
||||||
|
{
|
||||||
|
result.m_pageReference = pageNumberObject.getReference();
|
||||||
|
}
|
||||||
|
else if (pageNumberObject.isInt())
|
||||||
|
{
|
||||||
|
result.m_pageIndex = pageNumberObject.getInteger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Invalid destination - invalid page reference."));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray name = loader.readName(array->getItem(1));
|
||||||
|
|
||||||
|
size_t currentIndex = 2;
|
||||||
|
auto readNumber = [&]()
|
||||||
|
{
|
||||||
|
if (currentIndex >= array->getCount())
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Invalid destination - array has invalid size."));
|
||||||
|
}
|
||||||
|
return loader.readNumber(array->getItem(currentIndex++), 0.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (name == "XYZ")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::XYZ;
|
||||||
|
result.m_left = readNumber();
|
||||||
|
result.m_top = readNumber();
|
||||||
|
result.m_zoom = readNumber();
|
||||||
|
}
|
||||||
|
else if (name == "Fit")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::Fit;
|
||||||
|
}
|
||||||
|
else if (name == "FitH")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitH;
|
||||||
|
result.m_top = readNumber();
|
||||||
|
}
|
||||||
|
else if (name == "FitV")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitV;
|
||||||
|
result.m_left = readNumber();
|
||||||
|
}
|
||||||
|
else if (name == "FitR")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitR;
|
||||||
|
result.m_left = readNumber();
|
||||||
|
result.m_bottom = readNumber();
|
||||||
|
result.m_right = readNumber();
|
||||||
|
result.m_top = readNumber();
|
||||||
|
}
|
||||||
|
else if (name == "FitB")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitB;
|
||||||
|
}
|
||||||
|
else if (name == "FitBH")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitBH;
|
||||||
|
result.m_top = readNumber();
|
||||||
|
}
|
||||||
|
else if (name == "FitBV")
|
||||||
|
{
|
||||||
|
result.m_destinationType = DestinationType::FitBV;
|
||||||
|
result.m_left = readNumber();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Invalid destination - unknown type."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
269
PdfForQtLib/sources/pdfaction.h
Normal file
269
PdfForQtLib/sources/pdfaction.h
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFACTION_H
|
||||||
|
#define PDFACTION_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
#include "pdfobject.h"
|
||||||
|
#include "pdffile.h"
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <variant>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFAction;
|
||||||
|
class PDFDocument;
|
||||||
|
|
||||||
|
enum class ActionType
|
||||||
|
{
|
||||||
|
GoTo,
|
||||||
|
GoToR,
|
||||||
|
GoToE,
|
||||||
|
Launch,
|
||||||
|
Thread,
|
||||||
|
URI
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DestinationType
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Named,
|
||||||
|
XYZ,
|
||||||
|
Fit,
|
||||||
|
FitH,
|
||||||
|
FitV,
|
||||||
|
FitR,
|
||||||
|
FitB,
|
||||||
|
FitBH,
|
||||||
|
FitBV
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Destination to the specific location of the document. Destination can also be 'Named' type,
|
||||||
|
/// in this case, destination in name tree is found and used.
|
||||||
|
class PDFDestination
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFDestination() = default;
|
||||||
|
|
||||||
|
DestinationType getDestinationType() const { return m_destinationType; }
|
||||||
|
PDFReal getLeft() const { return m_left; }
|
||||||
|
PDFReal getTop() const { return m_top; }
|
||||||
|
PDFReal getRight() const { return m_right; }
|
||||||
|
PDFReal getBottom() const { return m_bottom; }
|
||||||
|
PDFReal getZoom() const { return m_zoom; }
|
||||||
|
const QByteArray& getName() const { return m_name; }
|
||||||
|
PDFObjectReference getPageReference() const { return m_pageReference; }
|
||||||
|
PDFInteger getPageIndex() const { return m_pageIndex; }
|
||||||
|
|
||||||
|
/// Parses the destination from the object. If object contains invalid destination,
|
||||||
|
/// then exception is thrown. If object is empty, empty destination is returned.
|
||||||
|
/// \param document Document
|
||||||
|
/// \param object Destination object
|
||||||
|
static PDFDestination parse(const PDFDocument* document, PDFObject object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DestinationType m_destinationType = DestinationType::Invalid;
|
||||||
|
PDFReal m_left = 0.0;
|
||||||
|
PDFReal m_top = 0.0;
|
||||||
|
PDFReal m_right = 0.0;
|
||||||
|
PDFReal m_bottom = 0.0;
|
||||||
|
PDFReal m_zoom = 0.0;
|
||||||
|
QByteArray m_name;
|
||||||
|
PDFObjectReference m_pageReference;
|
||||||
|
PDFInteger m_pageIndex = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PDFActionPtr = QSharedPointer<PDFAction>;
|
||||||
|
|
||||||
|
/// Base class for action types.
|
||||||
|
class PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFAction() = default;
|
||||||
|
virtual ~PDFAction() = default;
|
||||||
|
|
||||||
|
/// Returns type of the action.
|
||||||
|
virtual ActionType getType() const = 0;
|
||||||
|
|
||||||
|
/// Returns container with next actions
|
||||||
|
const std::vector<PDFActionPtr>& getNextActions() const { return m_nextActions; }
|
||||||
|
|
||||||
|
/// 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 object Object containing the action
|
||||||
|
static PDFActionPtr parse(const PDFDocument* document, PDFObject object);
|
||||||
|
|
||||||
|
/// Calls the lambda function with action as parameter, then following
|
||||||
|
/// the 'Next' entry, as described by PDF 1.7 specification.
|
||||||
|
void apply(const std::function<void(const PDFAction* action)>& callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PDFActionPtr parseImpl(const PDFDocument* document, PDFObject object, std::set<PDFObjectReference>& usedReferences);
|
||||||
|
|
||||||
|
std::vector<PDFActionPtr> m_nextActions;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionGoTo : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFActionGoTo(PDFDestination destination) : m_destination(qMove(destination)) { }
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::GoTo; }
|
||||||
|
|
||||||
|
const PDFDestination& getDestination() const { return m_destination; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFDestination m_destination;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionGoToR : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFActionGoToR(PDFDestination destination, PDFFileSpecification fileSpecification, bool newWindow) :
|
||||||
|
m_destination(qMove(destination)),
|
||||||
|
m_fileSpecification(qMove(fileSpecification)),
|
||||||
|
m_newWindow(newWindow)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::GoToR; }
|
||||||
|
|
||||||
|
const PDFDestination& getDestination() const { return m_destination; }
|
||||||
|
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
|
||||||
|
bool isNewWindow() const { return m_newWindow; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFDestination m_destination;
|
||||||
|
PDFFileSpecification m_fileSpecification;
|
||||||
|
bool m_newWindow = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionGoToE : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFActionGoToE(PDFDestination destination, PDFFileSpecification fileSpecification, bool newWindow, const PDFObject& target) :
|
||||||
|
m_destination(qMove(destination)),
|
||||||
|
m_fileSpecification(qMove(fileSpecification)),
|
||||||
|
m_newWindow(newWindow),
|
||||||
|
m_target(target)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::GoToE; }
|
||||||
|
|
||||||
|
const PDFDestination& getDestination() const { return m_destination; }
|
||||||
|
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
|
||||||
|
bool isNewWindow() const { return m_newWindow; }
|
||||||
|
const PDFObject& getTarget() const { return m_target; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFDestination m_destination;
|
||||||
|
PDFFileSpecification m_fileSpecification;
|
||||||
|
bool m_newWindow = false;
|
||||||
|
PDFObject m_target;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionLaunch : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Specification of launched application (if not file specification is attached)
|
||||||
|
struct Win
|
||||||
|
{
|
||||||
|
QByteArray file;
|
||||||
|
QByteArray directory;
|
||||||
|
QByteArray operation;
|
||||||
|
QByteArray parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit inline PDFActionLaunch(PDFFileSpecification fileSpecification, bool newWindow, Win win) :
|
||||||
|
m_fileSpecification(qMove(fileSpecification)),
|
||||||
|
m_newWindow(newWindow),
|
||||||
|
m_win(qMove(win))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::Launch; }
|
||||||
|
|
||||||
|
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
|
||||||
|
const Win& getWinSpecification() const { return m_win; }
|
||||||
|
bool isNewWindow() const { return m_newWindow; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFFileSpecification m_fileSpecification;
|
||||||
|
bool m_newWindow = false;
|
||||||
|
Win m_win;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionThread : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Thread = std::variant<typename std::monostate, PDFObjectReference, PDFInteger, QString>;
|
||||||
|
using Bead = std::variant<typename std::monostate, PDFObjectReference, PDFInteger>;
|
||||||
|
|
||||||
|
explicit inline PDFActionThread(PDFFileSpecification fileSpecification, Thread thread, Bead bead) :
|
||||||
|
m_fileSpecification(qMove(fileSpecification)),
|
||||||
|
m_thread(qMove(thread)),
|
||||||
|
m_bead(qMove(bead))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::Thread; }
|
||||||
|
|
||||||
|
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
|
||||||
|
const Thread& getThread() const { return m_thread; }
|
||||||
|
const Bead& getBead() const { return m_bead; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFFileSpecification m_fileSpecification;
|
||||||
|
Thread m_thread;
|
||||||
|
Bead m_bead;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFActionURI : public PDFAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFActionURI(QByteArray URI, bool isMap) :
|
||||||
|
m_URI(qMove(URI)),
|
||||||
|
m_isMap(isMap)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ActionType getType() const override { return ActionType::URI; }
|
||||||
|
|
||||||
|
const QByteArray& getURI() const { return m_URI; }
|
||||||
|
bool isMap() const { return m_isMap; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_URI;
|
||||||
|
bool m_isMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFACTION_H
|
@ -62,6 +62,11 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
|
|||||||
catalogObject.m_optionalContentProperties = PDFOptionalContentProperties::create(document, catalogDictionary->get("OCProperties"));
|
catalogObject.m_optionalContentProperties = PDFOptionalContentProperties::create(document, catalogDictionary->get("OCProperties"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (catalogDictionary->hasKey("Outlines"))
|
||||||
|
{
|
||||||
|
catalogObject.m_outlineRoot = PDFOutlineItem::parse(document, catalogDictionary->get("Outlines"));
|
||||||
|
}
|
||||||
|
|
||||||
return catalogObject;
|
return catalogObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "pdfobject.h"
|
#include "pdfobject.h"
|
||||||
#include "pdfpage.h"
|
#include "pdfpage.h"
|
||||||
#include "pdfoptionalcontent.h"
|
#include "pdfoptionalcontent.h"
|
||||||
|
#include "pdfoutline.h"
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
|
|
||||||
@ -224,6 +225,7 @@ private:
|
|||||||
std::vector<PDFPage> m_pages;
|
std::vector<PDFPage> m_pages;
|
||||||
std::vector<PDFPageLabel> m_pageLabels;
|
std::vector<PDFPageLabel> m_pageLabels;
|
||||||
PDFOptionalContentProperties m_optionalContentProperties;
|
PDFOptionalContentProperties m_optionalContentProperties;
|
||||||
|
QSharedPointer<PDFOutlineItem> m_outlineRoot;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -326,6 +326,10 @@ public:
|
|||||||
/// is returned (no exception is thrown).
|
/// is returned (no exception is thrown).
|
||||||
const PDFObject& getObject(const PDFObject& object) const;
|
const PDFObject& getObject(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 the document catalog
|
/// Returns the document catalog
|
||||||
const PDFCatalog* getCatalog() const { return &m_catalog; }
|
const PDFCatalog* getCatalog() const { return &m_catalog; }
|
||||||
|
|
||||||
@ -379,6 +383,12 @@ const PDFObject& PDFDocument::getObject(const PDFObject& object) const
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
const PDFObject& PDFDocument::getObjectByReference(PDFObjectReference reference) const
|
||||||
|
{
|
||||||
|
return m_pdfObjectStorage.getObject(reference);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFDOCUMENT_H
|
#endif // PDFDOCUMENT_H
|
||||||
|
183
PdfForQtLib/sources/pdffile.cpp
Normal file
183
PdfForQtLib/sources/pdffile.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdffile.h"
|
||||||
|
#include "pdfdocument.h"
|
||||||
|
#include "pdfencoding.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
QString PDFFileSpecification::getPlatformFileName() const
|
||||||
|
{
|
||||||
|
// UF has maximal precedence, because it is unicode string
|
||||||
|
if (!m_UF.isEmpty())
|
||||||
|
{
|
||||||
|
return m_UF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_F.isEmpty())
|
||||||
|
{
|
||||||
|
return QString::fromLatin1(m_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
for (const QByteArray& platformName : { m_DOS, m_Mac, m_Unix })
|
||||||
|
{
|
||||||
|
if (!platformName.isEmpty())
|
||||||
|
{
|
||||||
|
return QString::fromLatin1(platformName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
for (const QByteArray& platformName : { m_Unix, m_Mac, m_DOS })
|
||||||
|
{
|
||||||
|
if (!platformName.isEmpty())
|
||||||
|
{
|
||||||
|
return QString::fromLatin1(platformName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
for (const QByteArray& platformName : { m_Mac, m_Unix, m_DOS })
|
||||||
|
{
|
||||||
|
if (!platformName.isEmpty())
|
||||||
|
{
|
||||||
|
return QString::fromLatin1(platformName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFEmbeddedFile* PDFFileSpecification::getPlatformFile() const
|
||||||
|
{
|
||||||
|
if (m_embeddedFiles.count("UF"))
|
||||||
|
{
|
||||||
|
return &m_embeddedFiles.at("UF");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_embeddedFiles.count("F"))
|
||||||
|
{
|
||||||
|
return &m_embeddedFiles.at("F");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (m_embeddedFiles.count("DOS"))
|
||||||
|
{
|
||||||
|
return &m_embeddedFiles.at("DOS");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
if (m_embeddedFiles.count("Unix"))
|
||||||
|
{
|
||||||
|
return &m_embeddedFiles.at("Unix");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
if (m_embeddedFiles.count("Mac"))
|
||||||
|
{
|
||||||
|
return &m_embeddedFiles.at("Mac");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFFileSpecification PDFFileSpecification::parse(const PDFDocument* document, PDFObject object)
|
||||||
|
{
|
||||||
|
PDFFileSpecification result;
|
||||||
|
object = document->getObject(object);
|
||||||
|
|
||||||
|
if (object.isString())
|
||||||
|
{
|
||||||
|
result.m_UF = PDFEncoding::convertTextString(object.getString());
|
||||||
|
}
|
||||||
|
else if (object.isDictionary())
|
||||||
|
{
|
||||||
|
PDFDocumentDataLoaderDecorator loader(document);
|
||||||
|
const PDFDictionary* dictionary = object.getDictionary();
|
||||||
|
PDFObject collectionObject = dictionary->get("Cl");
|
||||||
|
|
||||||
|
result.m_fileSystem = loader.readNameFromDictionary(dictionary, "FS");
|
||||||
|
result.m_F = loader.readStringFromDictionary(dictionary, "F");
|
||||||
|
result.m_UF = loader.readTextStringFromDictionary(dictionary, "UF", QString());
|
||||||
|
result.m_DOS = loader.readStringFromDictionary(dictionary, "DOS");
|
||||||
|
result.m_Mac = loader.readStringFromDictionary(dictionary, "Mac");
|
||||||
|
result.m_Unix = loader.readStringFromDictionary(dictionary, "Unix");
|
||||||
|
result.m_volatile = loader.readBooleanFromDictionary(dictionary, "V", false);
|
||||||
|
result.m_description = loader.readTextStringFromDictionary(dictionary, "Desc", QString());
|
||||||
|
result.m_collection = collectionObject.isReference() ? collectionObject.getReference() : PDFObjectReference();
|
||||||
|
|
||||||
|
PDFObject embeddedFiles = document->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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFEmbeddedFile PDFEmbeddedFile::parse(const PDFDocument* document, PDFObject object)
|
||||||
|
{
|
||||||
|
PDFEmbeddedFile result;
|
||||||
|
object = document->getObject(object);
|
||||||
|
|
||||||
|
if (object.isStream())
|
||||||
|
{
|
||||||
|
const PDFStream* stream = object.getStream();
|
||||||
|
const PDFDictionary* dictionary = stream->getDictionary();
|
||||||
|
PDFDocumentDataLoaderDecorator loader(document);
|
||||||
|
result.m_stream = object;
|
||||||
|
result.m_subtype = loader.readNameFromDictionary(dictionary, "Subtype");
|
||||||
|
|
||||||
|
const PDFObject& paramsObject = document->getObject(dictionary->get("Params"));
|
||||||
|
if (paramsObject.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* paramsDictionary = paramsObject.getDictionary();
|
||||||
|
auto getDateTime = [&loader, paramsDictionary](const char* name)
|
||||||
|
{
|
||||||
|
QByteArray ba = loader.readStringFromDictionary(paramsDictionary, name);
|
||||||
|
if (!ba.isEmpty())
|
||||||
|
{
|
||||||
|
return PDFEncoding::convertToDateTime(ba);
|
||||||
|
}
|
||||||
|
return QDateTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
result.m_size = loader.readIntegerFromDictionary(paramsDictionary, "Size", -1);
|
||||||
|
result.m_creationDate = getDateTime("CreationDate");
|
||||||
|
result.m_modifiedDate = getDateTime("ModDate");
|
||||||
|
result.m_checksum = loader.readStringFromDictionary(paramsDictionary, "CheckSum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
106
PdfForQtLib/sources/pdffile.h
Normal file
106
PdfForQtLib/sources/pdffile.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFFILE_H
|
||||||
|
#define PDFFILE_H
|
||||||
|
|
||||||
|
#include "pdfobject.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFDocument;
|
||||||
|
|
||||||
|
class PDFEmbeddedFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFEmbeddedFile() = default;
|
||||||
|
|
||||||
|
bool isValid() const { return m_stream.isStream(); }
|
||||||
|
|
||||||
|
static PDFEmbeddedFile parse(const PDFDocument* document, PDFObject object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFObject m_stream;
|
||||||
|
QByteArray m_subtype;
|
||||||
|
PDFInteger m_size = -1;
|
||||||
|
QDateTime m_creationDate;
|
||||||
|
QDateTime m_modifiedDate;
|
||||||
|
QByteArray m_checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// File specification
|
||||||
|
class PDFFileSpecification
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFFileSpecification() = default;
|
||||||
|
|
||||||
|
/// Returns platform file name as string. It looks into the UF, F,
|
||||||
|
/// and platform names and selects the appropriate one. If error
|
||||||
|
/// occurs. then empty string is returned.
|
||||||
|
QString getPlatformFileName() const;
|
||||||
|
|
||||||
|
/// Returns platform file.
|
||||||
|
const PDFEmbeddedFile* getPlatformFile() const;
|
||||||
|
|
||||||
|
const QByteArray& getFileSystem() const { return m_fileSystem; }
|
||||||
|
const QByteArray& getF() const { return m_F; }
|
||||||
|
const QString& getUF() const { return m_UF; }
|
||||||
|
const QByteArray& getDOS() const { return m_DOS; }
|
||||||
|
const QByteArray& getMac() const { return m_Mac; }
|
||||||
|
const QByteArray& getUnix() const { return m_Unix; }
|
||||||
|
bool isVolatile() const { return m_volatile; }
|
||||||
|
const QString& getDescription() const { return m_description; }
|
||||||
|
PDFObjectReference getCollection() const { return m_collection; }
|
||||||
|
const std::map<QByteArray, PDFEmbeddedFile>& getEmbeddedFiles() const { return m_embeddedFiles; }
|
||||||
|
|
||||||
|
static PDFFileSpecification parse(const PDFDocument* document, PDFObject object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Name of the file system used to interpret this file specification,
|
||||||
|
/// usually, it is URL (this is only file system defined in PDF specification 1.7).
|
||||||
|
QByteArray m_fileSystem;
|
||||||
|
|
||||||
|
/// File specification string (for backward compatibility). If file system is URL,
|
||||||
|
/// it contains unified resource locator.
|
||||||
|
QByteArray m_F;
|
||||||
|
|
||||||
|
/// File specification string as unicode.
|
||||||
|
QString m_UF;
|
||||||
|
|
||||||
|
QByteArray m_DOS;
|
||||||
|
QByteArray m_Mac;
|
||||||
|
QByteArray m_Unix;
|
||||||
|
|
||||||
|
/// Is file volatile? I.e it is, for example, link to a video file from online camera?
|
||||||
|
/// If this boolean is true, then file should never be cached.
|
||||||
|
bool m_volatile = false;
|
||||||
|
|
||||||
|
/// Description of the file (for example, if file is embedded file stream)
|
||||||
|
QString m_description;
|
||||||
|
|
||||||
|
/// Collection item dictionary reference
|
||||||
|
PDFObjectReference m_collection;
|
||||||
|
|
||||||
|
/// Embedded files
|
||||||
|
std::map<QByteArray, PDFEmbeddedFile> m_embeddedFiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFFILE_H
|
110
PdfForQtLib/sources/pdfoutline.cpp
Normal file
110
PdfForQtLib/sources/pdfoutline.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfoutline.h"
|
||||||
|
#include "pdfdocument.h"
|
||||||
|
#include "pdfexception.h"
|
||||||
|
#include "pdfencoding.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
QSharedPointer<PDFOutlineItem> PDFOutlineItem::parse(const PDFDocument* document, const PDFObject& root)
|
||||||
|
{
|
||||||
|
const PDFObject& rootDereferenced = document->getObject(root);
|
||||||
|
if (rootDereferenced.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* dictionary = rootDereferenced.getDictionary();
|
||||||
|
const PDFObject& first = dictionary->get("First");
|
||||||
|
|
||||||
|
if (first.isReference())
|
||||||
|
{
|
||||||
|
QSharedPointer<PDFOutlineItem> result(new PDFOutlineItem());
|
||||||
|
std::set<PDFObjectReference> visitedOutlineItems;
|
||||||
|
parseImpl(document, result.get(), first.getReference(), visitedOutlineItems);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSharedPointer<PDFOutlineItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFOutlineItem::parseImpl(const PDFDocument* document,
|
||||||
|
PDFOutlineItem* parent,
|
||||||
|
PDFObjectReference currentItem,
|
||||||
|
std::set<PDFObjectReference>& visitedOutlineItems)
|
||||||
|
{
|
||||||
|
auto checkCyclicDependence = [&visitedOutlineItems](PDFObjectReference reference)
|
||||||
|
{
|
||||||
|
if (visitedOutlineItems.count(reference))
|
||||||
|
{
|
||||||
|
throw PDFException(PDFTranslationContext::tr("Outline items have cyclic dependence."));
|
||||||
|
}
|
||||||
|
|
||||||
|
visitedOutlineItems.insert(reference);
|
||||||
|
};
|
||||||
|
checkCyclicDependence(currentItem);
|
||||||
|
|
||||||
|
PDFObject dereferencedItem = document->getObjectByReference(currentItem);
|
||||||
|
while (dereferencedItem.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* dictionary = dereferencedItem.getDictionary();
|
||||||
|
|
||||||
|
QSharedPointer<PDFOutlineItem> currentOutlineItem(new PDFOutlineItem());
|
||||||
|
const PDFObject& titleObject = document->getObject(dictionary->get("Title"));
|
||||||
|
if (titleObject.isString())
|
||||||
|
{
|
||||||
|
currentOutlineItem->setTitle(PDFEncoding::convertTextString(titleObject.getString()));
|
||||||
|
}
|
||||||
|
currentOutlineItem->setAction(PDFAction::parse(document, dictionary->get("A")));
|
||||||
|
|
||||||
|
// Parse children of this item
|
||||||
|
const PDFObject& firstItem = dictionary->get("First");
|
||||||
|
if (firstItem.isReference())
|
||||||
|
{
|
||||||
|
parseImpl(document, currentOutlineItem.get(), firstItem.getReference(), visitedOutlineItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new child to the parent
|
||||||
|
parent->addChild(qMove(currentOutlineItem));
|
||||||
|
|
||||||
|
// Parse next item
|
||||||
|
const PDFObject& nextItem = dictionary->get("Next");
|
||||||
|
if (nextItem.isReference())
|
||||||
|
{
|
||||||
|
checkCyclicDependence(nextItem.getReference());
|
||||||
|
dereferencedItem = document->getObject(nextItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We are finished
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFAction* PDFOutlineItem::getAction() const
|
||||||
|
{
|
||||||
|
return m_action.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFOutlineItem::setAction(const PDFActionPtr& action)
|
||||||
|
{
|
||||||
|
m_action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
64
PdfForQtLib/sources/pdfoutline.h
Normal file
64
PdfForQtLib/sources/pdfoutline.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2019 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PdfForQt.
|
||||||
|
//
|
||||||
|
// PdfForQt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// PdfForQt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFOUTLINE_H
|
||||||
|
#define PDFOUTLINE_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
#include "pdfobject.h"
|
||||||
|
#include "pdfaction.h"
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFDocument;
|
||||||
|
|
||||||
|
/// Outline item
|
||||||
|
class PDFOutlineItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFOutlineItem() = default;
|
||||||
|
|
||||||
|
const QString& getTitle() const { return m_title; }
|
||||||
|
void setTitle(const QString& title) { m_title = title; }
|
||||||
|
|
||||||
|
size_t getChildCount() const { return m_children.size(); }
|
||||||
|
const PDFOutlineItem* getChild(size_t index) const { return m_children[index].get(); }
|
||||||
|
void addChild(QSharedPointer<PDFOutlineItem> child) { m_children.emplace_back(qMove(child)); }
|
||||||
|
|
||||||
|
static QSharedPointer<PDFOutlineItem> parse(const PDFDocument* document, const PDFObject& root);
|
||||||
|
|
||||||
|
const PDFAction* getAction() const;
|
||||||
|
void setAction(const PDFActionPtr& action);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void parseImpl(const PDFDocument* document,
|
||||||
|
PDFOutlineItem* parent,
|
||||||
|
PDFObjectReference currentItem,
|
||||||
|
std::set<PDFObjectReference>& visitedOutlineItems);
|
||||||
|
|
||||||
|
QString m_title;
|
||||||
|
std::vector<QSharedPointer<PDFOutlineItem>> m_children;
|
||||||
|
PDFActionPtr m_action;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFOUTLINE_H
|
Loading…
x
Reference in New Issue
Block a user