From 59721d7de848740d036bfce041af05efbf0b1afc Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Tue, 29 Dec 2020 18:33:25 +0100 Subject: [PATCH] Redacting tool --- Pdf4QtLib/Pdf4QtLib.pro | 2 + Pdf4QtLib/sources/pdfdocumentbuilder.cpp | 12 ++ Pdf4QtLib/sources/pdfdocumentbuilder.h | 11 +- Pdf4QtLib/sources/pdfpainter.cpp | 92 ++++++++++ Pdf4QtLib/sources/pdfpainter.h | 6 + Pdf4QtLib/sources/pdfplugin.cpp | 6 + Pdf4QtLib/sources/pdfplugin.h | 11 ++ Pdf4QtLib/sources/pdfredact.cpp | 140 +++++++++++++++ Pdf4QtLib/sources/pdfredact.h | 63 +++++++ Pdf4QtLib/sources/pdfrenderer.h | 1 + Pdf4QtViewer/pdfprogramcontroller.cpp | 6 + Pdf4QtViewer/pdfprogramcontroller.h | 4 +- .../RedactPlugin/RedactPlugin.pro | 3 + .../createredacteddocumentdialog.cpp | 122 +++++++++++++ .../createredacteddocumentdialog.h | 59 +++++++ .../createredacteddocumentdialog.ui | 164 ++++++++++++++++++ .../RedactPlugin/redactplugin.cpp | 35 +++- .../RedactPlugin/redactplugin.h | 2 + 18 files changed, 735 insertions(+), 4 deletions(-) create mode 100644 Pdf4QtLib/sources/pdfredact.cpp create mode 100644 Pdf4QtLib/sources/pdfredact.h create mode 100644 Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.cpp create mode 100644 Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.h create mode 100644 Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.ui diff --git a/Pdf4QtLib/Pdf4QtLib.pro b/Pdf4QtLib/Pdf4QtLib.pro index 5a6f865..fd3d152 100644 --- a/Pdf4QtLib/Pdf4QtLib.pro +++ b/Pdf4QtLib/Pdf4QtLib.pro @@ -74,6 +74,7 @@ SOURCES += \ sources/pdfpattern.cpp \ sources/pdfplugin.cpp \ sources/pdfprogress.cpp \ + sources/pdfredact.cpp \ sources/pdfsecurityhandler.cpp \ sources/pdfsignaturehandler.cpp \ sources/pdfsnapper.cpp \ @@ -140,6 +141,7 @@ HEADERS += \ sources/pdfpattern.h \ sources/pdfplugin.h \ sources/pdfprogress.h \ + sources/pdfredact.h \ sources/pdfsecurityhandler.h \ sources/pdfsignaturehandler.h \ sources/pdfsignaturehandler_impl.h \ diff --git a/Pdf4QtLib/sources/pdfdocumentbuilder.cpp b/Pdf4QtLib/sources/pdfdocumentbuilder.cpp index f2333fa..4249f5b 100644 --- a/Pdf4QtLib/sources/pdfdocumentbuilder.cpp +++ b/Pdf4QtLib/sources/pdfdocumentbuilder.cpp @@ -1152,6 +1152,18 @@ void PDFDocumentBuilder::updateDocumentInfo(PDFObject info) mergeTo(infoReference, info); } +void PDFDocumentBuilder::setDocumentInfo(PDFObjectReference infoReference) +{ + // Update the trailer dictionary + PDFObjectFactory objectFactory; + objectFactory.beginDictionary(); + objectFactory.beginDictionaryItem("Info"); + objectFactory << infoReference; + objectFactory.endDictionaryItem(); + objectFactory.endDictionary(); + m_storage.updateTrailerDictionary(objectFactory.takeObject()); +} + QRectF PDFDocumentBuilder::getPolygonsBoundingRect(const Polygons& polygons) const { QRectF rect; diff --git a/Pdf4QtLib/sources/pdfdocumentbuilder.h b/Pdf4QtLib/sources/pdfdocumentbuilder.h index 9b35cff..f8565b8 100644 --- a/Pdf4QtLib/sources/pdfdocumentbuilder.h +++ b/Pdf4QtLib/sources/pdfdocumentbuilder.h @@ -406,6 +406,15 @@ public: /// \param b Second 'Names' entry void mergeNames(PDFObjectReference a, PDFObjectReference b); + /// Updates document info by merging object info to actual info + void updateDocumentInfo(PDFObject info); + + /// Sets document info reference to trailer dictionary + void setDocumentInfo(PDFObjectReference infoReference); + + /// Returns document info reference + PDFObjectReference getDocumentInfo() const; + /* START GENERATED CODE */ /// Appends a new page after last page. @@ -1439,8 +1448,6 @@ private: QString getProducerString() const; PDFObjectReference getPageTreeRoot() const; PDFInteger getPageTreeRootChildCount() const; - PDFObjectReference getDocumentInfo() const; - void updateDocumentInfo(PDFObject info); QRectF getPolygonsBoundingRect(const Polygons& Polygons) const; PDFObjectReference createOutlineItem(const PDFOutlineItem* root, bool writeOutlineData); diff --git a/Pdf4QtLib/sources/pdfpainter.cpp b/Pdf4QtLib/sources/pdfpainter.cpp index f002c05..d741929 100644 --- a/Pdf4QtLib/sources/pdfpainter.cpp +++ b/Pdf4QtLib/sources/pdfpainter.cpp @@ -611,6 +611,98 @@ void PDFPrecompiledPage::draw(QPainter* painter, const QRectF& cropBox, const QM painter->restore(); } +void PDFPrecompiledPage::redact(QPainterPath redactPath, const QMatrix& matrix, QColor color) +{ + if (redactPath.isEmpty()) + { + // Nothing to be redacted + return; + } + + std::stack worldMatrixStack; + worldMatrixStack.push(matrix); + + if (color.isValid()) + { + m_instructions.insert(m_instructions.begin(), Instruction(InstructionType::SaveGraphicState, 0)); + } + + // Process all instructions + for (const Instruction& instruction : m_instructions) + { + switch (instruction.type) + { + case InstructionType::DrawPath: + { + QMatrix matrix = worldMatrixStack.top().inverted(); + QPainterPath mappedRedactPath = matrix.map(redactPath); + PathPaintData& path = m_paths[instruction.dataIndex]; + path.path = path.path.subtracted(mappedRedactPath); + break; + } + + case InstructionType::DrawImage: + { + ImageData& data = m_images[instruction.dataIndex]; + QImage& image = data.image; + + QMatrix imageTransform(1.0 / image.width(), 0, 0, 1.0 / image.height(), 0, 0); + QMatrix worldMatrix = imageTransform * worldMatrixStack.top(); + + // Jakub Melka: Because Qt uses opposite axis direction than PDF, then we must transform the y-axis + // to the opposite (so the image is then unchanged) + worldMatrix.translate(0, image.height()); + worldMatrix.scale(1, -1); + + QPainter painter(&image); + painter.setWorldMatrix(worldMatrix.inverted()); + painter.drawPath(redactPath); + painter.end(); + break; + } + + case InstructionType::DrawMesh: + // We do not redact mesh + break; + + case InstructionType::Clip: + { + QMatrix matrix = worldMatrixStack.top().inverted(); + QPainterPath mappedRedactPath = matrix.map(redactPath); + m_clips[instruction.dataIndex].clipPath = m_clips[instruction.dataIndex].clipPath.subtracted(mappedRedactPath); + break; + } + + case InstructionType::SaveGraphicState: + worldMatrixStack.push(worldMatrixStack.top()); + break; + + case InstructionType::RestoreGraphicState: + worldMatrixStack.pop(); + break; + + case InstructionType::SetWorldMatrix: + worldMatrixStack.top() = m_matrices[instruction.dataIndex]; + break; + + case InstructionType::SetCompositionMode: + break; + + default: + { + Q_ASSERT(false); + break; + } + } + } + + if (color.isValid()) + { + addRestoreGraphicState(); + addPath(Qt::NoPen, QBrush(color), matrix.map(redactPath), false); + } +} + void PDFPrecompiledPage::addPath(QPen pen, QBrush brush, QPainterPath path, bool isText) { m_instructions.emplace_back(InstructionType::DrawPath, m_paths.size()); diff --git a/Pdf4QtLib/sources/pdfpainter.h b/Pdf4QtLib/sources/pdfpainter.h index 6d4cf8c..2aeab63 100644 --- a/Pdf4QtLib/sources/pdfpainter.h +++ b/Pdf4QtLib/sources/pdfpainter.h @@ -189,6 +189,12 @@ public: /// \param features Renderer features void draw(QPainter* painter, const QRectF& cropBox, const QMatrix& pagePointToDevicePointMatrix, PDFRenderer::Features features) const; + /// Redact path - remove all content intersecting given path, + /// and fill redact path with given color. + /// \param redactPath Redaction path in page coordinates + /// \param color Redaction color (if invalid, nothing is being drawn) + void redact(QPainterPath redactPath, const QMatrix& matrix, QColor color); + void addPath(QPen pen, QBrush brush, QPainterPath path, bool isText); void addClip(QPainterPath path); void addImage(QImage image); diff --git a/Pdf4QtLib/sources/pdfplugin.cpp b/Pdf4QtLib/sources/pdfplugin.cpp index 9531062..1ef2964 100644 --- a/Pdf4QtLib/sources/pdfplugin.cpp +++ b/Pdf4QtLib/sources/pdfplugin.cpp @@ -22,6 +22,7 @@ namespace pdf PDFPlugin::PDFPlugin(QObject* parent) : QObject(parent), + m_dataExchangeInterface(nullptr), m_widget(nullptr), m_cmsManager(nullptr), m_document(nullptr) @@ -29,6 +30,11 @@ PDFPlugin::PDFPlugin(QObject* parent) : } +void PDFPlugin::setDataExchangeInterface(IPluginDataExchange* dataExchangeInterface) +{ + m_dataExchangeInterface = dataExchangeInterface; +} + void PDFPlugin::setWidget(PDFWidget* widget) { m_widget = widget; diff --git a/Pdf4QtLib/sources/pdfplugin.h b/Pdf4QtLib/sources/pdfplugin.h index 8544933..dd8a21e 100644 --- a/Pdf4QtLib/sources/pdfplugin.h +++ b/Pdf4QtLib/sources/pdfplugin.h @@ -44,6 +44,15 @@ struct Pdf4QtLIBSHARED_EXPORT PDFPluginInfo }; using PDFPluginInfos = std::vector; +class IPluginDataExchange +{ +public: + explicit IPluginDataExchange() = default; + virtual ~IPluginDataExchange() = default; + + virtual QString getOriginalFileName() const = 0; +}; + class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject { Q_OBJECT @@ -51,12 +60,14 @@ class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject public: explicit PDFPlugin(QObject* parent); + virtual void setDataExchangeInterface(IPluginDataExchange* dataExchangeInterface); virtual void setWidget(PDFWidget* widget); virtual void setCMSManager(PDFCMSManager* manager); virtual void setDocument(const PDFModifiedDocument& document); virtual std::vector getActions() const; protected: + IPluginDataExchange* m_dataExchangeInterface; PDFWidget* m_widget; PDFCMSManager* m_cmsManager; PDFDocument* m_document; diff --git a/Pdf4QtLib/sources/pdfredact.cpp b/Pdf4QtLib/sources/pdfredact.cpp new file mode 100644 index 0000000..6661c08 --- /dev/null +++ b/Pdf4QtLib/sources/pdfredact.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2020 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 +// (at your option) 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 . + +#include "pdfredact.h" +#include "pdfpainter.h" +#include "pdfdocumentbuilder.h" + +namespace pdf +{ + +PDFRedact::PDFRedact(const PDFDocument* document, + const PDFFontCache* fontCache, + const PDFCMS* cms, + const PDFOptionalContentActivity* optionalContentActivity, + const PDFMeshQualitySettings* meshQualitySettings, + QColor redactFillColor) : + m_document(document), + m_fontCache(fontCache), + m_cms(cms), + m_optionalContentActivity(optionalContentActivity), + m_meshQualitySettings(meshQualitySettings), + m_redactFillColor(redactFillColor) +{ + +} + +PDFDocument PDFRedact::perform(Options options) +{ + PDFDocumentBuilder builder; + builder.createDocument(); + + PDFRenderer renderer(m_document, + m_fontCache, + m_cms, + m_optionalContentActivity, + PDFRenderer::None, + *m_meshQualitySettings); + + for (size_t i = 0; i < m_document->getCatalog()->getPageCount(); ++i) + { + const PDFPage* page = m_document->getCatalog()->getPage(i); + + PDFPrecompiledPage compiledPage; + renderer.compile(&compiledPage, i); + + PDFObjectReference newPageReference = builder.appendPage(page->getMediaBox()); + + if (!page->getCropBox().isEmpty()) + { + builder.setPageCropBox(newPageReference, page->getCropBox()); + } + if (!page->getBleedBox().isEmpty()) + { + builder.setPageBleedBox(newPageReference, page->getBleedBox()); + } + if (!page->getTrimBox().isEmpty()) + { + builder.setPageTrimBox(newPageReference, page->getTrimBox()); + } + if (!page->getArtBox().isEmpty()) + { + builder.setPageArtBox(newPageReference, page->getArtBox()); + } + + // TODO: Nastavit natoceni stranky + // TODO: Popisek redakce anotace, Overlay text + // TODO: Redact searched text + // TODO: Duplikace redakce na vice stranek + + PDFPageContentStreamBuilder contentStreamBuilder(&builder); + + QPainterPath redactPath; + + for (const PDFObjectReference& annotationReference : page->getAnnotations()) + { + PDFAnnotationPtr annotation = PDFAnnotation::parse(&m_document->getStorage(), annotationReference); + if (!annotation || annotation->getType() != AnnotationType::Redact) + { + continue; + } + + // We have redact annotation here + const PDFRedactAnnotation* redactAnnotation = dynamic_cast(annotation.get()); + Q_ASSERT(redactAnnotation); + + redactPath.addPath(redactAnnotation->getRedactionRegion().getPath()); + } + + QMatrix matrix; + matrix.translate(0, page->getMediaBox().height()); + matrix.scale(1.0, -1.0); + + QPainter* painter = contentStreamBuilder.begin(newPageReference); + compiledPage.redact(redactPath, matrix, m_redactFillColor); + compiledPage.draw(painter, QRectF(), matrix, PDFRenderer::None); + contentStreamBuilder.end(painter); + } + + if (options.testFlag(CopyTitle)) + { + builder.setDocumentTitle(m_document->getInfo()->title); + } + + if (options.testFlag(CopyMetadata)) + { + PDFObject info = m_document->getTrailerDictionary()->get("Info"); + if (!info.isNull()) + { + std::vector copiedObjects = builder.copyFrom({ info }, m_document->getStorage(), true); + if (copiedObjects.size() == 1 && copiedObjects.front().isReference()) + { + builder.setDocumentInfo(copiedObjects.front().getReference()); + } + } + } + + if (options.testFlag(CopyOutline)) + { + builder.setOutline(m_document->getCatalog()->getOutlineRootPtr().data()); + } + + return builder.build(); +} + + +} // namespace pdf diff --git a/Pdf4QtLib/sources/pdfredact.h b/Pdf4QtLib/sources/pdfredact.h new file mode 100644 index 0000000..52c0cd0 --- /dev/null +++ b/Pdf4QtLib/sources/pdfredact.h @@ -0,0 +1,63 @@ +// Copyright (C) 2020 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 +// (at your option) 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 . + +#ifndef PDFREDACT_H +#define PDFREDACT_H + +#include "pdfdocument.h" +#include "pdfrenderer.h" + +namespace pdf +{ + +/// Create redacted document from the document, which have redact annotations. +/// Redacted document has removed content marked by these annotations, and +/// annotations themselfs are removed. +class Pdf4QtLIBSHARED_EXPORT PDFRedact +{ +public: + explicit PDFRedact(const PDFDocument* document, + const PDFFontCache* fontCache, + const PDFCMS* cms, + const PDFOptionalContentActivity* optionalContentActivity, + const PDFMeshQualitySettings* meshQualitySettings, + QColor redactFillColor); + + enum Option + { + None = 0x0000, + CopyTitle = 0x0001, + CopyMetadata = 0x0002, + CopyOutline = 0x0004 + }; + Q_DECLARE_FLAGS(Options, Option) + + + pdf::PDFDocument perform(Options options); + +private: + const PDFDocument* m_document; + const PDFFontCache* m_fontCache; + const PDFCMS* m_cms; + const PDFOptionalContentActivity* m_optionalContentActivity; + const PDFMeshQualitySettings* m_meshQualitySettings; + QColor m_redactFillColor; +}; + +} // namespace pdf + +#endif // PDFREDACT_H diff --git a/Pdf4QtLib/sources/pdfrenderer.h b/Pdf4QtLib/sources/pdfrenderer.h index 60db5e8..e5d6d1f 100644 --- a/Pdf4QtLib/sources/pdfrenderer.h +++ b/Pdf4QtLib/sources/pdfrenderer.h @@ -50,6 +50,7 @@ public: enum Feature { + None = 0x0000, Antialiasing = 0x0001, ///< Antialiasing for lines, shapes, etc. TextAntialiasing = 0x0002, ///< Antialiasing for drawing text SmoothImages = 0x0004, ///< Adjust images to the device space using smooth transformation (slower, but better image quality) diff --git a/Pdf4QtViewer/pdfprogramcontroller.cpp b/Pdf4QtViewer/pdfprogramcontroller.cpp index 86eee2a..5ae5811 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.cpp +++ b/Pdf4QtViewer/pdfprogramcontroller.cpp @@ -1047,6 +1047,11 @@ bool PDFProgramController::canClose() const return !(m_futureWatcher && m_futureWatcher->isRunning()) || !m_isBusy; } +QString PDFProgramController::getOriginalFileName() const +{ + return m_fileInfo.originalFileName; +} + void PDFProgramController::onActionRotateRightTriggered() { m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateRight); @@ -1690,6 +1695,7 @@ void PDFProgramController::loadPlugins() for (const auto& plugin : m_loadedPlugins) { + plugin.second->setDataExchangeInterface(this); plugin.second->setWidget(m_pdfWidget); plugin.second->setCMSManager(m_CMSManager); std::vector actions = plugin.second->getActions(); diff --git a/Pdf4QtViewer/pdfprogramcontroller.h b/Pdf4QtViewer/pdfprogramcontroller.h index 3bf687e..dae6b46 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.h +++ b/Pdf4QtViewer/pdfprogramcontroller.h @@ -223,7 +223,7 @@ private: std::vector m_additionalActions; }; -class Pdf4QtVIEWERLIBSHARED_EXPORT PDFProgramController : public QObject +class Pdf4QtVIEWERLIBSHARED_EXPORT PDFProgramController : public QObject, public pdf::IPluginDataExchange { Q_OBJECT @@ -279,6 +279,8 @@ public: bool canClose() const; + virtual QString getOriginalFileName() const override; + signals: void queryPasswordRequest(QString* password, bool* ok); diff --git a/Pdf4QtViewerPlugins/RedactPlugin/RedactPlugin.pro b/Pdf4QtViewerPlugins/RedactPlugin/RedactPlugin.pro index 295805a..c03032a 100644 --- a/Pdf4QtViewerPlugins/RedactPlugin/RedactPlugin.pro +++ b/Pdf4QtViewerPlugins/RedactPlugin/RedactPlugin.pro @@ -33,10 +33,12 @@ DESTDIR = $$OUT_PWD/../../pdfplugins CONFIG += c++11 SOURCES += \ + createredacteddocumentdialog.cpp \ redactplugin.cpp \ selectpagestoredactdialog.cpp HEADERS += \ + createredacteddocumentdialog.h \ redactplugin.h \ selectpagestoredactdialog.h @@ -49,6 +51,7 @@ RESOURCES += \ icons.qrc FORMS += \ + createredacteddocumentdialog.ui \ selectpagestoredactdialog.ui diff --git a/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.cpp b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.cpp new file mode 100644 index 0000000..2e20ede --- /dev/null +++ b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2020 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 +// (at your option) 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 . + +#include "createredacteddocumentdialog.h" +#include "ui_createredacteddocumentdialog.h" + +#include +#include + +#include "pdfwidgetutils.h" + +namespace pdfplugin +{ + +CreateRedactedDocumentDialog::CreateRedactedDocumentDialog(QString fileName, QColor fillColor, QWidget* parent) : + QDialog(parent), + ui(new Ui::CreateRedactedDocumentDialog) +{ + ui->setupUi(this); + ui->fileNameEdit->setText(fileName); + ui->fillRedactedAreaColorEdit->setText(fillColor.name(QColor::HexRgb)); + + connect(ui->copyMetadataCheckBox, &QCheckBox::clicked, this, &CreateRedactedDocumentDialog::updateUi); + + updateUi(); + setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, 300)); +} + +CreateRedactedDocumentDialog::~CreateRedactedDocumentDialog() +{ + delete ui; +} + +QString CreateRedactedDocumentDialog::getFileName() const +{ + return ui->fileNameEdit->text(); +} + +QColor CreateRedactedDocumentDialog::getRedactColor() const +{ + QColor color; + + if (ui->fillRedactedAreaCheckBox->isChecked()) + { + color.setNamedColor(ui->fillRedactedAreaColorEdit->text()); + } + + return color; +} + +bool CreateRedactedDocumentDialog::isCopyingTitle() const +{ + return ui->copyTitleCheckBox->isChecked(); +} + +bool CreateRedactedDocumentDialog::isCopyingMetadata() const +{ + return ui->copyMetadataCheckBox->isChecked(); +} + +bool CreateRedactedDocumentDialog::isCopyingOutline() const +{ + return ui->copyOutlineCheckBox->isChecked(); +} + +void CreateRedactedDocumentDialog::on_selectDirectoryButton_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, tr("File Name"), ui->fileNameEdit->text()); + if (!fileName.isEmpty()) + { + ui->fileNameEdit->setText(fileName); + } +} + +void CreateRedactedDocumentDialog::updateUi() +{ + if (ui->copyMetadataCheckBox->isChecked()) + { + ui->copyTitleCheckBox->setChecked(true); + ui->copyTitleCheckBox->setEnabled(false); + } + else + { + ui->copyTitleCheckBox->setEnabled(true); + } + + ui->fillRedactedAreaColorEdit->setEnabled(ui->fillRedactedAreaCheckBox->isChecked()); +} + +void CreateRedactedDocumentDialog::accept() +{ + if (ui->fillRedactedAreaCheckBox->isChecked()) + { + QColor color; + color.setNamedColor(ui->fillRedactedAreaColorEdit->text()); + if (!color.isValid()) + { + QMessageBox::critical(this, tr("Error"), tr("Cannot convert '%1' to color value.").arg(ui->fillRedactedAreaColorEdit->text())); + return; + } + } + + QDialog::accept(); +} + +} // namespace pdfplugin + + diff --git a/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.h b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.h new file mode 100644 index 0000000..373203e --- /dev/null +++ b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.h @@ -0,0 +1,59 @@ +// Copyright (C) 2020 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 +// (at your option) 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 . + +#ifndef CREATEREDACTEDDOCUMENTDIALOG_H +#define CREATEREDACTEDDOCUMENTDIALOG_H + +#include + +namespace Ui +{ +class CreateRedactedDocumentDialog; +} + +namespace pdfplugin +{ + +class CreateRedactedDocumentDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CreateRedactedDocumentDialog(QString fileName, QColor fillColor, QWidget* parent); + virtual ~CreateRedactedDocumentDialog() override; + + virtual void accept() override; + + QString getFileName() const; + QColor getRedactColor() const; + + bool isCopyingTitle() const; + bool isCopyingMetadata() const; + bool isCopyingOutline() const; + +private slots: + void on_selectDirectoryButton_clicked(); + +private: + void updateUi(); + + Ui::CreateRedactedDocumentDialog* ui; +}; + +} // namespace pdfplugin + +#endif // CREATEREDACTEDDOCUMENTDIALOG_H diff --git a/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.ui b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.ui new file mode 100644 index 0000000..e0a3205 --- /dev/null +++ b/Pdf4QtViewerPlugins/RedactPlugin/createredacteddocumentdialog.ui @@ -0,0 +1,164 @@ + + + CreateRedactedDocumentDialog + + + + 0 + 0 + 631 + 329 + + + + Create Redacted Document + + + + + + Redacted document + + + + + + Output file name + + + + + + + + + + ... + + + + + + + + + + Appearance + + + + + + Fill redacted area with color: + + + true + + + + + + + + + + + + + Options + + + + + + Copy document title into redacted document + + + true + + + + + + + Copy document metadata into redacted document + + + true + + + + + + + Copy outline into redacted document + + + false + + + + + + + Qt::Vertical + + + + 20 + 26 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + CreateRedactedDocumentDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CreateRedactedDocumentDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.cpp b/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.cpp index d1eb828..a491efc 100644 --- a/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.cpp +++ b/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Jakub Melka +// Copyright (C) 2020 Jakub Melka // // This file is part of Pdf4Qt. // @@ -17,10 +17,13 @@ #include "redactplugin.h" #include "selectpagestoredactdialog.h" +#include "createredacteddocumentdialog.h" #include "pdfdrawwidget.h" #include "pdfadvancedtools.h" #include "pdfdocumentbuilder.h" +#include "pdfredact.h" +#include "pdfdocumentwriter.h" #include @@ -124,7 +127,37 @@ void RedactPlugin::onRedactPageTriggered() void RedactPlugin::onCreateRedactedDocumentTriggered() { + CreateRedactedDocumentDialog dialog(getRedactedFileName(), Qt::black, m_widget); + if (dialog.exec() == QDialog::Accepted) + { + pdf::PDFCMSPointer cms = m_widget->getCMSManager()->getCurrentCMS(); + pdf::PDFRedact redactProcessor(m_document, + m_widget->getDrawWidgetProxy()->getFontCache(), + cms.data(), + m_widget->getDrawWidgetProxy()->getOptionalContentActivity(), + &m_widget->getDrawWidgetProxy()->getMeshQualitySettings(), + dialog.getRedactColor()); + pdf::PDFRedact::Options options; + options.setFlag(pdf::PDFRedact::CopyTitle, dialog.isCopyingTitle()); + options.setFlag(pdf::PDFRedact::CopyMetadata, dialog.isCopyingMetadata()); + options.setFlag(pdf::PDFRedact::CopyOutline, dialog.isCopyingOutline()); + + pdf::PDFDocument redactedDocument = redactProcessor.perform(options); + pdf::PDFDocumentWriter writer(m_widget->getDrawWidgetProxy()->getProgress()); + pdf::PDFOperationResult result = writer.write(dialog.getFileName(), &redactedDocument, false); + if (!result) + { + + } + } +} + +QString RedactPlugin::getRedactedFileName() const +{ + QFileInfo fileInfo(m_dataExchangeInterface->getOriginalFileName()); + + return fileInfo.path() + "/" + fileInfo.baseName() + "_REDACTED.pdf"; } } diff --git a/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.h b/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.h index 18445f3..b65ec7b 100644 --- a/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.h +++ b/Pdf4QtViewerPlugins/RedactPlugin/redactplugin.h @@ -46,6 +46,8 @@ private: void onRedactPageTriggered(); void onCreateRedactedDocumentTriggered(); + QString getRedactedFileName() const; + QAction* m_actionRedactRectangle; QAction* m_actionRedactText; QAction* m_actionRedactPage;