From 4c12527be0de84c92d3080ee20949118e64f80f1 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Mon, 18 Oct 2021 16:14:58 +0200 Subject: [PATCH] DocDiff application: create document report, overlay --- Pdf4QtDocDiff/mainwindow.cpp | 40 ++++++++- Pdf4QtDocDiff/mainwindow.h | 1 + Pdf4QtDocDiff/settingsdockwidget.cpp | 7 ++ Pdf4QtDocDiff/settingsdockwidget.h | 3 + Pdf4QtDocDiff/settingsdockwidget.ui | 27 +++++- Pdf4QtDocDiff/utils.cpp | 87 ++++++++++++++++++-- Pdf4QtDocDiff/utils.h | 15 ++++ Pdf4QtLib/sources/pdfdrawspacecontroller.cpp | 50 +++++++++-- Pdf4QtLib/sources/pdfdrawspacecontroller.h | 36 ++++++-- Pdf4QtLib/sources/pdfpainter.cpp | 7 +- Pdf4QtLib/sources/pdfpainter.h | 7 +- Pdf4QtLib/sources/pdfredact.cpp | 2 +- Pdf4QtLib/sources/pdfrenderer.cpp | 4 +- 13 files changed, 257 insertions(+), 29 deletions(-) diff --git a/Pdf4QtDocDiff/mainwindow.cpp b/Pdf4QtDocDiff/mainwindow.cpp index dc57049..ec40d9f 100644 --- a/Pdf4QtDocDiff/mainwindow.cpp +++ b/Pdf4QtDocDiff/mainwindow.cpp @@ -26,6 +26,8 @@ #include "pdfdocumentreader.h" #include "pdfdrawspacecontroller.h" #include "pdfdocumentmanipulator.h" +#include "pdfdocumentbuilder.h" +#include "pdfdocumentwriter.h" #include #include @@ -65,6 +67,7 @@ MainWindow::MainWindow(QWidget* parent) : m_settingsDockWidget = new SettingsDockWidget(&m_settings, this); addDockWidget(Qt::LeftDockWidgetArea, m_settingsDockWidget);; connect(m_settingsDockWidget, &SettingsDockWidget::colorsChanged, this, &MainWindow::onColorsChanged); + connect(m_settingsDockWidget, &SettingsDockWidget::transparencySliderChanged, this, &MainWindow::updateOverlayTransparency); m_differencesDockWidget = new DifferencesDockWidget(this, &m_diffResult, &m_filteredDiffResult, &m_diffNavigator, &m_settings); addDockWidget(Qt::LeftDockWidgetArea, m_differencesDockWidget); @@ -171,6 +174,7 @@ MainWindow::MainWindow(QWidget* parent) : loadSettings(); updateAll(false); + updateOverlayTransparency(); } MainWindow::~MainWindow() @@ -403,8 +407,10 @@ bool MainWindow::canPerformOperation(Operation operation) const return m_diffNavigator.canGoNext(); case Operation::CreateCompareReport: - case Operation::ShowPageswithDifferences: case Operation::SaveDifferencesToXML: + return m_filteredDiffResult.isChanged(); + + case Operation::ShowPageswithDifferences: return m_diffResult.isChanged(); case Operation::DisplayDifferences: @@ -610,9 +616,31 @@ void MainWindow::performOperation(Operation operation) break; } + case Operation::CreateCompareReport: - Q_ASSERT(false); + { + if (m_filteredDiffResult.isSame()) + { + break; + } + + QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save As"), m_settings.directory, tr("Portable Document (*.pdf);;All files (*.*)")); + if (!saveFileName.isEmpty()) + { + pdf::PDFDocumentBuilder builder(m_pdfWidget->getDrawWidgetProxy()->getDocument()); + m_drawInterface.drawAnnotations(m_pdfWidget->getDrawWidgetProxy()->getDocument(), &builder); + + pdf::PDFDocument document = builder.build(); + pdf::PDFDocumentWriter writer(m_progress); + pdf::PDFOperationResult result = writer.write(saveFileName, &document, QFile::exists(saveFileName)); + if (!result) + { + QMessageBox::critical(this, tr("Error"), result.getErrorMessage()); + } + } + break; + } default: { @@ -765,6 +793,14 @@ void MainWindow::updateCustomPageLayout() m_pdfWidget->getDrawWidgetProxy()->setPageLayout(pdf::PageLayout::Custom); } +void MainWindow::updateOverlayTransparency() +{ + const pdf::PDFReal value = m_settingsDockWidget->getTransparencySliderValue() * 0.01; + m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(1, true, 1.0 - value); + m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(2, false, value); + m_pdfWidget->update(); +} + std::optional MainWindow::openDocument() { QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)")); diff --git a/Pdf4QtDocDiff/mainwindow.h b/Pdf4QtDocDiff/mainwindow.h index 2b3d11f..467f60f 100644 --- a/Pdf4QtDocDiff/mainwindow.h +++ b/Pdf4QtDocDiff/mainwindow.h @@ -114,6 +114,7 @@ private: void updateFilteredResult(); void updateViewDocument(); void updateCustomPageLayout(); + void updateOverlayTransparency(); std::optional openDocument(); diff --git a/Pdf4QtDocDiff/settingsdockwidget.cpp b/Pdf4QtDocDiff/settingsdockwidget.cpp index 5212a82..eefdeeb 100644 --- a/Pdf4QtDocDiff/settingsdockwidget.cpp +++ b/Pdf4QtDocDiff/settingsdockwidget.cpp @@ -43,6 +43,8 @@ SettingsDockWidget::SettingsDockWidget(Settings* settings, QWidget* parent) : connect(comboBox, &QComboBox::editTextChanged, this, &SettingsDockWidget::onEditColorChanged); } + + connect(ui->transparencySlider, &QSlider::valueChanged, this, &SettingsDockWidget::transparencySliderChanged); } SettingsDockWidget::~SettingsDockWidget() @@ -101,6 +103,11 @@ void SettingsDockWidget::loadColors() loadColor(ui->moveColorCombo, m_settings->colorPageMove); } +int SettingsDockWidget::getTransparencySliderValue() const +{ + return ui->transparencySlider->value(); +} + QIcon SettingsDockWidget::getIconForColor(QColor color) const { QIcon icon; diff --git a/Pdf4QtDocDiff/settingsdockwidget.h b/Pdf4QtDocDiff/settingsdockwidget.h index 3f3cae3..86be8e0 100644 --- a/Pdf4QtDocDiff/settingsdockwidget.h +++ b/Pdf4QtDocDiff/settingsdockwidget.h @@ -52,8 +52,11 @@ public: void loadColors(); void saveColors(); + int getTransparencySliderValue() const; + signals: void colorsChanged(); + void transparencySliderChanged(int value); private: QIcon getIconForColor(QColor color) const; diff --git a/Pdf4QtDocDiff/settingsdockwidget.ui b/Pdf4QtDocDiff/settingsdockwidget.ui index 5966ca9..7877e49 100644 --- a/Pdf4QtDocDiff/settingsdockwidget.ui +++ b/Pdf4QtDocDiff/settingsdockwidget.ui @@ -7,7 +7,7 @@ 0 0 548 - 417 + 511 @@ -79,6 +79,31 @@ + + + + Transparency | Overlay View + + + + + + 100 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + + + + diff --git a/Pdf4QtDocDiff/utils.cpp b/Pdf4QtDocDiff/utils.cpp index 21d2000..83b9d6f 100644 --- a/Pdf4QtDocDiff/utils.cpp +++ b/Pdf4QtDocDiff/utils.cpp @@ -16,8 +16,10 @@ // along with PDF4QT. If not, see . #include "utils.h" +#include "pdfutils.h" #include "pdfwidgetutils.h" #include "pdfpainterutils.h" +#include "pdfdocumentbuilder.h" #include @@ -87,7 +89,7 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, { QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size(); QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); - m_layout.emplace_back(0, i, rect); + m_layout.emplace_back(0, i, -1, rect); yPos += pageSize.height() + 5; } } @@ -102,7 +104,7 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size(); QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); - m_layout.emplace_back(0, item.leftPage, rect); + m_layout.emplace_back(0, item.leftPage, -1, rect); yPos += pageSize.height() + 5; } } @@ -126,7 +128,7 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, { QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size(); QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); - m_layout.emplace_back(0, i, rect); + m_layout.emplace_back(0, i, -1, rect); yPos += pageSize.height() + 5; } } @@ -141,7 +143,7 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, QSizeF pageSize = catalog->getPage(item.rightPage)->getRotatedMediaBoxMM().size(); QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); - m_layout.emplace_back(0, item.rightPage, rect); + m_layout.emplace_back(0, item.rightPage, -1, rect); yPos += pageSize.height() + 5; } } @@ -164,15 +166,20 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, { QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size(); QRectF rect; + pdf::PDFInteger groupIndex = -1; if (mode == ComparedDocumentMapper::Mode::Combined) { rect = QRectF(-pageSize.width() - 5, yPos, pageSize.width(), pageSize.height()); } else { + if (item.rightPage != -1) + { + groupIndex = 1; + } rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); } - m_layout.emplace_back(0, item.leftPage, rect); + m_layout.emplace_back(0, item.leftPage, groupIndex, rect); yAdvance = pageSize.height() + 5; m_leftPageIndices[item.leftPage] = item.leftPage; } @@ -182,15 +189,20 @@ void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode, pdf::PDFInteger rightPageIndex = item.rightPage + offset; QSizeF pageSize = catalog->getPage(rightPageIndex)->getRotatedMediaBoxMM().size(); QRectF rect; + pdf::PDFInteger groupIndex = -1; if (mode == ComparedDocumentMapper::Mode::Combined) { rect = QRectF(5, yPos, pageSize.width(), pageSize.height()); } else { + if (item.leftPage != -1) + { + groupIndex = 2; + } rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); } - m_layout.emplace_back(0, rightPageIndex, rect); + m_layout.emplace_back(0, rightPageIndex, groupIndex, rect); yAdvance = qMax(yAdvance, pageSize.height() + 5); m_rightPageIndices[rightPageIndex] = item.rightPage; } @@ -414,6 +426,69 @@ void DifferencesDrawInterface::drawPostRendering(QPainter* painter, QRect rect) Q_UNUSED(rect); } +void DifferencesDrawInterface::drawAnnotations(const pdf::PDFDocument* document, + pdf::PDFDocumentBuilder* builder) +{ + pdf::PDFInteger pageCount = document->getCatalog()->getPageCount(); + + QString title = pdf::PDFSysUtils::getUserName(); + QString subject = tr("Difference"); + + for (pdf::PDFInteger pageIndex = 0; pageIndex < pageCount; ++pageIndex) + { + const size_t differencesCount = m_diffResult->getDifferencesCount(); + const pdf::PDFInteger leftPageIndex = m_mapper->getLeftPageIndex(pageIndex); + const pdf::PDFInteger rightPageIndex = m_mapper->getRightPageIndex(pageIndex); + + const pdf::PDFPage* page = document->getCatalog()->getPage(pageIndex); + pdf::PDFObjectReference reference = page->getPageReference(); + + if (leftPageIndex != -1) + { + for (size_t i = 0; i < differencesCount; ++i) + { + auto leftRectangles = m_diffResult->getLeftRectangles(i); + for (auto it = leftRectangles.first; it != leftRectangles.second; ++it) + { + const auto& item = *it; + if (item.first == leftPageIndex) + { + QColor color = getColorForIndex(i); + const QRectF& rect = item.second; + QPolygonF polygon; + polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft(); + pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i)); + builder->setAnnotationOpacity(annotation, 0.3); + builder->updateAnnotationAppearanceStreams(annotation); + } + } + } + } + + if (rightPageIndex != -1) + { + for (size_t i = 0; i < differencesCount; ++i) + { + auto rightRectangles = m_diffResult->getRightRectangles(i); + for (auto it = rightRectangles.first; it != rightRectangles.second; ++it) + { + const auto& item = *it; + if (item.first == rightPageIndex) + { + QColor color = getColorForIndex(i); + const QRectF& rect = item.second; + QPolygonF polygon; + polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft(); + pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i)); + builder->setAnnotationOpacity(annotation, 0.3); + builder->updateAnnotationAppearanceStreams(annotation); + } + } + } + } + } +} + void DifferencesDrawInterface::drawRectangle(QPainter* painter, const QMatrix& pagePointToDevicePointMatrix, const QRectF& rect, diff --git a/Pdf4QtDocDiff/utils.h b/Pdf4QtDocDiff/utils.h index b31357b..9a287d6 100644 --- a/Pdf4QtDocDiff/utils.h +++ b/Pdf4QtDocDiff/utils.h @@ -23,6 +23,13 @@ #include "pdfdrawspacecontroller.h" #include "pdfdocumentdrawinterface.h" +#include + +namespace pdf +{ +class PDFDocumentBuilder; +} // namespace pdf + namespace pdfdocdiff { @@ -77,6 +84,8 @@ private: class DifferencesDrawInterface : public pdf::IDocumentDrawInterface { + Q_DECLARE_TR_FUNCTIONS(pdfdocdiff::DifferencesDrawInterface) + public: explicit DifferencesDrawInterface(const Settings* settings, const ComparedDocumentMapper* mapper, @@ -87,8 +96,14 @@ public: pdf::PDFTextLayoutGetter& layoutGetter, const QMatrix& pagePointToDevicePointMatrix, QList& errors) const override; + virtual void drawPostRendering(QPainter* painter, QRect rect) const override; + /// Draw annotations for differences + /// \param document Document + /// \param builder Builder + void drawAnnotations(const pdf::PDFDocument* document, pdf::PDFDocumentBuilder* builder); + private: void drawRectangle(QPainter* painter, const QMatrix& pagePointToDevicePointMatrix, diff --git a/Pdf4QtLib/sources/pdfdrawspacecontroller.cpp b/Pdf4QtLib/sources/pdfdrawspacecontroller.cpp index 411609a..7f38202 100644 --- a/Pdf4QtLib/sources/pdfdrawspacecontroller.cpp +++ b/Pdf4QtLib/sources/pdfdrawspacecontroller.cpp @@ -195,7 +195,7 @@ void PDFDrawSpaceController::recalculate() QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(leftIndex)->getRotatedMediaBoxMM(), m_pageRotation).size(); PDFReal xPos = -pageSize.width() - m_horizontalSpacingMM * 0.5; QRectF rect(xPos, yPos, pageSize.width(), pageSize.height()); - m_layoutItems.emplace_back(blockIndex, leftIndex, rect); + m_layoutItems.emplace_back(blockIndex, leftIndex, -1, rect); yPosAdvance = qMax(yPosAdvance, pageSize.height()); boundingRect = boundingRect.united(rect); } @@ -205,7 +205,7 @@ void PDFDrawSpaceController::recalculate() QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(rightIndex)->getRotatedMediaBoxMM(), m_pageRotation).size(); PDFReal xPos = m_horizontalSpacingMM * 0.5; QRectF rect(xPos, yPos, pageSize.width(), pageSize.height()); - m_layoutItems.emplace_back(blockIndex, rightIndex, rect); + m_layoutItems.emplace_back(blockIndex, rightIndex, -1, rect); yPosAdvance = qMax(yPosAdvance, pageSize.height()); boundingRect = boundingRect.united(rect); } @@ -267,7 +267,7 @@ void PDFDrawSpaceController::recalculate() { QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(i)->getRotatedMediaBoxMM(), m_pageRotation).size(); QRectF rect(-pageSize.width() * 0.5, -pageSize.height() * 0.5, pageSize.width(), pageSize.height()); - m_layoutItems.emplace_back(i, i, rect); + m_layoutItems.emplace_back(i, i, -1, rect); m_blockItems.emplace_back(rect); } @@ -288,7 +288,7 @@ void PDFDrawSpaceController::recalculate() // Top of current page is at yPos. QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(i)->getRotatedMediaBoxMM(), m_pageRotation).size(); QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height()); - m_layoutItems.emplace_back(0, i, rect); + m_layoutItems.emplace_back(0, i, -1, rect); yPos += pageSize.height() + m_verticalSpacingMM; boundingRectangle = boundingRectangle.united(rect); } @@ -382,10 +382,10 @@ void PDFDrawSpaceController::recalculate() // We do not support page rotation for custom layout Q_ASSERT(m_pageRotation == PageRotation::None); - // Assure, that layout items are sorted by block + // Assure, that layout items are sorted by block and page group auto comparator = [](const LayoutItem& l, const LayoutItem& r) { - return l.blockIndex < r.blockIndex; + return std::tie(l.blockIndex, l.groupIndex) < std::tie(r.blockIndex, r.groupIndex); }; std::stable_sort(m_layoutItems.begin(), m_layoutItems.end(), comparator); @@ -566,7 +566,7 @@ void PDFDrawWidgetProxy::update() m_layout.items.reserve(items.size()); for (const PDFDrawSpaceController::LayoutItem& item : items) { - m_layout.items.emplace_back(item.pageIndex, fromDeviceSpace(item.pageRectMM).toRect()); + m_layout.items.emplace_back(item.pageIndex, item.groupIndex, fromDeviceSpace(item.pageRectMM).toRect()); } m_layout.blockRect = fromDeviceSpace(rectangle).toRect(); @@ -762,8 +762,13 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F QRect placedRect = item.pageRect.translated(m_horizontalOffset - m_layout.blockRect.left(), m_verticalOffset - m_layout.blockRect.top()); if (placedRect.intersects(rect)) { + GroupInfo groupInfo = getGroupInfo(item.groupIndex); + // Clear the page space by paper color - painter->fillRect(placedRect, paperColor); + if (groupInfo.drawPaper) + { + painter->fillRect(placedRect, paperColor); + } const PDFPrecompiledPage* compiledPage = m_compiler->getCompiledPage(item.pageIndex, true); if (compiledPage && compiledPage->isValid()) @@ -773,7 +778,7 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex); QMatrix matrix = createPagePointToDevicePointMatrix(page, placedRect) * baseMatrix; - compiledPage->draw(painter, page->getCropBox(), matrix, features); + compiledPage->draw(painter, page->getCropBox(), matrix, features, groupInfo.transparency); PDFTextLayoutGetter layoutGetter = m_textLayoutCompiler->getTextLayoutLazy(item.pageIndex); // Draw text blocks/text lines, if it is enabled @@ -1001,6 +1006,22 @@ PDFWidgetSnapshot PDFDrawWidgetProxy::getSnapshot() const return snapshot; } +void PDFDrawWidgetProxy::setGroupTransparency(PDFInteger groupIndex, bool drawPaper, PDFReal transparency) +{ + GroupInfo groupInfo; + groupInfo.drawPaper = drawPaper; + groupInfo.transparency = transparency; + + if (groupInfo == GroupInfo()) + { + m_groupInfos.erase(groupIndex); + } + else + { + m_groupInfos[groupIndex] = std::move(groupInfo); + } +} + QRect PDFDrawWidgetProxy::getPagesIntersectingRectBoundingBox(QRect rect) const { QRect resultRect; @@ -1385,6 +1406,17 @@ void PDFDrawWidgetProxy::updateVerticalScrollbarFromOffset() } } +PDFDrawWidgetProxy::GroupInfo PDFDrawWidgetProxy::getGroupInfo(int groupIndex) const +{ + auto it = m_groupInfos.find(groupIndex); + if (it != m_groupInfos.cend()) + { + return it->second; + } + + return GroupInfo(); +} + PDFWidgetAnnotationManager* PDFDrawWidgetProxy::getAnnotationManager() const { return m_widget->getAnnotationManager(); diff --git a/Pdf4QtLib/sources/pdfdrawspacecontroller.h b/Pdf4QtLib/sources/pdfdrawspacecontroller.h index b1dc8da..9f82c64 100644 --- a/Pdf4QtLib/sources/pdfdrawspacecontroller.h +++ b/Pdf4QtLib/sources/pdfdrawspacecontroller.h @@ -77,9 +77,9 @@ public: /// page and page rectangle, in which the page is contained. struct LayoutItem { - constexpr inline explicit LayoutItem() : blockIndex(-1), pageIndex(-1) { } - constexpr inline explicit LayoutItem(PDFInteger blockIndex, PDFInteger pageIndex, const QRectF& pageRectMM) : - blockIndex(blockIndex), pageIndex(pageIndex), pageRectMM(pageRectMM) { } + constexpr inline explicit LayoutItem() : blockIndex(-1), pageIndex(-1), groupIndex(-1) { } + constexpr inline explicit LayoutItem(PDFInteger blockIndex, PDFInteger pageIndex, PDFInteger groupIndex, const QRectF& pageRectMM) : + blockIndex(blockIndex), pageIndex(pageIndex), groupIndex(groupIndex), pageRectMM(pageRectMM) { } bool operator ==(const LayoutItem&) const = default; @@ -87,6 +87,7 @@ public: PDFInteger blockIndex; PDFInteger pageIndex; + PDFInteger groupIndex; ///< Page group index QRectF pageRectMM; }; @@ -371,6 +372,13 @@ public: /// Returns snapshot of current view area PDFWidgetSnapshot getSnapshot() const; + + /// Sets page group transparency settings. All pages with a given group index + /// will be displayed with this transparency settings. + /// \param groupIndex Group index + /// \param drawPaper Draw background paper + /// \param transparency Page graphics transparency + void setGroupTransparency(PDFInteger groupIndex, bool drawPaper = true, PDFReal transparency = 1.0); PDFWidgetAnnotationManager* getAnnotationManager() const; @@ -385,12 +393,13 @@ signals: private: struct LayoutItem { - constexpr inline explicit LayoutItem() : pageIndex(-1) { } - constexpr inline explicit LayoutItem(PDFInteger pageIndex, const QRect& pageRect) : - pageIndex(pageIndex), pageRect(pageRect) { } + constexpr inline explicit LayoutItem() : pageIndex(-1), groupIndex(-1) { } + constexpr inline explicit LayoutItem(PDFInteger pageIndex, PDFInteger groupIndex, const QRect& pageRect) : + pageIndex(pageIndex), groupIndex(groupIndex), pageRect(pageRect) { } PDFInteger pageIndex; + PDFInteger groupIndex; ///< Used to create group of pages (for transparency and overlay) QRect pageRect; }; @@ -406,6 +415,14 @@ private: QRect blockRect; }; + struct GroupInfo + { + bool operator==(const GroupInfo&) const = default; + + bool drawPaper = true; + PDFReal transparency = 1.0; + }; + static constexpr size_t INVALID_BLOCK_INDEX = std::numeric_limits::max(); // Minimal/maximal zoom is from 8% to 6400 %, according to the PDF 1.7 Reference, @@ -430,6 +447,8 @@ private: void updateHorizontalScrollbarFromOffset(); void updateVerticalScrollbarFromOffset(); + GroupInfo getGroupInfo(int groupIndex) const; + template struct Range { @@ -518,6 +537,11 @@ private: /// Surface format for OpenGL QSurfaceFormat m_surfaceFormat; + + /// Page group info for rendering. Group of pages + /// can be rendered with transparency or without paper + /// as overlay. + std::map m_groupInfos; }; } // namespace pdf diff --git a/Pdf4QtLib/sources/pdfpainter.cpp b/Pdf4QtLib/sources/pdfpainter.cpp index 410377a..4766416 100644 --- a/Pdf4QtLib/sources/pdfpainter.cpp +++ b/Pdf4QtLib/sources/pdfpainter.cpp @@ -501,13 +501,18 @@ void PDFPrecompiledPageGenerator::setCompositionMode(QPainter::CompositionMode m m_precompiledPage->addSetCompositionMode(mode); } -void PDFPrecompiledPage::draw(QPainter* painter, const QRectF& cropBox, const QMatrix& pagePointToDevicePointMatrix, PDFRenderer::Features features) const +void PDFPrecompiledPage::draw(QPainter* painter, + const QRectF& cropBox, + const QMatrix& pagePointToDevicePointMatrix, + PDFRenderer::Features features, + PDFReal opacity) const { Q_ASSERT(painter); Q_ASSERT(pagePointToDevicePointMatrix.isInvertible()); painter->save(); painter->setWorldMatrix(QMatrix()); + painter->setOpacity(opacity); if (features.testFlag(PDFRenderer::ClipToCropBox)) { diff --git a/Pdf4QtLib/sources/pdfpainter.h b/Pdf4QtLib/sources/pdfpainter.h index ec89813..40e2a40 100644 --- a/Pdf4QtLib/sources/pdfpainter.h +++ b/Pdf4QtLib/sources/pdfpainter.h @@ -187,7 +187,12 @@ public: /// \param cropBox Page's crop box /// \param pagePointToDevicePointMatrix Page point to device point transformation matrix /// \param features Renderer features - void draw(QPainter* painter, const QRectF& cropBox, const QMatrix& pagePointToDevicePointMatrix, PDFRenderer::Features features) const; + /// \param opacity Opacity of page graphics + void draw(QPainter* painter, + const QRectF& cropBox, + const QMatrix& pagePointToDevicePointMatrix, + PDFRenderer::Features features, + PDFReal opacity) const; /// Redact path - remove all content intersecting given path, /// and fill redact path with given color. diff --git a/Pdf4QtLib/sources/pdfredact.cpp b/Pdf4QtLib/sources/pdfredact.cpp index 866cc7e..888ed4d 100644 --- a/Pdf4QtLib/sources/pdfredact.cpp +++ b/Pdf4QtLib/sources/pdfredact.cpp @@ -106,7 +106,7 @@ PDFDocument PDFRedact::perform(Options options) QPainter* painter = contentStreamBuilder.begin(newPageReference); compiledPage.redact(redactPath, matrix, m_redactFillColor); - compiledPage.draw(painter, QRectF(), matrix, PDFRenderer::None); + compiledPage.draw(painter, QRectF(), matrix, PDFRenderer::None, 1.0); contentStreamBuilder.end(painter); } diff --git a/Pdf4QtLib/sources/pdfrenderer.cpp b/Pdf4QtLib/sources/pdfrenderer.cpp index 33af50d..0c7feda 100644 --- a/Pdf4QtLib/sources/pdfrenderer.cpp +++ b/Pdf4QtLib/sources/pdfrenderer.cpp @@ -244,7 +244,7 @@ QImage PDFRasterizer::render(PDFInteger pageIndex, QOpenGLPaintDevice device(size); QPainter painter(&device); painter.fillRect(QRect(QPoint(0, 0), size), compiledPage->getPaperColor()); - compiledPage->draw(&painter, page->getCropBox(), matrix, features); + compiledPage->draw(&painter, page->getCropBox(), matrix, features, 1.0); if (annotationManager) { @@ -276,7 +276,7 @@ QImage PDFRasterizer::render(PDFInteger pageIndex, image.fill(Qt::white); QPainter painter(&image); - compiledPage->draw(&painter, page->getCropBox(), matrix, features); + compiledPage->draw(&painter, page->getCropBox(), matrix, features, 1.0); if (annotationManager) {