mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Optimization (basic structures)
This commit is contained in:
@@ -37,6 +37,7 @@ SOURCES += \
|
||||
pdfaboutdialog.cpp \
|
||||
pdfadvancedfindwidget.cpp \
|
||||
pdfdocumentpropertiesdialog.cpp \
|
||||
pdfoptimizedocumentdialog.cpp \
|
||||
pdfrecentfilemanager.cpp \
|
||||
pdfrendertoimagesdialog.cpp \
|
||||
pdfsendmail.cpp \
|
||||
@@ -51,6 +52,7 @@ HEADERS += \
|
||||
pdfaboutdialog.h \
|
||||
pdfadvancedfindwidget.h \
|
||||
pdfdocumentpropertiesdialog.h \
|
||||
pdfoptimizedocumentdialog.h \
|
||||
pdfrecentfilemanager.h \
|
||||
pdfrendertoimagesdialog.h \
|
||||
pdfsendmail.h \
|
||||
@@ -65,6 +67,7 @@ FORMS += \
|
||||
pdfaboutdialog.ui \
|
||||
pdfadvancedfindwidget.ui \
|
||||
pdfdocumentpropertiesdialog.ui \
|
||||
pdfoptimizedocumentdialog.ui \
|
||||
pdfrendertoimagesdialog.ui \
|
||||
pdfsidebarwidget.ui \
|
||||
pdfviewermainwindow.ui \
|
||||
|
144
PdfForQtViewer/pdfoptimizedocumentdialog.cpp
Normal file
144
PdfForQtViewer/pdfoptimizedocumentdialog.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "pdfoptimizedocumentdialog.h"
|
||||
#include "ui_pdfoptimizedocumentdialog.h"
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfdocumentwriter.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QElapsedTimer>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace pdfviewer
|
||||
{
|
||||
|
||||
PDFOptimizeDocumentDialog::PDFOptimizeDocumentDialog(const pdf::PDFDocument* document, QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFOptimizeDocumentDialog),
|
||||
m_document(document),
|
||||
m_optimizer(pdf::PDFOptimizer::All, nullptr),
|
||||
m_optimizeButton(nullptr),
|
||||
m_optimizationInProgress(false),
|
||||
m_wasOptimized(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
auto addCheckBox = [this](QString text, pdf::PDFOptimizer::OptimizationFlag flag)
|
||||
{
|
||||
QCheckBox* checkBox = new QCheckBox(text, this);
|
||||
checkBox->setChecked(m_optimizer.getFlags().testFlag(flag));
|
||||
connect(checkBox, &QCheckBox::clicked, this, [this, flag](bool checked) { m_optimizer.setFlags(m_optimizer.getFlags().setFlag(flag, checked)); });
|
||||
ui->groupBoxLayout->addWidget(checkBox);
|
||||
};
|
||||
|
||||
addCheckBox(tr("Embed (dereference) simple objects, such as int, bool, real"), pdf::PDFOptimizer::DereferenceSimpleObjects);
|
||||
addCheckBox(tr("Remove null objects from dictionary entries"), pdf::PDFOptimizer::RemoveNullObjects);
|
||||
addCheckBox(tr("Remove unused objects (objects unreachable from document root object)"), pdf::PDFOptimizer::RemoveUnusedObjects);
|
||||
addCheckBox(tr("Merge identical objects"), pdf::PDFOptimizer::MergeIdenticalObjects);
|
||||
addCheckBox(tr("Shrink object storage (squeeze free entries)"), pdf::PDFOptimizer::ShrinkObjectStorage);
|
||||
addCheckBox(tr("Recompress flate streams by maximal compression"), pdf::PDFOptimizer::RecompressFlateStreams);
|
||||
|
||||
m_optimizeButton = ui->buttonBox->addButton(tr("Optimize"), QDialogButtonBox::ActionRole);
|
||||
|
||||
connect(m_optimizeButton, &QPushButton::clicked, this, &PDFOptimizeDocumentDialog::onOptimizeButtonClicked);
|
||||
connect(&m_optimizer, &pdf::PDFOptimizer::optimizationStarted, this, &PDFOptimizeDocumentDialog::onOptimizationStarted);
|
||||
connect(&m_optimizer, &pdf::PDFOptimizer::optimizationProgress, this, &PDFOptimizeDocumentDialog::onOptimizationProgress);
|
||||
connect(&m_optimizer, &pdf::PDFOptimizer::optimizationFinished, this, &PDFOptimizeDocumentDialog::onOptimizationFinished);
|
||||
connect(this, &PDFOptimizeDocumentDialog::displayOptimizationInfo, this, &PDFOptimizeDocumentDialog::onDisplayOptimizationInfo);
|
||||
|
||||
pdf::PDFWidgetUtils::scaleWidget(this, QSize(640, 380));
|
||||
updateUi();
|
||||
}
|
||||
|
||||
PDFOptimizeDocumentDialog::~PDFOptimizeDocumentDialog()
|
||||
{
|
||||
Q_ASSERT(!m_optimizationInProgress);
|
||||
Q_ASSERT(!m_future.isRunning());
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::optimize()
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
m_optimizer.setDocument(m_document);
|
||||
m_optimizer.optimize();
|
||||
m_optimizedDocument = m_optimizer.takeOptimizedDocument();
|
||||
|
||||
qreal msecsElapsed = timer.nsecsElapsed() / 1000000.0;
|
||||
timer.invalidate();
|
||||
|
||||
m_optimizationInfo.msecsElapsed = msecsElapsed;
|
||||
m_optimizationInfo.bytesBeforeOptimization = pdf::PDFDocumentWriter::getDocumentFileSize(m_document);
|
||||
m_optimizationInfo.bytesAfterOptimization = pdf::PDFDocumentWriter::getDocumentFileSize(&m_optimizedDocument);
|
||||
emit displayOptimizationInfo();
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onOptimizeButtonClicked()
|
||||
{
|
||||
Q_ASSERT(!m_optimizationInProgress);
|
||||
Q_ASSERT(!m_future.isRunning());
|
||||
|
||||
m_optimizationInProgress = true;
|
||||
m_future = QtConcurrent::run([this]() { optimize(); });
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onOptimizationStarted()
|
||||
{
|
||||
Q_ASSERT(m_optimizationInProgress);
|
||||
ui->logTextEdit->setPlainText(tr("Optimization started!"));
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onOptimizationProgress(QString progressText)
|
||||
{
|
||||
Q_ASSERT(m_optimizationInProgress);
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText()).arg(progressText));
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onOptimizationFinished()
|
||||
{
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText()).arg(tr("Optimization finished!")));
|
||||
m_future.waitForFinished();
|
||||
m_optimizationInProgress = false;
|
||||
m_wasOptimized = true;
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onDisplayOptimizationInfo()
|
||||
{
|
||||
QStringList texts;
|
||||
texts << tr("Optimized in %1 msecs").arg(m_optimizationInfo.msecsElapsed);
|
||||
if (m_optimizationInfo.bytesBeforeOptimization != -1 &&
|
||||
m_optimizationInfo.bytesAfterOptimization != -1)
|
||||
{
|
||||
texts << tr("Bytes before optimization: %1").arg(m_optimizationInfo.bytesBeforeOptimization);
|
||||
texts << tr("Bytes after optimization: %1").arg(m_optimizationInfo.bytesAfterOptimization);
|
||||
texts << tr("Bytes saved by optimization: %1").arg(m_optimizationInfo.bytesBeforeOptimization - m_optimizationInfo.bytesAfterOptimization);
|
||||
|
||||
qreal ratio = 100.0;
|
||||
if (m_optimizationInfo.bytesBeforeOptimization > 0)
|
||||
{
|
||||
ratio = 100.0 * qreal(m_optimizationInfo.bytesAfterOptimization) / qreal(m_optimizationInfo.bytesBeforeOptimization);
|
||||
}
|
||||
|
||||
texts << tr("Compression ratio: %1 %").arg(ratio);
|
||||
}
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText(), texts.join("\n")));
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::updateUi()
|
||||
{
|
||||
for (QCheckBox* checkBox : findChildren<QCheckBox*>(QString(), Qt::FindChildrenRecursively))
|
||||
{
|
||||
checkBox->setEnabled(!m_optimizationInProgress);
|
||||
}
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_wasOptimized && !m_optimizationInProgress);
|
||||
ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(!m_optimizationInProgress);
|
||||
m_optimizeButton->setEnabled(!m_optimizationInProgress);
|
||||
}
|
||||
|
||||
} // namespace pdfviewer
|
58
PdfForQtViewer/pdfoptimizedocumentdialog.h
Normal file
58
PdfForQtViewer/pdfoptimizedocumentdialog.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef PDFOPTIMIZEDOCUMENTDIALOG_H
|
||||
#define PDFOPTIMIZEDOCUMENTDIALOG_H
|
||||
|
||||
#include "pdfoptimizer.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFuture>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFOptimizeDocumentDialog;
|
||||
}
|
||||
|
||||
namespace pdfviewer
|
||||
{
|
||||
|
||||
class PDFOptimizeDocumentDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFOptimizeDocumentDialog(const pdf::PDFDocument* document, QWidget* parent);
|
||||
virtual ~PDFOptimizeDocumentDialog() override;
|
||||
|
||||
signals:
|
||||
void displayOptimizationInfo();
|
||||
|
||||
private:
|
||||
void optimize();
|
||||
void onOptimizeButtonClicked();
|
||||
void onOptimizationStarted();
|
||||
void onOptimizationProgress(QString progressText);
|
||||
void onOptimizationFinished();
|
||||
void onDisplayOptimizationInfo();
|
||||
|
||||
void updateUi();
|
||||
|
||||
struct OptimizationInfo
|
||||
{
|
||||
qreal msecsElapsed = 0.0;
|
||||
qint64 bytesBeforeOptimization = -1;
|
||||
qint64 bytesAfterOptimization = -1;
|
||||
};
|
||||
|
||||
Ui::PDFOptimizeDocumentDialog* ui;
|
||||
const pdf::PDFDocument* m_document;
|
||||
pdf::PDFOptimizer m_optimizer;
|
||||
QPushButton* m_optimizeButton;
|
||||
bool m_optimizationInProgress;
|
||||
bool m_wasOptimized;
|
||||
QFuture<void> m_future;
|
||||
pdf::PDFDocument m_optimizedDocument;
|
||||
OptimizationInfo m_optimizationInfo;
|
||||
};
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
||||
#endif // PDFOPTIMIZEDOCUMENTDIALOG_H
|
82
PdfForQtViewer/pdfoptimizedocumentdialog.ui
Normal file
82
PdfForQtViewer/pdfoptimizedocumentdialog.ui
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFOptimizeDocumentDialog</class>
|
||||
<widget class="QDialog" name="PDFOptimizeDocumentDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>741</width>
|
||||
<height>530</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Document optimization</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="dialogLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optimizationSettingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Optimization Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="groupBoxLayout"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="logTextEdit">
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PDFOptimizeDocumentDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PDFOptimizeDocumentDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -24,6 +24,7 @@
|
||||
#include "pdfviewersettingsdialog.h"
|
||||
#include "pdfdocumentpropertiesdialog.h"
|
||||
#include "pdfrendertoimagesdialog.h"
|
||||
#include "pdfoptimizedocumentdialog.h"
|
||||
|
||||
#include "pdfdocumentreader.h"
|
||||
#include "pdfvisitor.h"
|
||||
@@ -886,6 +887,7 @@ void PDFViewerMainWindow::updateActionsAvailability()
|
||||
ui->actionFind->setEnabled(hasValidDocument);
|
||||
ui->actionPrint->setEnabled(hasValidDocument && canPrint);
|
||||
ui->actionRender_to_Images->setEnabled(hasValidDocument && canPrint);
|
||||
ui->actionOptimize->setEnabled(hasValidDocument);
|
||||
setEnabled(!isBusy);
|
||||
updateUndoRedoActions();
|
||||
}
|
||||
@@ -1409,4 +1411,15 @@ void PDFViewerMainWindow::on_actionRender_to_Images_triggered()
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void PDFViewerMainWindow::on_actionOptimize_triggered()
|
||||
{
|
||||
PDFOptimizeDocumentDialog dialog(m_pdfDocument.data(), this);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
||||
|
@@ -99,6 +99,8 @@ private slots:
|
||||
void on_actionPrint_triggered();
|
||||
void on_actionRender_to_Images_triggered();
|
||||
|
||||
void on_actionOptimize_triggered();
|
||||
|
||||
private:
|
||||
void onActionOpenTriggered();
|
||||
void onActionCloseTriggered();
|
||||
|
@@ -124,6 +124,8 @@
|
||||
<addaction name="actionSelectTextAll"/>
|
||||
<addaction name="actionDeselectText"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOptimize"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuEdit"/>
|
||||
@@ -529,6 +531,11 @@
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOptimize">
|
||||
<property name="text">
|
||||
<string>Optimize</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
Reference in New Issue
Block a user