diff --git a/PdfForQtLib/PdfForQtLib.pro b/PdfForQtLib/PdfForQtLib.pro index 76dc6b9..8f4b532 100644 --- a/PdfForQtLib/PdfForQtLib.pro +++ b/PdfForQtLib/PdfForQtLib.pro @@ -42,6 +42,7 @@ SOURCES += \ sources/pdfccittfaxdecoder.cpp \ sources/pdfcms.cpp \ sources/pdfcompiler.cpp \ + sources/pdfdocumentbuilder.cpp \ sources/pdfexecutionpolicy.cpp \ sources/pdffile.cpp \ sources/pdfitemmodels.cpp \ @@ -87,6 +88,7 @@ HEADERS += \ sources/pdfccittfaxdecoder.h \ sources/pdfcms.h \ sources/pdfcompiler.h \ + sources/pdfdocumentbuilder.h \ sources/pdfdocumentdrawinterface.h \ sources/pdfexecutionpolicy.h \ sources/pdffile.h \ diff --git a/PdfForQtLib/sources/pdfdocumentbuilder.cpp b/PdfForQtLib/sources/pdfdocumentbuilder.cpp new file mode 100644 index 0000000..cfc19ca --- /dev/null +++ b/PdfForQtLib/sources/pdfdocumentbuilder.cpp @@ -0,0 +1,130 @@ +// Copyright (C) 2020 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 . + +#include "pdfdocumentbuilder.h" + +namespace pdf +{ + +void PDFObjectFactory::beginArray() +{ + m_items.emplace_back(ItemType::Array, PDFArray()); +} + +void PDFObjectFactory::endArray() +{ + Item topItem = qMove(m_items.back()); + Q_ASSERT(topItem.type == ItemType::Array); + m_items.pop_back(); + addObject(PDFObject::createArray(std::make_shared(qMove(std::get(topItem.object))))); +} + +void PDFObjectFactory::beginDictionary() +{ + m_items.emplace_back(ItemType::Dictionary, PDFDictionary()); +} + +void PDFObjectFactory::endDictionary() +{ + Item topItem = qMove(m_items.back()); + Q_ASSERT(topItem.type == ItemType::Dictionary); + m_items.pop_back(); + addObject(PDFObject::createDictionary(std::make_shared(qMove(std::get(topItem.object))))); +} + +void PDFObjectFactory::beginDictionaryItem(const QByteArray& name) +{ + m_items.emplace_back(ItemType::DictionaryItem, name, PDFObject()); +} + +void PDFObjectFactory::endDictionaryItem() +{ + Item topItem = qMove(m_items.back()); + Q_ASSERT(topItem.type == ItemType::DictionaryItem); + m_items.pop_back(); + + Item& dictionaryItem = m_items.back(); + Q_ASSERT(dictionaryItem.type == ItemType::Dictionary); + std::get(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get(topItem.object))); +} + +void PDFObjectFactory::addObject(PDFObject object) +{ + if (m_items.empty()) + { + m_items.emplace_back(ItemType::Object, qMove(object)); + return; + } + + Item& topItem = m_items.back(); + switch (topItem.type) + { + case ItemType::Object: + // Just override the object + topItem.object = qMove(object); + break; + + case ItemType::Dictionary: + // Do not do anything - we are inside dictionary + break; + + case ItemType::DictionaryItem: + // Add item to dictionary item + topItem.object = qMove(object); + break; + + case ItemType::Array: + std::get(topItem.object).appendItem(qMove(object)); + break; + + default: + Q_ASSERT(false); + break; + } +} + +PDFObjectFactory& PDFObjectFactory::operator<<(std::nullptr_t) +{ + addObject(PDFObject::createNull()); + return *this; +} + +PDFObjectFactory& PDFObjectFactory::operator<<(bool value) +{ + addObject(PDFObject::createBool(value)); + return *this; +} + +PDFObjectFactory& PDFObjectFactory::operator<<(PDFReal value) +{ + addObject(PDFObject::createReal(value)); + return *this; +} + +PDFObjectFactory& PDFObjectFactory::operator<<(PDFInteger value) +{ + addObject(PDFObject::createInteger(value)); + return *this; +} + +PDFObjectFactory& PDFObjectFactory::operator<<(PDFObjectReference value) +{ + addObject(PDFObject::createReference(value)); + return *this; +} + +} // namespace pdf diff --git a/PdfForQtLib/sources/pdfdocumentbuilder.h b/PdfForQtLib/sources/pdfdocumentbuilder.h new file mode 100644 index 0000000..997f629 --- /dev/null +++ b/PdfForQtLib/sources/pdfdocumentbuilder.h @@ -0,0 +1,119 @@ +// Copyright (C) 2020 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 . + +#ifndef PDFDOCUMENTBUILDER_H +#define PDFDOCUMENTBUILDER_H + +#include "pdfobject.h" + +namespace pdf +{ + +/// Factory for creating various PDF objects, such as simple objects, +/// dictionaries, arrays etc. +class PDFObjectFactory +{ +public: + inline explicit PDFObjectFactory() = default; + + void beginArray(); + void endArray(); + + void beginDictionary(); + void endDictionary(); + + void beginDictionaryItem(const QByteArray& name); + void endDictionaryItem(); + + PDFObjectFactory& operator<<(std::nullptr_t); + PDFObjectFactory& operator<<(bool value); + PDFObjectFactory& operator<<(PDFReal value); + PDFObjectFactory& operator<<(PDFInteger value); + PDFObjectFactory& operator<<(PDFObjectReference value); + + /// Treat containers - write them as array + template()))> + PDFObjectFactory& operator<<(Container container) + { + beginArray(); + + auto it = std::begin(container); + auto itEnd = std::end(container); + for (; it != itEnd; ++it) + { + *this << *it; + } + + endArray(); + + return *this; + } + +private: + void addObject(PDFObject object); + + enum class ItemType + { + Object, + Dictionary, + DictionaryItem, + Array + }; + + /// What is stored in this structure, depends on the type. + /// If type is 'Object', then single simple object is in object, + /// if type is dictionary, then PDFDictionary is stored in object, + /// if type is dictionary item, then object and item name is stored + /// in the data, if item is array, then array is stored in the data. + struct Item + { + inline Item() = default; + + template + inline Item(ItemType type, T&& data) : + type(type), + object(qMove(data)) + { + + } + + template + inline Item(ItemType type, const QByteArray& itemName, T&& data) : + type(type), + itemName(qMove(itemName)), + object(qMove(data)) + { + + } + + ItemType type = ItemType::Object; + QByteArray itemName; + std::variant object; + }; + + std::vector m_items; +}; + +class PDFDocumentBuilder +{ +public: + PDFDocumentBuilder(); +}; + +} // namespace pdf + +#endif // PDFDOCUMENTBUILDER_H diff --git a/PdfForQtLib/sources/pdfobject.h b/PdfForQtLib/sources/pdfobject.h index 9b7f44d..da4e916 100644 --- a/PdfForQtLib/sources/pdfobject.h +++ b/PdfForQtLib/sources/pdfobject.h @@ -55,7 +55,7 @@ public: class PDFFORQTLIBSHARED_EXPORT PDFObject { public: - enum class Type + enum class Type : uint8_t { // Simple PDF objects Null,