PDF4QT/PdfForQtLib/sources/pdfdocument.h

224 lines
7.5 KiB
C
Raw Normal View History

2018-11-17 16:48:30 +01:00
// Copyright (C) 2018 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 PDFDOCUMENT_H
#define PDFDOCUMENT_H
#include "pdfglobal.h"
2018-11-25 14:48:08 +01:00
#include "pdfobject.h"
2018-12-24 17:09:23 +01:00
#include "pdfcatalog.h"
2018-11-17 16:48:30 +01:00
2018-12-02 17:53:19 +01:00
#include <QtCore>
#include <QDateTime>
2018-11-17 16:48:30 +01:00
namespace pdf
{
2018-12-24 17:09:23 +01:00
class PDFDocument;
2018-11-17 16:48:30 +01:00
2018-11-25 14:48:08 +01:00
/// Storage for objects. This class is not thread safe for writing (calling non-const functions). Caller must ensure
/// locking, if this object is used from multiple threads. Calling const functions should be thread safe.
class PDFObjectStorage
{
public:
constexpr inline PDFObjectStorage() = default;
constexpr inline PDFObjectStorage(const PDFObjectStorage&) = default;
constexpr inline PDFObjectStorage(PDFObjectStorage&&) = default;
constexpr inline PDFObjectStorage& operator=(const PDFObjectStorage&) = default;
constexpr inline PDFObjectStorage& operator=(PDFObjectStorage&&) = default;
struct Entry
{
constexpr inline explicit Entry() = default;
inline explicit Entry(PDFInteger generation, PDFObject object) : generation(generation), object(std::move(object)) { }
PDFInteger generation = 0;
PDFObject object;
};
using PDFObjects = std::vector<Entry>;
2018-12-01 11:36:07 +01:00
explicit PDFObjectStorage(PDFObjects&& objects, PDFObject&& trailerDictionary) :
m_objects(std::move(objects)),
m_trailerDictionary(std::move(trailerDictionary))
{
}
2018-12-02 17:53:19 +01:00
/// Returns object from the object storage. If invalid reference is passed,
/// then null object is returned (no exception is thrown).
const PDFObject& getObject(PDFObjectReference reference) const;
2018-12-01 11:36:07 +01:00
/// Returns array of objects stored in this storage
const PDFObjects& getObjects() const { return m_objects; }
/// Returns trailer dictionary
const PDFObject& getTrailerDictionary() const { return m_trailerDictionary; }
2018-11-25 14:48:08 +01:00
private:
2018-12-01 11:36:07 +01:00
PDFObjects m_objects;
PDFObject m_trailerDictionary;
2018-11-25 14:48:08 +01:00
};
2018-12-24 17:09:23 +01:00
/// Loads data from the object contained in the PDF document, such as integers,
/// bools, ... This object has two sets of functions - first one with default values,
/// then if object with valid data is not found, default value is used, and second one,
/// without default value, if valid data are not found, then exception is thrown.
/// This class uses Decorator design pattern.
class PDFDocumentDataLoaderDecorator
{
public:
inline explicit PDFDocumentDataLoaderDecorator(const PDFDocument* document) : m_document(document) { }
inline ~PDFDocumentDataLoaderDecorator() = default;
/// Reads an integer from the object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param defaultValue Default value
PDFInteger readInteger(const PDFObject& object, PDFInteger defaultValue) const;
/// Reads a text string from the object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param defaultValue Default value
QString readTextString(const PDFObject& object, const QString& defaultValue) const;
2018-12-26 18:00:17 +01:00
/// Reads a rectangle from the object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param defaultValue Default value
QRectF readRectangle(const PDFObject& object, const QRectF& defaultValue) const;
2018-12-24 17:09:23 +01:00
/// Reads enum from name object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param begin Begin of the enum search array
/// \param end End of the enum search array
/// \param default value Default value
template<typename Enum, typename Iterator>
Enum readEnumByName(const PDFObject& object, Iterator begin, Iterator end, Enum defaultValue) const
{
const PDFObject& dereferencedObject = m_document->getObject(object);
if (dereferencedObject.isName())
{
QByteArray name = dereferencedObject.getString();
for (Iterator it = begin; it != end; ++it)
{
if (name == (*it).first)
{
return (*it).second;
}
}
}
return defaultValue;
}
private:
const PDFDocument* m_document;
};
2018-12-01 11:36:07 +01:00
/// PDF document main class.
2018-11-17 16:48:30 +01:00
class PDFDocument
{
2018-12-02 17:53:19 +01:00
Q_DECLARE_TR_FUNCTIONS(pdf::PDFDocument)
2018-11-17 16:48:30 +01:00
public:
explicit PDFDocument() = default;
2018-11-25 14:48:08 +01:00
2018-12-01 11:36:07 +01:00
const PDFObjectStorage& getStorage() const { return m_pdfObjectStorage; }
2018-12-02 17:53:19 +01:00
/// Info about the document. Title, Author, Keywords...
struct Info
{
/// Indicates, that document was modified that it includes trapping information.
/// See PDF Reference 1.7, Section 10.10.5 "Trapping Support".
enum class Trapped
{
True, ///< Fully trapped
False, ///< Not yet trapped
Unknown ///< Either unknown, or it has been trapped partly, not fully
};
QString title;
QString author;
QString subject;
QString keywords;
QString creator;
QString producer;
QDateTime creationDate;
QDateTime modifiedDate;
Trapped trapped = Trapped::Unknown;
};
/// Returns info about the document (title, author, etc.)
const Info* getInfo() const { return &m_info; }
2018-12-14 19:41:12 +01:00
/// 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;
2019-01-20 17:55:06 +01:00
/// Returns the document catalog
const PDFCatalog* getCatalog() const { return &m_catalog; }
2018-11-25 14:48:08 +01:00
private:
2018-12-01 11:36:07 +01:00
friend class PDFDocumentReader;
explicit PDFDocument(PDFObjectStorage&& storage) :
m_pdfObjectStorage(std::move(storage))
{
2018-12-02 17:53:19 +01:00
init();
2018-12-01 11:36:07 +01:00
}
2018-12-02 17:53:19 +01:00
/// Initialize data based on object in the storage.
/// Can throw exception if error is detected.
void init();
/// Initialize the document info from the trailer dictionary.
/// If document info is not present, then default document
/// info is used. If error is detected, exception is thrown.
void initInfo();
2018-11-25 14:48:08 +01:00
/// Storage of objects
PDFObjectStorage m_pdfObjectStorage;
2018-12-02 17:53:19 +01:00
/// Info about the PDF document
Info m_info;
2018-12-24 17:09:23 +01:00
/// Catalog object
PDFCatalog m_catalog;
2018-11-17 16:48:30 +01:00
};
2018-12-24 17:09:23 +01:00
// Implementation
2018-12-02 17:53:19 +01:00
inline
const PDFObject& PDFDocument::getObject(const PDFObject& object) const
{
if (object.isReference())
{
// Try to dereference the object
return m_pdfObjectStorage.getObject(object.getReference());
}
return object;
}
2018-11-17 16:48:30 +01:00
} // namespace pdf
#endif // PDFDOCUMENT_H