DocPage Organizer: Installer

This commit is contained in:
Jakub Melka 2021-08-08 16:52:10 +02:00
parent cbdd1bcfb3
commit d9da61fd77
12 changed files with 185 additions and 140 deletions

View File

@ -1,3 +1,20 @@
# Copyright (C) 2018-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 <https://www.gnu.org/licenses/>.
QT += core gui xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@ -34,7 +51,3 @@ HEADERS += \
FORMS += \
generatormainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

View File

@ -34,10 +34,11 @@ INCLUDEPATH += $$PWD/../PDF4QtLib/Sources
DESTDIR = $$OUT_PWD/..
LIBS += -L$$OUT_PWD/..
LIBS += -lPDF4QtLib
CONFIG += force_debug_info
CONFIG += force_debug_info no_check_exist
application.files = $$DESTDIR/Pdf4QtDocPageOrganizer.exe
application.path = $$DESTDIR/install
application.CONFIG += no_check_exist
INSTALLS += application
SOURCES += \

View File

@ -237,6 +237,7 @@ QMAKE_RESOURCE_FLAGS += -threshold 0 -compress 9
PdfforQt_library.files = $$DESTDIR/Pdf4QtLib.dll
PdfforQt_library.path = $$DESTDIR/install
PdfforQt_library.CONFIG += no_check_exist
INSTALLS += PdfforQt_library

View File

@ -83,129 +83,7 @@ PDFOperationResult PDFDocumentManipulator::assemble(const AssembledPages& pages)
// manipulating a single document).
if (!m_flags.testFlag(SingleDocument))
{
PDFInteger lastDocumentIndex = pages.front().documentIndex;
struct DocumentPartInfo
{
size_t pageCount = 0;
PDFInteger documentIndex = 0;
bool isWholeDocument = false;
QString caption;
PDFObjectReference firstPageReference;
};
std::vector<DocumentPartInfo> documentParts = { DocumentPartInfo() };
PDFClosedIntervalSet pageNumbers;
PDFInteger imageCount = 0;
PDFInteger blankPageCount = 0;
PDFInteger totalPageCount = 0;
auto addDocumentPartCaption = [&](PDFInteger documentIndex)
{
DocumentPartInfo& info = documentParts.back();
QString documentTitle;
if (documentIndex != -1 && m_documents.count(documentIndex))
{
const PDFDocument* document = m_documents.at(documentIndex);
documentTitle = document->getInfo()->title;
if (documentTitle.isEmpty())
{
documentTitle = tr("Document %1").arg(documentIndex);
}
if (pageNumbers.getTotalLength() < PDFInteger(document->getCatalog()->getPageCount()))
{
documentTitle = tr("%1, p. %2").arg(documentTitle, pageNumbers.toText(true));
}
else
{
info.isWholeDocument = true;
}
}
else if (imageCount > 0 && blankPageCount == 0)
{
documentTitle = tr("%1 Images").arg(imageCount);
}
else
{
documentTitle = tr("%1 Pages").arg(imageCount + blankPageCount);
}
info.caption = documentTitle;
info.documentIndex = documentIndex;
info.firstPageReference = (totalPageCount < PDFInteger(adjustedPages.size())) ? adjustedPages[totalPageCount] : PDFObjectReference();
pageNumbers = PDFClosedIntervalSet();
imageCount = 0;
blankPageCount = 0;
totalPageCount += info.pageCount;
};
for (const AssembledPage& page : pages)
{
if (page.documentIndex == lastDocumentIndex)
{
++documentParts.back().pageCount;
}
else
{
addDocumentPartCaption(lastDocumentIndex);
documentParts.push_back(DocumentPartInfo());
++documentParts.back().pageCount;
lastDocumentIndex = page.documentIndex;
}
if (page.isDocumentPage())
{
pageNumbers.addValue(page.pageIndex + 1);
}
if (page.isImagePage())
{
++imageCount;
}
if (page.isBlankPage())
{
++blankPageCount;
}
}
addDocumentPartCaption(lastDocumentIndex);
std::vector<size_t> documentPartPageCounts;
std::transform(documentParts.cbegin(), documentParts.cend(), std::back_inserter(documentPartPageCounts), [](const auto& part) { return part.pageCount; });
documentBuilder.createDocumentParts(documentPartPageCounts);
if (m_outlineMode != OutlineMode::NoOutline)
{
QSharedPointer<PDFOutlineItem> rootItem(new PDFOutlineItem());
for (const DocumentPartInfo& info : documentParts)
{
QSharedPointer<PDFOutlineItem> documentPartItem(new PDFOutlineItem);
documentPartItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::createFit(info.firstPageReference), PDFDestination())));
documentPartItem->setTitle(info.caption);
documentPartItem->setFontBold(true);
if (m_outlineMode == OutlineMode::Join && info.isWholeDocument)
{
const PDFInteger documentIndex = info.documentIndex;
QSharedPointer<PDFOutlineItem> outline = PDFOutlineItem::parse(documentBuilder.getStorage(), PDFObject::createReference(m_outlines.at(documentIndex)));
if (outline)
{
for (size_t i = 0; i < outline->getChildCount(); ++i)
{
documentPartItem->addChild(outline->getChildPtr(i));
}
}
}
rootItem->addChild(std::move(documentPartItem));
}
documentBuilder.setOutline(rootItem.data());
}
addOutlineAndDocumentParts(documentBuilder, pages, adjustedPages);
}
pdf::PDFDocument mergedDocument = documentBuilder.build();
@ -583,6 +461,135 @@ void PDFDocumentManipulator::finalizeDocument(PDFDocument* document)
m_assembledDocument = finalBuilder.build();
}
void PDFDocumentManipulator::addOutlineAndDocumentParts(PDFDocumentBuilder& documentBuilder,
const AssembledPages& pages,
const std::vector<PDFObjectReference>& adjustedPages)
{
PDFInteger lastDocumentIndex = pages.front().documentIndex;
struct DocumentPartInfo
{
size_t pageCount = 0;
PDFInteger documentIndex = 0;
bool isWholeDocument = false;
QString caption;
PDFObjectReference firstPageReference;
};
std::vector<DocumentPartInfo> documentParts = { DocumentPartInfo() };
PDFClosedIntervalSet pageNumbers;
PDFInteger imageCount = 0;
PDFInteger blankPageCount = 0;
PDFInteger totalPageCount = 0;
auto addDocumentPartCaption = [&](PDFInteger documentIndex)
{
DocumentPartInfo& info = documentParts.back();
QString documentTitle;
if (documentIndex != -1 && m_documents.count(documentIndex))
{
const PDFDocument* document = m_documents.at(documentIndex);
documentTitle = document->getInfo()->title;
if (documentTitle.isEmpty())
{
documentTitle = tr("Document %1").arg(documentIndex);
}
if (pageNumbers.getTotalLength() < PDFInteger(document->getCatalog()->getPageCount()))
{
documentTitle = tr("%1, p. %2").arg(documentTitle, pageNumbers.toText(true));
}
else
{
info.isWholeDocument = true;
}
}
else if (imageCount > 0 && blankPageCount == 0)
{
documentTitle = tr("%1 Images").arg(imageCount);
}
else
{
documentTitle = tr("%1 Pages").arg(imageCount + blankPageCount);
}
info.caption = documentTitle;
info.documentIndex = documentIndex;
info.firstPageReference = (totalPageCount < PDFInteger(adjustedPages.size())) ? adjustedPages[totalPageCount] : PDFObjectReference();
pageNumbers = PDFClosedIntervalSet();
imageCount = 0;
blankPageCount = 0;
totalPageCount += info.pageCount;
};
for (const AssembledPage& page : pages)
{
if (page.documentIndex == lastDocumentIndex)
{
++documentParts.back().pageCount;
}
else
{
addDocumentPartCaption(lastDocumentIndex);
documentParts.push_back(DocumentPartInfo());
++documentParts.back().pageCount;
lastDocumentIndex = page.documentIndex;
}
if (page.isDocumentPage())
{
pageNumbers.addValue(page.pageIndex + 1);
}
if (page.isImagePage())
{
++imageCount;
}
if (page.isBlankPage())
{
++blankPageCount;
}
}
addDocumentPartCaption(lastDocumentIndex);
std::vector<size_t> documentPartPageCounts;
std::transform(documentParts.cbegin(), documentParts.cend(), std::back_inserter(documentPartPageCounts), [](const auto& part) { return part.pageCount; });
documentBuilder.createDocumentParts(documentPartPageCounts);
if (m_outlineMode != OutlineMode::NoOutline)
{
QSharedPointer<PDFOutlineItem> rootItem(new PDFOutlineItem());
for (const DocumentPartInfo& info : documentParts)
{
QSharedPointer<PDFOutlineItem> documentPartItem(new PDFOutlineItem);
documentPartItem->setAction(PDFActionPtr(new PDFActionGoTo(PDFDestination::createFit(info.firstPageReference), PDFDestination())));
documentPartItem->setTitle(info.caption);
documentPartItem->setFontBold(true);
if (m_outlineMode == OutlineMode::Join && info.isWholeDocument)
{
const PDFInteger documentIndex = info.documentIndex;
QSharedPointer<PDFOutlineItem> outline = PDFOutlineItem::parse(documentBuilder.getStorage(), PDFObject::createReference(m_outlines.at(documentIndex)));
if (outline)
{
for (size_t i = 0; i < outline->getChildCount(); ++i)
{
documentPartItem->addChild(outline->getChildPtr(i));
}
}
}
rootItem->addChild(std::move(documentPartItem));
}
documentBuilder.setOutline(rootItem.data());
}
}
PDFDocumentManipulator::OutlineMode PDFDocumentManipulator::getOutlineMode() const
{
return m_outlineMode;

View File

@ -140,6 +140,9 @@ private:
void initializeMergedObjects(PDFDocumentBuilder& documentBuilder);
void finalizeMergedObjects(PDFDocumentBuilder& documentBuilder);
void finalizeDocument(PDFDocument* document);
void addOutlineAndDocumentParts(PDFDocumentBuilder& documentBuilder,
const AssembledPages& pages,
const std::vector<PDFObjectReference>& adjustedPages);
std::map<PDFInteger, const PDFDocument*> m_documents;
std::map<PDFInteger, QImage> m_images;

View File

@ -92,10 +92,17 @@ CONFIG += force_debug_info
viewer_library.files = $$DESTDIR/Pdf4QtViewer.dll
viewer_library.path = $$DESTDIR/install
viewer_library.CONFIG += no_check_exist
INSTALLS += viewer_library
plugins.files = $$files($$DESTDIR/pdfplugins/*.dll)
plugins.files = $$DESTDIR/pdfplugins/ObjectInspectorPlugin.dll \
$$DESTDIR/pdfplugins/OutputPreviewPlugin.dll \
$$DESTDIR/pdfplugins/DimensionsPlugin.dll \
$$DESTDIR/pdfplugins/SoftProofingPlugin.dll \
$$DESTDIR/pdfplugins/RedactPlugin.dll
plugins.path = $$DESTDIR/install/pdfplugins
plugins.CONFIG += no_check_exist
INSTALLS += plugins
RESOURCES += \

View File

@ -2123,6 +2123,10 @@ void PDFProgramController::onActionDeveloperCreateInstaller()
addComponentMeta("pdf4qt_v_profi", tr("Viewer (Profi)"), tr("Advanced PDF viewer with many functions, such as annotation editing, form filling, signature verification, and many optional plugins."), pdf::PDF_LIBRARY_VERSION, "pdf4qt_v_profi", false, true, false);
addFileContent("pdf4qt_v_profi", "Pdf4QtViewerProfi.exe");
addStartMenuShortcut("pdf4qt_dpo", "Pdf4QtDocPageOrganizer", tr("PDF4QT DocPage Organizer"));
addComponentMeta("pdf4qt_dpo", tr("DocPage Organizer"), tr("Document page organizer (split/merge documents, insert/remove/move/clone pages, insert blank pages and images to create a new document)."), pdf::PDF_LIBRARY_VERSION, "pdf4qt_dpo", false, true, false);
addFileContent("pdf4qt_dpo", "Pdf4QtDocPageOrganizer.exe");
addStartMenuShortcut("pdf4qt_tool", "PdfTool", tr("PDF4QT Command Line Tool"));
addComponentMeta("pdf4qt_tool", tr("PdfTool"), tr("Command line tool for manipulation of PDF files with many functions."), pdf::PDF_LIBRARY_VERSION, "pdf4qt_tool", false, false, false);
addFileContent("pdf4qt_tool", "PdfTool.exe");

View File

@ -38,6 +38,7 @@ CONFIG += force_debug_info
application.files = $$DESTDIR/Pdf4QtViewerLite.exe
application.path = $$DESTDIR/install
application.CONFIG += no_check_exist
INSTALLS += application
SOURCES += \

View File

@ -38,6 +38,7 @@ CONFIG += force_debug_info
application.files = $$DESTDIR/Pdf4QtViewerProfi.exe
application.path = $$DESTDIR/install
application.CONFIG += no_check_exist
INSTALLS += application
SOURCES += \

View File

@ -1,3 +1,20 @@
# Copyright (C) 2018-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 <https://www.gnu.org/licenses/>.
QT += gui widgets
CONFIG += c++11 console
@ -28,10 +45,5 @@ SOURCES += \
main.cpp \
pdfexamplesgenerator.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
pdfexamplesgenerator.h

View File

@ -67,13 +67,9 @@ SOURCES += \
pdftoolverifysignatures.cpp \
pdftoolxml.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
application.files = $$DESTDIR/PdfTool.exe
application.path = $$DESTDIR/install
application.CONFIG += no_check_exist
INSTALLS += application
HEADERS += \

View File

@ -15,7 +15,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
QT += testlib
CONFIG += qt console warn_on depend_includepath testcase