mirror of https://github.com/JakubMelka/PDF4QT.git
Redacting tool
This commit is contained in:
parent
0c6903d5b8
commit
59721d7de8
|
@ -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 \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue