// Copyright (C) 2021 Jakub Melka // // This file is part of PDF4QT. // // PDF4QT 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 // with the written consent of the copyright owner, any later version. // // PDF4QT 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 PDF4QT. If not, see . #ifndef PDFDOCUMENTMANIPULATOR_H #define PDFDOCUMENTMANIPULATOR_H #include "pdfdocument.h" #include "pdfutils.h" #include namespace pdf { /// Document page assembler/manipulator. Can assemble document(s) pages /// to a new document, where pages are inserted/removed/moved, or joined /// from another documents, or blank pages/image pages inserted. Document /// is also optimized. class PDF4QTLIBSHARED_EXPORT PDFDocumentManipulator { Q_DECLARE_TR_FUNCTIONS(pdf::PDFDocumentManipulator) public: explicit PDFDocumentManipulator() = default; /// Selects outline creation mode, when multiple documents /// are merged into one. For single document manipulation, /// this has no meaning. enum class OutlineMode { NoOutline, Join, DocumentParts }; struct AssembledPage { PDFInteger documentIndex = -1; ///< Source document index. If page is not from a document, value is -1. PDFInteger imageIndex = -1; ///< Source image index. If page is not from a image, value is -1. PDFInteger pageIndex = -1; ///< Source document page index. If page is not from a document, value is -1. QSizeF pageSize; ///< Unrotated page size PageRotation pageRotation = PageRotation::None; ///< Page rotation constexpr bool isDocumentPage() const { return documentIndex != -1; } constexpr bool isImagePage() const { return imageIndex != -1; } constexpr bool isBlankPage() const { return documentIndex == -1 && imageIndex == -1; } }; using AssembledPages = std::vector; /// Adds document with given index to available document list /// \param documentIndex Document index /// \param document Document void addDocument(int documentIndex, const PDFDocument* document) { m_documents[documentIndex] = document; } /// Adds image with given index to available image list /// \param imageIndex Image index /// \param image Image void addImage(int imageIndex, QImage image) { m_images[imageIndex] = std::move(image); } /// Assembles pages into a new document. Returns true, if a new document /// was assembled, otherwise error message is being returned. Assebmled /// document can be accessed trough a given getters. /// \param pages Pages /// \returns True or error message PDFOperationResult assemble(const AssembledPages& pages); /// Returns reference to an assembled document. This function should /// be called only, if method \p assemble returns true, otherwise /// undefined document can be returned. /// \returns Assembled document const PDFDocument& getAssembledDocument() const { return m_assembledDocument; } /// Returns rvalue reference to an assembled document. This function should /// be called only, if method \p assemble returns true, otherwise /// undefined document can be returned. /// \returns Assembled document PDFDocument&& takeAssembledDocument() { return std::move(m_assembledDocument); } static AssembledPages createAllDocumentPages(int documentIndex, const PDFDocument* document); static constexpr AssembledPage createDocumentPage(int documentIndex, int pageIndex, QSizeF pageSize, PageRotation pageRotation) { return AssembledPage{ documentIndex, -1, pageIndex, pageSize, pageRotation}; } static constexpr AssembledPage createImagePage(int imageIndex, QSizeF pageSize, PageRotation pageRotation) { return AssembledPage{ -1, imageIndex, -1, pageSize, pageRotation}; } static constexpr AssembledPage createBlankPage(QSizeF pageSize, PageRotation pageRotation) { return AssembledPage{ -1, -1, -1, pageSize, pageRotation}; } OutlineMode getOutlineMode() const; void setOutlineMode(OutlineMode outlineMode); private: struct ProcessedPage { AssembledPage assembledPage; PDFObjectReference targetPageReference; }; using ProcessedPages = std::vector; enum AssembleFlag { None = 0x0000, SingleDocument = 0x0001, ///< We are assembling a single page document (possibly with blank pages / image pages RemovedPages = 0x0002, ///< Document contains removed pages }; Q_DECLARE_FLAGS(AssembleFlags, AssembleFlag) enum MergedObjectType { MOT_OCProperties, MOT_Form, MOT_Names, MOT_Last }; /// Processes pages given a page list and a document builder. /// \param documentBuilder Document builder /// \param pages Pages to be processed /// \returns Processed pages ProcessedPages processPages(PDFDocumentBuilder& documentBuilder, const AssembledPages& pages); /// Collects objects and copies them into the target document builder. /// \param documentBuilder Document builder /// \param pages Pages to be copied /// \returns Processed pages ProcessedPages collectObjectsAndCopyPages(PDFDocumentBuilder& documentBuilder, const AssembledPages& pages); void classify(const AssembledPages& pages); void initializeMergedObjects(PDFDocumentBuilder& documentBuilder); void finalizeMergedObjects(PDFDocumentBuilder& documentBuilder); void finalizeDocument(PDFDocument* document); void addOutlineAndDocumentParts(PDFDocumentBuilder& documentBuilder, const AssembledPages& pages, const std::vector& adjustedPages); std::map m_documents; std::map m_images; AssembleFlags m_flags = None; std::array m_mergedObjects = { }; PDFDocument m_assembledDocument; OutlineMode m_outlineMode = OutlineMode::DocumentParts; std::map m_outlines; }; } // namespace pdf #endif // PDFDOCUMENTMANIPULATOR_H