Redacting tool

This commit is contained in:
Jakub Melka 2020-12-29 18:33:25 +01:00
parent 0c6903d5b8
commit 59721d7de8
18 changed files with 735 additions and 4 deletions

View File

@ -74,6 +74,7 @@ SOURCES += \
sources/pdfpattern.cpp \ sources/pdfpattern.cpp \
sources/pdfplugin.cpp \ sources/pdfplugin.cpp \
sources/pdfprogress.cpp \ sources/pdfprogress.cpp \
sources/pdfredact.cpp \
sources/pdfsecurityhandler.cpp \ sources/pdfsecurityhandler.cpp \
sources/pdfsignaturehandler.cpp \ sources/pdfsignaturehandler.cpp \
sources/pdfsnapper.cpp \ sources/pdfsnapper.cpp \
@ -140,6 +141,7 @@ HEADERS += \
sources/pdfpattern.h \ sources/pdfpattern.h \
sources/pdfplugin.h \ sources/pdfplugin.h \
sources/pdfprogress.h \ sources/pdfprogress.h \
sources/pdfredact.h \
sources/pdfsecurityhandler.h \ sources/pdfsecurityhandler.h \
sources/pdfsignaturehandler.h \ sources/pdfsignaturehandler.h \
sources/pdfsignaturehandler_impl.h \ sources/pdfsignaturehandler_impl.h \

View File

@ -1152,6 +1152,18 @@ void PDFDocumentBuilder::updateDocumentInfo(PDFObject info)
mergeTo(infoReference, 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 PDFDocumentBuilder::getPolygonsBoundingRect(const Polygons& polygons) const
{ {
QRectF rect; QRectF rect;

View File

@ -406,6 +406,15 @@ public:
/// \param b Second 'Names' entry /// \param b Second 'Names' entry
void mergeNames(PDFObjectReference a, PDFObjectReference b); 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 */ /* START GENERATED CODE */
/// Appends a new page after last page. /// Appends a new page after last page.
@ -1439,8 +1448,6 @@ private:
QString getProducerString() const; QString getProducerString() const;
PDFObjectReference getPageTreeRoot() const; PDFObjectReference getPageTreeRoot() const;
PDFInteger getPageTreeRootChildCount() const; PDFInteger getPageTreeRootChildCount() const;
PDFObjectReference getDocumentInfo() const;
void updateDocumentInfo(PDFObject info);
QRectF getPolygonsBoundingRect(const Polygons& Polygons) const; QRectF getPolygonsBoundingRect(const Polygons& Polygons) const;
PDFObjectReference createOutlineItem(const PDFOutlineItem* root, bool writeOutlineData); PDFObjectReference createOutlineItem(const PDFOutlineItem* root, bool writeOutlineData);

View File

@ -611,6 +611,98 @@ void PDFPrecompiledPage::draw(QPainter* painter, const QRectF& cropBox, const QM
painter->restore(); painter->restore();
} }
void PDFPrecompiledPage::redact(QPainterPath redactPath, const QMatrix& matrix, QColor color)
{
if (redactPath.isEmpty())
{
// Nothing to be redacted
return;
}
std::stack<QMatrix> 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) void PDFPrecompiledPage::addPath(QPen pen, QBrush brush, QPainterPath path, bool isText)
{ {
m_instructions.emplace_back(InstructionType::DrawPath, m_paths.size()); m_instructions.emplace_back(InstructionType::DrawPath, m_paths.size());

View File

@ -189,6 +189,12 @@ public:
/// \param features Renderer features /// \param features Renderer features
void draw(QPainter* painter, const QRectF& cropBox, const QMatrix& pagePointToDevicePointMatrix, PDFRenderer::Features features) const; 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 addPath(QPen pen, QBrush brush, QPainterPath path, bool isText);
void addClip(QPainterPath path); void addClip(QPainterPath path);
void addImage(QImage image); void addImage(QImage image);

View File

@ -22,6 +22,7 @@ namespace pdf
PDFPlugin::PDFPlugin(QObject* parent) : PDFPlugin::PDFPlugin(QObject* parent) :
QObject(parent), QObject(parent),
m_dataExchangeInterface(nullptr),
m_widget(nullptr), m_widget(nullptr),
m_cmsManager(nullptr), m_cmsManager(nullptr),
m_document(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) void PDFPlugin::setWidget(PDFWidget* widget)
{ {
m_widget = widget; m_widget = widget;

View File

@ -44,6 +44,15 @@ struct Pdf4QtLIBSHARED_EXPORT PDFPluginInfo
}; };
using PDFPluginInfos = std::vector<PDFPluginInfo>; using PDFPluginInfos = std::vector<PDFPluginInfo>;
class IPluginDataExchange
{
public:
explicit IPluginDataExchange() = default;
virtual ~IPluginDataExchange() = default;
virtual QString getOriginalFileName() const = 0;
};
class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -51,12 +60,14 @@ class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject
public: public:
explicit PDFPlugin(QObject* parent); explicit PDFPlugin(QObject* parent);
virtual void setDataExchangeInterface(IPluginDataExchange* dataExchangeInterface);
virtual void setWidget(PDFWidget* widget); virtual void setWidget(PDFWidget* widget);
virtual void setCMSManager(PDFCMSManager* manager); virtual void setCMSManager(PDFCMSManager* manager);
virtual void setDocument(const PDFModifiedDocument& document); virtual void setDocument(const PDFModifiedDocument& document);
virtual std::vector<QAction*> getActions() const; virtual std::vector<QAction*> getActions() const;
protected: protected:
IPluginDataExchange* m_dataExchangeInterface;
PDFWidget* m_widget; PDFWidget* m_widget;
PDFCMSManager* m_cmsManager; PDFCMSManager* m_cmsManager;
PDFDocument* m_document; PDFDocument* m_document;

View File

@ -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 <https://www.gnu.org/licenses/>.
#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<const PDFRedactAnnotation*>(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<PDFObject> 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

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -50,6 +50,7 @@ public:
enum Feature enum Feature
{ {
None = 0x0000,
Antialiasing = 0x0001, ///< Antialiasing for lines, shapes, etc. Antialiasing = 0x0001, ///< Antialiasing for lines, shapes, etc.
TextAntialiasing = 0x0002, ///< Antialiasing for drawing text TextAntialiasing = 0x0002, ///< Antialiasing for drawing text
SmoothImages = 0x0004, ///< Adjust images to the device space using smooth transformation (slower, but better image quality) SmoothImages = 0x0004, ///< Adjust images to the device space using smooth transformation (slower, but better image quality)

View File

@ -1047,6 +1047,11 @@ bool PDFProgramController::canClose() const
return !(m_futureWatcher && m_futureWatcher->isRunning()) || !m_isBusy; return !(m_futureWatcher && m_futureWatcher->isRunning()) || !m_isBusy;
} }
QString PDFProgramController::getOriginalFileName() const
{
return m_fileInfo.originalFileName;
}
void PDFProgramController::onActionRotateRightTriggered() void PDFProgramController::onActionRotateRightTriggered()
{ {
m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateRight); m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateRight);
@ -1690,6 +1695,7 @@ void PDFProgramController::loadPlugins()
for (const auto& plugin : m_loadedPlugins) for (const auto& plugin : m_loadedPlugins)
{ {
plugin.second->setDataExchangeInterface(this);
plugin.second->setWidget(m_pdfWidget); plugin.second->setWidget(m_pdfWidget);
plugin.second->setCMSManager(m_CMSManager); plugin.second->setCMSManager(m_CMSManager);
std::vector<QAction*> actions = plugin.second->getActions(); std::vector<QAction*> actions = plugin.second->getActions();

View File

@ -223,7 +223,7 @@ private:
std::vector<QAction*> m_additionalActions; std::vector<QAction*> m_additionalActions;
}; };
class Pdf4QtVIEWERLIBSHARED_EXPORT PDFProgramController : public QObject class Pdf4QtVIEWERLIBSHARED_EXPORT PDFProgramController : public QObject, public pdf::IPluginDataExchange
{ {
Q_OBJECT Q_OBJECT
@ -279,6 +279,8 @@ public:
bool canClose() const; bool canClose() const;
virtual QString getOriginalFileName() const override;
signals: signals:
void queryPasswordRequest(QString* password, bool* ok); void queryPasswordRequest(QString* password, bool* ok);

View File

@ -33,10 +33,12 @@ DESTDIR = $$OUT_PWD/../../pdfplugins
CONFIG += c++11 CONFIG += c++11
SOURCES += \ SOURCES += \
createredacteddocumentdialog.cpp \
redactplugin.cpp \ redactplugin.cpp \
selectpagestoredactdialog.cpp selectpagestoredactdialog.cpp
HEADERS += \ HEADERS += \
createredacteddocumentdialog.h \
redactplugin.h \ redactplugin.h \
selectpagestoredactdialog.h selectpagestoredactdialog.h
@ -49,6 +51,7 @@ RESOURCES += \
icons.qrc icons.qrc
FORMS += \ FORMS += \
createredacteddocumentdialog.ui \
selectpagestoredactdialog.ui selectpagestoredactdialog.ui

View File

@ -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 <https://www.gnu.org/licenses/>.
#include "createredacteddocumentdialog.h"
#include "ui_createredacteddocumentdialog.h"
#include <QFileDialog>
#include <QMessageBox>
#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

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef CREATEREDACTEDDOCUMENTDIALOG_H
#define CREATEREDACTEDDOCUMENTDIALOG_H
#include <QDialog>
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

View File

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateRedactedDocumentDialog</class>
<widget class="QDialog" name="CreateRedactedDocumentDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>631</width>
<height>329</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Redacted Document</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="redactedDocumentGroupBox">
<property name="title">
<string>Redacted document</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="redactedDocumentLabel">
<property name="text">
<string>Output file name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fileNameEdit"/>
</item>
<item>
<widget class="QToolButton" name="selectDirectoryButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="appearanceGroupBox">
<property name="title">
<string>Appearance</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="fillRedactedAreaCheckBox">
<property name="text">
<string>Fill redacted area with color:</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fillRedactedAreaColorEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="optionsGroupBox">
<property name="title">
<string>Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="copyTitleCheckBox">
<property name="text">
<string>Copy document title into redacted document</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="copyMetadataCheckBox">
<property name="text">
<string>Copy document metadata into redacted document</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="copyOutlineCheckBox">
<property name="text">
<string>Copy outline into redacted document</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>26</height>
</size>
</property>
</spacer>
</item>
</layout>
</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>CreateRedactedDocumentDialog</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>CreateRedactedDocumentDialog</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>

View File

@ -1,4 +1,4 @@
// Copyright (C) 2020 Jakub Melka // Copyright (C) 2020 Jakub Melka
// //
// This file is part of Pdf4Qt. // This file is part of Pdf4Qt.
// //
@ -17,10 +17,13 @@
#include "redactplugin.h" #include "redactplugin.h"
#include "selectpagestoredactdialog.h" #include "selectpagestoredactdialog.h"
#include "createredacteddocumentdialog.h"
#include "pdfdrawwidget.h" #include "pdfdrawwidget.h"
#include "pdfadvancedtools.h" #include "pdfadvancedtools.h"
#include "pdfdocumentbuilder.h" #include "pdfdocumentbuilder.h"
#include "pdfredact.h"
#include "pdfdocumentwriter.h"
#include <QAction> #include <QAction>
@ -124,7 +127,37 @@ void RedactPlugin::onRedactPageTriggered()
void RedactPlugin::onCreateRedactedDocumentTriggered() 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";
} }
} }

View File

@ -46,6 +46,8 @@ private:
void onRedactPageTriggered(); void onRedactPageTriggered();
void onCreateRedactedDocumentTriggered(); void onCreateRedactedDocumentTriggered();
QString getRedactedFileName() const;
QAction* m_actionRedactRectangle; QAction* m_actionRedactRectangle;
QAction* m_actionRedactText; QAction* m_actionRedactText;
QAction* m_actionRedactPage; QAction* m_actionRedactPage;