From d335aaa2664a485d2d3098b84e6c5b50277a6e96 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sun, 1 Nov 2020 18:50:21 +0100 Subject: [PATCH] Optimize tool --- PdfTool/PdfTool.pro | 2 + PdfTool/pdftoolabstractapplication.cpp | 33 ++++++++++ PdfTool/pdftoolabstractapplication.h | 15 +++++ PdfTool/pdftooloptimize.cpp | 85 ++++++++++++++++++++++++++ PdfTool/pdftooloptimize.h | 36 +++++++++++ 5 files changed, 171 insertions(+) create mode 100644 PdfTool/pdftooloptimize.cpp create mode 100644 PdfTool/pdftooloptimize.h diff --git a/PdfTool/PdfTool.pro b/PdfTool/PdfTool.pro index 90f6f29..be80390 100644 --- a/PdfTool/PdfTool.pro +++ b/PdfTool/PdfTool.pro @@ -54,6 +54,7 @@ SOURCES += \ pdftoolinfonameddestinations.cpp \ pdftoolinfopageboxes.cpp \ pdftoolinfostructuretree.cpp \ + pdftooloptimize.cpp \ pdftoolrender.cpp \ pdftoolseparate.cpp \ pdftoolunite.cpp \ @@ -84,6 +85,7 @@ HEADERS += \ pdftoolinfonameddestinations.h \ pdftoolinfopageboxes.h \ pdftoolinfostructuretree.h \ + pdftooloptimize.h \ pdftoolrender.h \ pdftoolseparate.h \ pdftoolunite.h \ diff --git a/PdfTool/pdftoolabstractapplication.cpp b/PdfTool/pdftoolabstractapplication.cpp index 6ab7e83..b8558e2 100644 --- a/PdfTool/pdftoolabstractapplication.cpp +++ b/PdfTool/pdftoolabstractapplication.cpp @@ -303,6 +303,14 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser* parser->addOption(QCommandLineOption("render-msaa-samples", "MSAA sample count for GPU rendering.", "samples", "4")); parser->addOption(QCommandLineOption("render-rasterizers", "Number of rasterizer contexts.", "rasterizers", QString::number(pdf::PDFRasterizerPool::getDefaultRasterizerCount()))); } + + if (optionFlags.testFlag(Optimize)) + { + for (const PDFToolOptions::OptimizeFeatureInfo& info : PDFToolOptions::getOptimizeFlagInfos()) + { + parser->addOption(QCommandLineOption(info.option, info.description)); + } + } } PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser) const @@ -820,6 +828,18 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser options.uniteFiles = positionalArguments; } + if (optionFlags.testFlag(Optimize)) + { + options.optimizeFlags = pdf::PDFOptimizer::None; + for (const PDFToolOptions::OptimizeFeatureInfo& info : PDFToolOptions::getOptimizeFlagInfos()) + { + if (parser->isSet(info.option)) + { + options.optimizeFlags |= info.flag; + } + } + } + return options; } @@ -969,4 +989,17 @@ std::vector PDFToolOptions::getRenderFeatures }; } +std::vector PDFToolOptions::getOptimizeFlagInfos() +{ + return { + OptimizeFeatureInfo{ "opt-deref-simple", "Dereference referenced simple objects (integers, bools, ...).", pdf::PDFOptimizer::DereferenceSimpleObjects }, + OptimizeFeatureInfo{ "opt-remove-null", "Remove null objects from dictionary entries.", pdf::PDFOptimizer::RemoveNullObjects }, + OptimizeFeatureInfo{ "opt-remove-unused", "Remove not referenced objects.", pdf::PDFOptimizer::RemoveUnusedObjects }, + OptimizeFeatureInfo{ "opt-merge-identical", "Merge identical objects.", pdf::PDFOptimizer::MergeIdenticalObjects }, + OptimizeFeatureInfo{ "opt-shrink-storage", "Shrink object storage by renumbering objects.", pdf::PDFOptimizer::ShrinkObjectStorage }, + OptimizeFeatureInfo{ "opt-recompress-flate", "Recompress flate streams with maximal compression.", pdf::PDFOptimizer::RecompressFlateStreams }, + OptimizeFeatureInfo{ "opt-all", "Use all optimization algorithms.", pdf::PDFOptimizer::All } + }; +} + } // pdftool diff --git a/PdfTool/pdftoolabstractapplication.h b/PdfTool/pdftoolabstractapplication.h index c3c2220..853eb5b 100644 --- a/PdfTool/pdftoolabstractapplication.h +++ b/PdfTool/pdftoolabstractapplication.h @@ -23,6 +23,7 @@ #include "pdfdocumenttextflow.h" #include "pdfrenderer.h" #include "pdfcms.h" +#include "pdfoptimizer.h" #include #include @@ -135,6 +136,9 @@ struct PDFToolOptions // For option 'Unite' QStringList uniteFiles; + // For option 'Optimize' + pdf::PDFOptimizer::OptimizationFlags optimizeFlags = pdf::PDFOptimizer::None; + /// Returns page range. If page range is invalid, then \p errorMessage is empty. /// \param pageCount Page count /// \param[out] errorMessage Error message @@ -150,6 +154,16 @@ struct PDFToolOptions /// Returns a list of available renderer features static std::vector getRenderFeatures(); + + struct OptimizeFeatureInfo + { + QString option; + QString description; + pdf::PDFOptimizer::OptimizationFlag flag; + }; + + /// Returns a list of available optimize features + static std::vector getOptimizeFlagInfos(); }; /// Base class for all applications @@ -203,6 +217,7 @@ public: RenderFlags = 0x00020000, ///< Render flags for page image rasterizer Separate = 0x00040000, ///< Settings for Separate tool Unite = 0x00080000, ///< Settings for Unite tool + Optimize = 0x00100000, ///< Settings for Optimize }; Q_DECLARE_FLAGS(Options, Option) diff --git a/PdfTool/pdftooloptimize.cpp b/PdfTool/pdftooloptimize.cpp new file mode 100644 index 0000000..4cce6fb --- /dev/null +++ b/PdfTool/pdftooloptimize.cpp @@ -0,0 +1,85 @@ +// 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 "pdftooloptimize.h" +#include "pdfdocumentwriter.h" + + +namespace pdftool +{ + +static PDFToolOptimize s_optimizeApplication; + +QString PDFToolOptimize::getStandardString(PDFToolAbstractApplication::StandardString standardString) const +{ + switch (standardString) + { + case Command: + return "optimize"; + + case Name: + return PDFToolTranslationContext::tr("Optimize"); + + case Description: + return PDFToolTranslationContext::tr("Optimize document size using various algorithms."); + + default: + Q_ASSERT(false); + break; + } + + return QString(); +} + +int PDFToolOptimize::execute(const PDFToolOptions& options) +{ + if (!options.optimizeFlags) + { + PDFConsole::writeError(PDFToolTranslationContext::tr("No optimization option has been set."), options.outputCodec); + return ErrorInvalidArguments; + } + + pdf::PDFDocument document; + QByteArray sourceData; + if (!readDocument(options, document, &sourceData)) + { + return ErrorDocumentReading; + } + + pdf::PDFOptimizer optimizer(options.optimizeFlags, nullptr); + QObject::connect(&optimizer, &pdf::PDFOptimizer::optimizationProgress, &optimizer, [&options](QString text) { PDFConsole::writeError(text, options.outputCodec); }, Qt::DirectConnection); + optimizer.setDocument(&document); + optimizer.optimize(); + document = optimizer.takeOptimizedDocument(); + + pdf::PDFDocumentWriter writer(nullptr); + pdf::PDFOperationResult result = writer.write(options.document, &document, true); + if (!result) + { + PDFConsole::writeError(PDFToolTranslationContext::tr("Failed to write optimize document. %1").arg(result.getErrorMessage()), options.outputCodec); + return ErrorFailedWriteToFile; + } + + return ExitSuccess; +} + +PDFToolAbstractApplication::Options PDFToolOptimize::getOptionsFlags() const +{ + return ConsoleFormat | OpenDocument | Optimize; +} + +} // namespace pdftool diff --git a/PdfTool/pdftooloptimize.h b/PdfTool/pdftooloptimize.h new file mode 100644 index 0000000..b78cad3 --- /dev/null +++ b/PdfTool/pdftooloptimize.h @@ -0,0 +1,36 @@ +// 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 PDFTOOLOPTIMIZE_H +#define PDFTOOLOPTIMIZE_H + +#include "pdftoolabstractapplication.h" + +namespace pdftool +{ + +class PDFToolOptimize : public PDFToolAbstractApplication +{ +public: + virtual QString getStandardString(StandardString standardString) const override; + virtual int execute(const PDFToolOptions& options) override; + virtual Options getOptionsFlags() const override; +}; + +} // namespace pdftool + +#endif // PDFTOOLOPTIMIZE_H