From 15805d80af8ed5741f26e35cd0a137aefe2277d9 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sun, 9 Feb 2020 16:06:29 +0100 Subject: [PATCH] Rendering pdf to images (first part) --- .../sources/pdfdrawspacecontroller.cpp | 5 +- PdfForQtLib/sources/pdfdrawspacecontroller.h | 8 + PdfForQtLib/sources/pdfexception.h | 3 +- PdfForQtLib/sources/pdfrenderer.cpp | 288 +++++++++++++++++- PdfForQtLib/sources/pdfrenderer.h | 100 +++++- PdfForQtViewer/main.cpp | 1 + PdfForQtViewer/pdfrendertoimagesdialog.cpp | 87 +++++- PdfForQtViewer/pdfrendertoimagesdialog.h | 18 +- PdfForQtViewer/pdfrendertoimagesdialog.ui | 11 +- PdfForQtViewer/pdfviewermainwindow.cpp | 7 +- 10 files changed, 510 insertions(+), 18 deletions(-) diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp index 7919f81..ff7439a 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp @@ -393,7 +393,8 @@ PDFDrawWidgetProxy::PDFDrawWidgetProxy(QObject* parent) : m_compiler(new PDFAsynchronousPageCompiler(this)), m_textLayoutCompiler(new PDFAsynchronousTextLayoutCompiler(this)), m_rasterizer(new PDFRasterizer(this)), - m_progress(nullptr) + m_progress(nullptr), + m_useOpenGL(false) { m_controller = new PDFDrawSpaceController(this); connect(m_controller, &PDFDrawSpaceController::drawSpaceChanged, this, &PDFDrawWidgetProxy::update); @@ -1117,6 +1118,8 @@ bool PDFDrawWidgetProxy::isBlockMode() const void PDFDrawWidgetProxy::updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat) { + m_useOpenGL = useOpenGL; + m_surfaceFormat = surfaceFormat; m_rasterizer->reset(useOpenGL, surfaceFormat); } diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.h b/PdfForQtLib/sources/pdfdrawspacecontroller.h index f54723c..3d7ba6e 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.h +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.h @@ -320,6 +320,8 @@ public: void setProgress(PDFProgress* progress) { m_progress = progress; } PDFAsynchronousTextLayoutCompiler* getTextLayoutCompiler() const { return m_textLayoutCompiler; } PDFWidget* getWidget() const { return m_widget; } + bool isUsingOpenGL() const { return m_useOpenGL; } + const QSurfaceFormat& getSurfaceFormat() const { return m_surfaceFormat; } void setFeatures(PDFRenderer::Features features); void setPreferredMeshResolutionRatio(PDFReal ratio); @@ -470,6 +472,12 @@ private: /// Additional drawing interfaces std::set m_drawInterfaces; + + /// Use OpenGL for rendering? + bool m_useOpenGL; + + /// Surface format for OpenGL + QSurfaceFormat m_surfaceFormat; }; } // namespace pdf diff --git a/PdfForQtLib/sources/pdfexception.h b/PdfForQtLib/sources/pdfexception.h index b294444..1f522ce 100644 --- a/PdfForQtLib/sources/pdfexception.h +++ b/PdfForQtLib/sources/pdfexception.h @@ -44,7 +44,8 @@ enum RenderErrorType Error, Warning, NotImplemented, - NotSupported + NotSupported, + Information }; struct PDFRenderError diff --git a/PdfForQtLib/sources/pdfrenderer.cpp b/PdfForQtLib/sources/pdfrenderer.cpp index 30719b2..0e0ef75 100644 --- a/PdfForQtLib/sources/pdfrenderer.cpp +++ b/PdfForQtLib/sources/pdfrenderer.cpp @@ -18,7 +18,10 @@ #include "pdfrenderer.h" #include "pdfpainter.h" #include "pdfdocument.h" +#include "pdfexecutionpolicy.h" +#include "pdfprogress.h" +#include #include #include #include @@ -336,10 +339,120 @@ void PDFRasterizer::releaseOpenGL() } } +PDFRasterizer* PDFRasterizerPool::acquire() +{ + m_semaphore.acquire(); + + QMutexLocker guard(&m_mutex); + Q_ASSERT(!m_rasterizers.empty()); + PDFRasterizer* rasterizer = m_rasterizers.back(); + m_rasterizers.pop_back(); + return rasterizer; +} + +void PDFRasterizerPool::release(pdf::PDFRasterizer* rasterizer) +{ + QMutexLocker guard(&m_mutex); + Q_ASSERT(std::find(m_rasterizers.cbegin(), m_rasterizers.cend(), rasterizer) == m_rasterizers.cend()); + m_rasterizers.push_back(rasterizer); + + // Jakub Melka: we must release it at the end, to ensure rasterizer is in the array before + // semaphore is released, to avoid race condition. + m_semaphore.release(); +} + +void PDFRasterizerPool::render(const std::vector& pageIndices, + const PDFRasterizerPool::PageImageSizeGetter& imageSizeGetter, + const PDFRasterizerPool::ProcessImageMethod& processImage, + PDFProgress* progress) +{ + if (pageIndices.empty()) + { + return; + } + + Q_ASSERT(imageSizeGetter); + Q_ASSERT(processImage); + + QElapsedTimer timer; + timer.start(); + + emit renderError(PDFRenderError(RenderErrorType::Information, PDFTranslationContext::tr("Start at %1...").arg(QTime::currentTime().toString(Qt::TextDate)))); + + if (progress) + { + ProgressStartupInfo info; + info.showDialog = true; + info.text = PDFTranslationContext::tr("Rendering document into images."); + progress->start(pageIndices.size(), qMove(info)); + } + auto processPage = [this, progress, &imageSizeGetter, &processImage](const PDFInteger pageIndex) + { + const PDFPage* page = m_document->getCatalog()->getPage(pageIndex); + + if (!page) + { + if (progress) + { + progress->step(); + } + emit renderError(PDFRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Page %1 not found.").arg(pageIndex))); + return; + } + + // Precompile the page + PDFPrecompiledPage precompiledPage; + PDFRenderer renderer(m_document, m_fontCache, m_cms, m_optionalContentActivity, m_features, m_meshQualitySettings); + renderer.compile(&precompiledPage, pageIndex); + + for (const PDFRenderError error : precompiledPage.getErrors()) + { + emit renderError(PDFRenderError(error.type, PDFTranslationContext::tr("Page %1: %2").arg(pageIndex + 1).arg(error.message))); + } + + // Render page to image + PDFRasterizer* rasterizer = acquire(); + QImage image = rasterizer->render(page, &precompiledPage, imageSizeGetter(page), m_features); + release(rasterizer); + + // Now, process the image + processImage(pageIndex, qMove(image)); + + if (progress) + { + progress->step(); + } + }; + PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Page, pageIndices.cbegin(), pageIndices.cend(), processPage); + + if (progress) + { + progress->finish(); + } + + emit renderError(PDFRenderError(RenderErrorType::Information, PDFTranslationContext::tr("Finished at %1...").arg(QTime::currentTime().toString(Qt::TextDate)))); + emit renderError(PDFRenderError(RenderErrorType::Information, PDFTranslationContext::tr("%1 miliseconds elapsed to render %2 pages...").arg(timer.nsecsElapsed() / 1000000).arg(pageIndices.size()))); +} + +int PDFRasterizerPool::getDefaultRasterizerCount() +{ + int hint = QThread::idealThreadCount() / 2; + return qBound(1, hint, 16); +} + PDFImageWriterSettings::PDFImageWriterSettings() { m_formats = QImageWriter::supportedImageFormats(); - selectFormat(m_formats.front()); + + constexpr const char* DEFAULT_FORMAT = "png"; + if (m_formats.count(DEFAULT_FORMAT)) + { + selectFormat(DEFAULT_FORMAT); + } + else + { + selectFormat(m_formats.front()); + } } void PDFImageWriterSettings::selectFormat(const QByteArray& format) @@ -460,7 +573,8 @@ void PDFImageWriterSettings::setCurrentSubtype(const QByteArray& currentSubtype) m_currentSubtype = currentSubtype; } -PDFPageImageExportSettings::PDFPageImageExportSettings() +PDFPageImageExportSettings::PDFPageImageExportSettings(const PDFDocument* document) : + m_document(document) { m_fileTemplate = PDFTranslationContext::tr("Image_%"); } @@ -535,4 +649,174 @@ void PDFPageImageExportSettings::setPixelResolution(int pixelResolution) m_pixelResolution = pixelResolution; } +bool PDFPageImageExportSettings::validate(QString* errorMessagePtr) +{ + QString dummy; + QString& errorMessage = errorMessagePtr ? *errorMessagePtr : dummy; + + if (m_directory.isEmpty()) + { + errorMessage = PDFTranslationContext::tr("Target directory is empty."); + return false; + } + + // Check, if target directory exists + QDir directory(m_directory); + if (!directory.exists()) + { + errorMessage = PDFTranslationContext::tr("Target directory '%1' doesn't exist.").arg(m_directory); + return false; + } + + if (m_fileTemplate.isEmpty()) + { + errorMessage = PDFTranslationContext::tr("File template is empty."); + return false; + } + + if (!m_fileTemplate.contains("%")) + { + errorMessage = PDFTranslationContext::tr("File template must contain character '%' for page number."); + return false; + } + + // Check page selection + if (m_pageSelectionMode == PageSelectionMode::Selection) + { + std::vector pages = getPages(); + if (pages.empty()) + { + errorMessage = PDFTranslationContext::tr("Page list is invalid. It should have form such as '1-12,17,24,27-29'."); + return false; + } + + if (pages.back() >= PDFInteger(m_document->getCatalog()->getPageCount())) + { + errorMessage = PDFTranslationContext::tr("Page list contains page, which is not in the document (%1).").arg(pages.back()); + return false; + } + } + + if (m_resolutionMode == ResolutionMode::DPI && (m_dpiResolution < getMinDPIResolution() || m_dpiResolution > getMaxDPIResolution())) + { + errorMessage = PDFTranslationContext::tr("DPI resolution should be in range %1 to %2.").arg(getMinDPIResolution()).arg(getMaxDPIResolution()); + return false; + } + + if (m_resolutionMode == ResolutionMode::Pixels && (m_pixelResolution < getMinPixelResolution() || m_pixelResolution > getMaxPixelResolution())) + { + errorMessage = PDFTranslationContext::tr("Pixel resolution should be in range %1 to %2.").arg(getMinPixelResolution()).arg(getMaxPixelResolution()); + return false; + } + + return true; +} + +std::vector PDFPageImageExportSettings::getPages() const +{ + std::vector result; + + switch (m_pageSelectionMode) + { + case PageSelectionMode::All: + { + result.resize(m_document->getCatalog()->getPageCount(), 0); + std::iota(result.begin(), result.end(), 0); + break; + } + + case PageSelectionMode::Selection: + { + bool ok = false; + QStringList parts = m_pageSelection.split(QChar(','), Qt::SkipEmptyParts, Qt::CaseSensitive); + for (const QString& part : parts) + { + QStringList numbers = part.split(QChar('-'), Qt::KeepEmptyParts, Qt::CaseSensitive); + switch (numbers.size()) + { + case 1: + { + const QString& numberString = numbers.front(); + result.push_back(numberString.toLongLong(&ok)); + break; + } + + case 2: + { + bool ok1 = false; + bool ok2 = false; + const QString& lowString = numbers.front(); + const QString& highString = numbers.back(); + const PDFInteger low = lowString.toLongLong(&ok1); + const PDFInteger high = highString.toLongLong(&ok2); + ok = ok1 && ok2 && low <= high; + if (ok) + { + const PDFInteger count = high - low + 1; + result.resize(result.size() + count, 0); + std::iota(std::prev(result.end(), count), result.end(), low); + } + break; + } + + default: + { + ok = true; + break; + } + } + + // If error is detected, do not continue in parsing + if (!ok) + { + break; + } + + // We must remove duplicate pages + qSort(result); + result.erase(std::unique(result.begin(), result.end()), result.end()); + } + + if (!ok) + { + result.clear(); + } + + break; + } + + default: + break; + } + + return result; +} + +PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document, + const PDFFontCache* fontCache, + const PDFCMS* cms, + const PDFOptionalContentActivity* optionalContentActivity, + PDFRenderer::Features features, + const PDFMeshQualitySettings& meshQualitySettings, + int rasterizerCount, + bool useOpenGL, + const QSurfaceFormat& surfaceFormat, + QObject* parent) : + BaseClass(parent), + m_document(document), + m_fontCache(fontCache), + m_cms(cms), + m_optionalContentActivity(optionalContentActivity), + m_features(features), + m_meshQualitySettings(meshQualitySettings), + m_semaphore(rasterizerCount) +{ + m_rasterizers.reserve(rasterizerCount); + for (int i = 0; i < rasterizerCount; ++i) + { + m_rasterizers.push_back(new PDFRasterizer(this)); + m_rasterizers.back()->reset(useOpenGL, surfaceFormat); + } +} + } // namespace pdf diff --git a/PdfForQtLib/sources/pdfrenderer.h b/PdfForQtLib/sources/pdfrenderer.h index 32522aa..8f3cd53 100644 --- a/PdfForQtLib/sources/pdfrenderer.h +++ b/PdfForQtLib/sources/pdfrenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2020 Jakub Melka +// Copyright (C) 2019-2020 Jakub Melka // // This file is part of PdfForQt. // @@ -22,6 +22,8 @@ #include "pdfexception.h" #include "pdfmeshqualitysettings.h" +#include +#include #include #include @@ -33,6 +35,7 @@ class QOpenGLFramebufferObject; namespace pdf { class PDFCMS; +class PDFProgress; class PDFFontCache; class PDFPrecompiledPage; class PDFOptionalContentActivity; @@ -105,6 +108,7 @@ private: /// Renders PDF pages to bitmap images (QImage). It can use OpenGL for painting, /// if it is enabled, if this is the case, offscreen rendering to framebuffer /// is used. +/// \note Construct this object only in main GUI thread class PDFRasterizer : public QObject { Q_OBJECT @@ -114,7 +118,7 @@ private: public: explicit PDFRasterizer(QObject* parent); - ~PDFRasterizer(); + virtual ~PDFRasterizer() override; /// Resets the renderer. This function must be called from main GUI thread, /// it cannot be called from deferred threads, because it can create hidden @@ -155,6 +159,83 @@ private: QOpenGLFramebufferObject* m_fbo; }; +/// Pool of page image renderers. It can use predefined number of renderers to +/// render page images asynchronously. You can use this object in two ways - +/// first one is as standard object pool, second one is to directly render +/// page images asynchronously. +class PDFFORQTLIBSHARED_EXPORT PDFRasterizerPool : public QObject +{ + Q_OBJECT + +private: + using BaseClass = QObject; + +public: + + using PageImageSizeGetter = std::function; + using ProcessImageMethod = std::function; + + /// Creates new rasterizer pool + /// \param document Document + /// \param fontCache Font cache + /// \param cms Color management system + /// \param optionalContentActivity Optional content activity + /// \param features Renderer features + /// \param meshQualitySettings Mesh quality settings + /// \param rasterizerCount Number of rasterizers + /// \param useOpenGL Use OpenGL for rendering? + /// \param surfaceFormat Surface format + /// \param parent Parent object + explicit PDFRasterizerPool(const PDFDocument* document, + const PDFFontCache* fontCache, + const PDFCMS* cms, + const PDFOptionalContentActivity* optionalContentActivity, + PDFRenderer::Features features, + const PDFMeshQualitySettings& meshQualitySettings, + int rasterizerCount, + bool useOpenGL, + const QSurfaceFormat& surfaceFormat, + QObject* parent); + + /// Acquire rasterizer. This function is thread safe. + PDFRasterizer* acquire(); + + /// Return back (release) rasterizer into rasterizer pool + /// This function is thread safe. + /// \param rasterizer Rasterizer + void release(PDFRasterizer* rasterizer); + + /// Renders pages asynchronously to images, using given page indices, + /// function which returns rendered size and process image function, + /// which processes rendered images. + /// \param pageIndices Page indices for rendered pages + /// \param imageSizeGetter Getter, which computes image size from page index + /// \param processImage Method, which processes rendered page images + /// \param progress Progress indicator + void render(const std::vector& pageIndices, + const PageImageSizeGetter& imageSizeGetter, + const ProcessImageMethod& processImage, + PDFProgress* progress); + + /// Returns default rasterizer count + static int getDefaultRasterizerCount(); + +signals: + void renderError(PDFRenderError error); + +private: + const PDFDocument* m_document; + const PDFFontCache* m_fontCache; + const PDFCMS* m_cms; + const PDFOptionalContentActivity* m_optionalContentActivity; + PDFRenderer::Features m_features; + const PDFMeshQualitySettings& m_meshQualitySettings; + + QSemaphore m_semaphore; + QMutex m_mutex; + std::vector m_rasterizers; +}; + /// Settings object for image writer class PDFFORQTLIBSHARED_EXPORT PDFImageWriterSettings { @@ -211,7 +292,7 @@ private: class PDFFORQTLIBSHARED_EXPORT PDFPageImageExportSettings { public: - explicit PDFPageImageExportSettings(); + explicit PDFPageImageExportSettings(const PDFDocument* document); enum class PageSelectionMode { @@ -246,7 +327,20 @@ public: int getPixelResolution() const; void setPixelResolution(int pixelResolution); + /// Validates the settings, if they can be used for image generation + bool validate(QString* errorMessagePtr); + + /// Returns list of selected pages + std::vector getPages() const; + + static constexpr int getMinDPIResolution() { return 72; } + static constexpr int getMaxDPIResolution() { return 6000; } + + static constexpr int getMinPixelResolution() { return 100; } + static constexpr int getMaxPixelResolution() { return 16384; } + private: + const PDFDocument* m_document; ResolutionMode m_resolutionMode = ResolutionMode::DPI; PageSelectionMode m_pageSelectionMode = PageSelectionMode::All; QString m_directory; diff --git a/PdfForQtViewer/main.cpp b/PdfForQtViewer/main.cpp index 70bf6da..eeb3dab 100644 --- a/PdfForQtViewer/main.cpp +++ b/PdfForQtViewer/main.cpp @@ -25,6 +25,7 @@ int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true); QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); + QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true); QApplication application(argc, argv); QCoreApplication::setOrganizationName("MelkaJ"); diff --git a/PdfForQtViewer/pdfrendertoimagesdialog.cpp b/PdfForQtViewer/pdfrendertoimagesdialog.cpp index a6956cc..d67e1ce 100644 --- a/PdfForQtViewer/pdfrendertoimagesdialog.cpp +++ b/PdfForQtViewer/pdfrendertoimagesdialog.cpp @@ -18,17 +18,29 @@ #include "pdfrendertoimagesdialog.h" #include "ui_pdfrendertoimagesdialog.h" +#include "pdfcms.h" #include "pdfutils.h" #include "pdfwidgetutils.h" +#include "pdfoptionalcontent.h" +#include "pdfdrawspacecontroller.h" #include +#include +#include namespace pdfviewer { -PDFRenderToImagesDialog::PDFRenderToImagesDialog(QWidget* parent) : +PDFRenderToImagesDialog::PDFRenderToImagesDialog(const pdf::PDFDocument* document, + pdf::PDFDrawWidgetProxy* proxy, + pdf::PDFProgress* progress, + QWidget* parent) : QDialog(parent), ui(new Ui::PDFRenderToImagesDialog), + m_document(document), + m_proxy(proxy), + m_progress(progress), + m_imageExportSettings(document), m_isLoadingData(false) { ui->setupUi(this); @@ -56,6 +68,9 @@ PDFRenderToImagesDialog::PDFRenderToImagesDialog(QWidget* parent) : connect(ui->optimizedWriteCheckBox, &QCheckBox::clicked, this, &PDFRenderToImagesDialog::onOptimizedWriteChanged); connect(ui->progressiveScanWriteCheckBox, &QCheckBox::clicked, this, &PDFRenderToImagesDialog::onProgressiveScanWriteChanged); + ui->resolutionDPIEdit->setRange(pdf::PDFPageImageExportSettings::getMinDPIResolution(), pdf::PDFPageImageExportSettings::getMaxDPIResolution()); + ui->resolutionPixelsEdit->setRange(pdf::PDFPageImageExportSettings::getMinPixelResolution(), pdf::PDFPageImageExportSettings::getMaxPixelResolution()); + loadImageWriterSettings(); loadImageExportSettings(); @@ -219,6 +234,11 @@ void PDFRenderToImagesDialog::onProgressiveScanWriteChanged(bool value) m_imageWriterSettings.setProgressiveScanWrite(value); } +void PDFRenderToImagesDialog::onRenderError(pdf::PDFRenderError error) +{ + ui->progressMessagesEdit->setPlainText(QString("%1\n%2").arg(ui->progressMessagesEdit->toPlainText()).arg(error.message)); +} + void PDFRenderToImagesDialog::on_selectDirectoryButton_clicked() { QString directory = QFileDialog::getExistingDirectory(this, tr("Select output directory"), ui->directoryEdit->text()); @@ -228,6 +248,67 @@ void PDFRenderToImagesDialog::on_selectDirectoryButton_clicked() } } +void PDFRenderToImagesDialog::on_buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) + { + QString message; + if (m_imageExportSettings.validate(&message)) + { + // We are ready to render the document + std::vector pageIndices = m_imageExportSettings.getPages(); + + pdf::PDFOptionalContentActivity optionalContentActivity(m_document, pdf::OCUsage::Export, nullptr); + pdf::PDFCMSPointer cms = m_proxy->getCMSManager()->getCurrentCMS(); + pdf::PDFRasterizerPool rasterizerPool(m_document, m_proxy->getFontCache(), cms.data(), + &optionalContentActivity, m_proxy->getFeatures(), m_proxy->getMeshQualitySettings(), + pdf::PDFRasterizerPool::getDefaultRasterizerCount(), m_proxy->isUsingOpenGL(), m_proxy->getSurfaceFormat(), this); + connect(&rasterizerPool, &pdf::PDFRasterizerPool::renderError, this, &PDFRenderToImagesDialog::onRenderError); + + auto imageSizeGetter = [this](const pdf::PDFPage* page) -> QSize + { + Q_ASSERT(page); + + switch (m_imageExportSettings.getResolutionMode()) + { + case pdf::PDFPageImageExportSettings::ResolutionMode::DPI: + { + QSizeF size = page->getRotatedMediaBox().size() * m_imageExportSettings.getDpiResolution(); + return size.toSize(); + } + + case pdf::PDFPageImageExportSettings::ResolutionMode::Pixels: + { + int pixelResolution = m_imageExportSettings.getPixelResolution(); + QSizeF size = page->getRotatedMediaBox().size().scaled(pixelResolution, pixelResolution, Qt::KeepAspectRatio); + return size.toSize(); + } + + default: + { + Q_ASSERT(false); + break; + } + } + + return QSize(); + }; + + auto processImage = [](const pdf::PDFInteger pageIndex, QImage&& image) + { + Q_UNUSED(pageIndex); + Q_UNUSED(image); + }; + + setEnabled(false); + rasterizerPool.render(pageIndices, imageSizeGetter, processImage, m_progress); + setEnabled(true); + } + else + { + QMessageBox::critical(this, tr("Error"), message); + } + } +} + } // namespace pdfviewer - - diff --git a/PdfForQtViewer/pdfrendertoimagesdialog.h b/PdfForQtViewer/pdfrendertoimagesdialog.h index ed14840..f054baf 100644 --- a/PdfForQtViewer/pdfrendertoimagesdialog.h +++ b/PdfForQtViewer/pdfrendertoimagesdialog.h @@ -22,11 +22,19 @@ #include +class QAbstractButton; + namespace Ui { class PDFRenderToImagesDialog; } +namespace pdf +{ +class PDFProgress; +class PDFDrawWidgetProxy; +} + namespace pdfviewer { @@ -35,11 +43,15 @@ class PDFRenderToImagesDialog : public QDialog Q_OBJECT public: - explicit PDFRenderToImagesDialog(QWidget* parent); + explicit PDFRenderToImagesDialog(const pdf::PDFDocument* document, + pdf::PDFDrawWidgetProxy* proxy, + pdf::PDFProgress* progress, + QWidget* parent); virtual ~PDFRenderToImagesDialog() override; private slots: void on_selectDirectoryButton_clicked(); + void on_buttonBox_clicked(QAbstractButton* button); private: /// Loads image writer settings to the ui @@ -62,8 +74,12 @@ private: void onGammaChanged(double value); void onOptimizedWriteChanged(bool value); void onProgressiveScanWriteChanged(bool value); + void onRenderError(pdf::PDFRenderError error); Ui::PDFRenderToImagesDialog* ui; + const pdf::PDFDocument* m_document; + pdf::PDFDrawWidgetProxy* m_proxy; + pdf::PDFProgress* m_progress; pdf::PDFImageWriterSettings m_imageWriterSettings; pdf::PDFPageImageExportSettings m_imageExportSettings; bool m_isLoadingData; diff --git a/PdfForQtViewer/pdfrendertoimagesdialog.ui b/PdfForQtViewer/pdfrendertoimagesdialog.ui index 625e095..6cd14a7 100644 --- a/PdfForQtViewer/pdfrendertoimagesdialog.ui +++ b/PdfForQtViewer/pdfrendertoimagesdialog.ui @@ -7,7 +7,7 @@ 0 0 690 - 593 + 602 @@ -234,7 +234,14 @@ - + + + false + + + true + + diff --git a/PdfForQtViewer/pdfviewermainwindow.cpp b/PdfForQtViewer/pdfviewermainwindow.cpp index 913fcd2..764ab45 100644 --- a/PdfForQtViewer/pdfviewermainwindow.cpp +++ b/PdfForQtViewer/pdfviewermainwindow.cpp @@ -1279,11 +1279,8 @@ void PDFViewerMainWindow::on_actionPrint_triggered() void PDFViewerMainWindow::on_actionRender_to_Images_triggered() { - PDFRenderToImagesDialog dialog(this); - if (dialog.exec() == QDialog::Accepted) - { - - } + PDFRenderToImagesDialog dialog(m_pdfDocument.data(), m_pdfWidget->getDrawWidgetProxy(), m_progress, this); + dialog.exec(); } } // namespace pdfviewer