mirror of https://github.com/JakubMelka/PDF4QT.git
Redact text search result
This commit is contained in:
parent
19dd761f35
commit
00e67ec2b1
|
@ -19,6 +19,7 @@
|
|||
#define PDFPLUGIN_H
|
||||
|
||||
#include "pdfdocument.h"
|
||||
#include "pdftextlayout.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonObject>
|
||||
|
@ -51,6 +52,7 @@ public:
|
|||
virtual ~IPluginDataExchange() = default;
|
||||
|
||||
virtual QString getOriginalFileName() const = 0;
|
||||
virtual pdf::PDFTextSelection getSelectedText() const = 0;
|
||||
};
|
||||
|
||||
class Pdf4QtLIBSHARED_EXPORT PDFPlugin : public QObject
|
||||
|
|
|
@ -78,8 +78,6 @@ PDFDocument PDFRedact::perform(Options options)
|
|||
}
|
||||
builder.setPageRotation(newPageReference, page->getPageRotation());
|
||||
|
||||
// TODO: Redact searched text
|
||||
|
||||
PDFPageContentStreamBuilder contentStreamBuilder(&builder);
|
||||
|
||||
QPainterPath redactPath;
|
||||
|
|
|
@ -66,6 +66,30 @@ void PDFAdvancedFindWidget::setDocument(const pdf::PDFModifiedDocument& document
|
|||
}
|
||||
}
|
||||
|
||||
pdf::PDFTextSelection PDFAdvancedFindWidget::getSelectedText() const
|
||||
{
|
||||
pdf::PDFTextSelection result;
|
||||
|
||||
std::vector<size_t> selectedRowIndices;
|
||||
QModelIndexList selectedRows = ui->resultsTableWidget->selectionModel()->selectedRows();
|
||||
std::transform(selectedRows.cbegin(), selectedRows.cend(), std::back_inserter(selectedRowIndices), [] (const QModelIndex& index) { return index.row(); });
|
||||
std::sort(selectedRowIndices.begin(), selectedRowIndices.end());
|
||||
|
||||
for (size_t i = 0; i < m_findResults.size(); ++i)
|
||||
{
|
||||
const pdf::PDFFindResult& findResult = m_findResults[i];
|
||||
|
||||
QColor color(Qt::yellow);
|
||||
if (std::binary_search(selectedRowIndices.cbegin(), selectedRowIndices.cend(), i))
|
||||
{
|
||||
result.addItems(findResult.textSelectionItems, color);
|
||||
}
|
||||
}
|
||||
result.build();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFAdvancedFindWidget::on_searchButton_clicked()
|
||||
{
|
||||
m_parameters.phrase = ui->searchPhraseEdit->text();
|
||||
|
|
|
@ -58,6 +58,10 @@ public:
|
|||
|
||||
void setDocument(const pdf::PDFModifiedDocument& document);
|
||||
|
||||
/// Returns selected text items in the table (selected means not all results,
|
||||
/// but those, which are selected rows in the result table)
|
||||
pdf::PDFTextSelection getSelectedText() const;
|
||||
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent* event) override;
|
||||
virtual void hideEvent(QHideEvent* event) override;
|
||||
|
|
|
@ -1052,6 +1052,11 @@ QString PDFProgramController::getOriginalFileName() const
|
|||
return m_fileInfo.originalFileName;
|
||||
}
|
||||
|
||||
pdf::PDFTextSelection PDFProgramController::getSelectedText() const
|
||||
{
|
||||
return m_mainWindowInterface->getSelectedText();
|
||||
}
|
||||
|
||||
void PDFProgramController::onActionRotateRightTriggered()
|
||||
{
|
||||
m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateRight);
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
virtual void setStatusBarMessage(QString message, int time) = 0;
|
||||
virtual void setDocument(const pdf::PDFModifiedDocument& document) = 0;
|
||||
virtual void adjustToolbar(QToolBar* toolbar) = 0;
|
||||
virtual pdf::PDFTextSelection getSelectedText() const = 0;
|
||||
};
|
||||
|
||||
class Pdf4QtVIEWERLIBSHARED_EXPORT PDFActionManager : public QObject
|
||||
|
@ -280,6 +281,7 @@ public:
|
|||
bool canClose() const;
|
||||
|
||||
virtual QString getOriginalFileName() const override;
|
||||
virtual pdf::PDFTextSelection getSelectedText() const override;
|
||||
|
||||
signals:
|
||||
void queryPasswordRequest(QString* password, bool* ok);
|
||||
|
|
|
@ -468,6 +468,16 @@ void PDFViewerMainWindow::adjustToolbar(QToolBar* toolbar)
|
|||
toolbar->setIconSize(iconSize);
|
||||
}
|
||||
|
||||
pdf::PDFTextSelection PDFViewerMainWindow::getSelectedText() const
|
||||
{
|
||||
if (!m_advancedFindWidget)
|
||||
{
|
||||
return pdf::PDFTextSelection();
|
||||
}
|
||||
|
||||
return m_advancedFindWidget->getSelectedText();
|
||||
}
|
||||
|
||||
void PDFViewerMainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!m_programController->canClose())
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
virtual void setStatusBarMessage(QString message, int time) override;
|
||||
virtual void setDocument(const pdf::PDFModifiedDocument& document) override;
|
||||
virtual void adjustToolbar(QToolBar* toolbar) override;
|
||||
virtual pdf::PDFTextSelection getSelectedText() const override;
|
||||
|
||||
protected:
|
||||
virtual void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
|
|
|
@ -385,6 +385,11 @@ void PDFViewerMainWindowLite::adjustToolbar(QToolBar* toolbar)
|
|||
toolbar->setIconSize(iconSize);
|
||||
}
|
||||
|
||||
pdf::PDFTextSelection PDFViewerMainWindowLite::getSelectedText() const
|
||||
{
|
||||
return pdf::PDFTextSelection();
|
||||
}
|
||||
|
||||
void PDFViewerMainWindowLite::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!m_programController->canClose())
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
virtual void setStatusBarMessage(QString message, int time) override;
|
||||
virtual void setDocument(const pdf::PDFModifiedDocument& document) override;
|
||||
virtual void adjustToolbar(QToolBar* toolbar) override;
|
||||
virtual pdf::PDFTextSelection getSelectedText() const override;
|
||||
|
||||
protected:
|
||||
virtual void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
<file>redact-rectangle.svg</file>
|
||||
<file>redact-text.svg</file>
|
||||
<file>redact-page.svg</file>
|
||||
<file>redact-text-selection.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="30mm"
|
||||
height="30mm"
|
||||
viewBox="0 0 30 30"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="redact-text-selection.svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient2293"
|
||||
osb:paint="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2291" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
effect="spiro"
|
||||
id="path-effect831"
|
||||
is_visible="true" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="344.91448"
|
||||
inkscape:cy="-149.9167"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2035"
|
||||
inkscape:window-x="-13"
|
||||
inkscape:window-y="-13"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Melka</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Vrstva 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-267)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 11.646391,283.58184 v 0 0"
|
||||
id="path837"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect841"
|
||||
width="27.214285"
|
||||
height="26.316593"
|
||||
x="1.3701636"
|
||||
y="268.31158" />
|
||||
<g
|
||||
aria-label="txt"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.93333244px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
|
||||
id="text891"
|
||||
transform="translate(0,5.8208336)">
|
||||
<path
|
||||
d="m 9.8438522,287.79674 q -0.4382161,0.11576 -0.9591145,0.19017 -0.5126302,0.0744 -0.9177734,0.0744 -1.4138671,0 -2.1497395,-0.76068 -0.7358724,-0.76068 -0.7358724,-2.43913 v -4.91133 h -1.050065 v -1.30638 h 1.050065 v -2.6541 h 1.554427 v 2.6541 h 3.2080728 v 1.30638 H 6.6357794 v 4.20853 q 0,0.72761 0.033073,1.14102 0.033073,0.40514 0.2315104,0.76067 0.181901,0.33073 0.4960937,0.48783 0.3224609,0.14883 0.975651,0.14883 0.3803385,0 0.7937499,-0.10749 0.4134115,-0.11575 0.5953125,-0.19017 h 0.082682 z"
|
||||
style="font-size:16.93333244px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
|
||||
id="path893"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 19.724386,287.87943 h -1.959571 l -2.621028,-3.54708 -2.637565,3.54708 H 10.69548 l 3.604948,-4.60541 -3.571875,-4.63021 h 1.95957 l 2.604492,3.4892 2.61276,-3.4892 h 1.819011 l -3.629753,4.54753 z"
|
||||
style="font-size:16.93333244px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
|
||||
id="path895"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 26.545674,287.79674 q -0.438216,0.11576 -0.959114,0.19017 -0.51263,0.0744 -0.917773,0.0744 -1.413868,0 -2.14974,-0.76068 -0.735872,-0.76068 -0.735872,-2.43913 v -4.91133 H 20.73311 v -1.30638 h 1.050065 v -2.6541 h 1.554427 v 2.6541 h 3.208072 v 1.30638 h -3.208072 v 4.20853 q 0,0.72761 0.03307,1.14102 0.03307,0.40514 0.23151,0.76067 0.181901,0.33073 0.496094,0.48783 0.322461,0.14883 0.975651,0.14883 0.380338,0 0.79375,-0.10749 0.413411,-0.11575 0.595312,-0.19017 h 0.08268 z"
|
||||
style="font-size:16.93333244px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
|
||||
id="path897"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g849"
|
||||
transform="translate(-0.16305276,-1.5679908)"
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1">
|
||||
<ellipse
|
||||
ry="4.8121095"
|
||||
rx="4.8741207"
|
||||
cy="275.09717"
|
||||
cx="12.618022"
|
||||
id="path5985"
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.75;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5987"
|
||||
d="m 16.10308,278.8923 4.861718,5.45703"
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
|
@ -24,6 +24,7 @@
|
|||
#include "pdfredact.h"
|
||||
#include "pdfdocumentwriter.h"
|
||||
#include "pdfselectpagesdialog.h"
|
||||
#include "pdfcompiler.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
|
@ -35,6 +36,7 @@ RedactPlugin::RedactPlugin() :
|
|||
pdf::PDFPlugin(nullptr),
|
||||
m_actionRedactRectangle(nullptr),
|
||||
m_actionRedactText(nullptr),
|
||||
m_actionRedactTextSelection(nullptr),
|
||||
m_actionRedactPage(nullptr),
|
||||
m_actionCreateRedactedDocument(nullptr)
|
||||
{
|
||||
|
@ -49,11 +51,13 @@ void RedactPlugin::setWidget(pdf::PDFWidget* widget)
|
|||
|
||||
m_actionRedactRectangle = new QAction(QIcon(":/pdfplugins/redactplugin/redact-rectangle.svg"), tr("Redact Rectangle"), this);
|
||||
m_actionRedactText = new QAction(QIcon(":/pdfplugins/redactplugin/redact-text.svg"), tr("Redact Text"), this);
|
||||
m_actionRedactTextSelection = new QAction(QIcon(":/pdfplugins/redactplugin/redact-text-selection.svg"), tr("Redact Text Selection"), this);
|
||||
m_actionRedactPage = new QAction(QIcon(":/pdfplugins/redactplugin/redact-page.svg"), tr("Redact Page(s)"), this);
|
||||
m_actionCreateRedactedDocument = new QAction(QIcon(":/pdfplugins/redactplugin/redact-create-document.svg"), tr("Create Redacted Document"), this);
|
||||
|
||||
m_actionRedactRectangle->setObjectName("redactplugin_RedactRectangle");
|
||||
m_actionRedactText->setObjectName("redactplugin_RedactText");
|
||||
m_actionRedactTextSelection->setObjectName("redactplugin_RedactTextSelection");
|
||||
m_actionRedactPage->setObjectName("redactplugin_RedactPage");
|
||||
m_actionCreateRedactedDocument->setObjectName("redactplugin_CreateRedactedDocument");
|
||||
|
||||
|
@ -67,6 +71,7 @@ void RedactPlugin::setWidget(pdf::PDFWidget* widget)
|
|||
toolManager->addTool(redactRectangleTool);
|
||||
toolManager->addTool(redactTextTool);
|
||||
|
||||
connect(m_actionRedactTextSelection, &QAction::triggered, this, &RedactPlugin::onRedactTextSelectionTriggered);
|
||||
connect(m_actionRedactPage, &QAction::triggered, this, &RedactPlugin::onRedactPageTriggered);
|
||||
connect(m_actionCreateRedactedDocument, &QAction::triggered, this, &RedactPlugin::onCreateRedactedDocumentTriggered);
|
||||
|
||||
|
@ -85,15 +90,53 @@ void RedactPlugin::setDocument(const pdf::PDFModifiedDocument& document)
|
|||
|
||||
std::vector<QAction*> RedactPlugin::getActions() const
|
||||
{
|
||||
return { m_actionRedactRectangle, m_actionRedactText, m_actionRedactPage, m_actionCreateRedactedDocument };
|
||||
return { m_actionRedactRectangle, m_actionRedactText, m_actionRedactTextSelection, m_actionRedactPage, m_actionCreateRedactedDocument };
|
||||
}
|
||||
|
||||
void RedactPlugin::updateActions()
|
||||
{
|
||||
m_actionRedactTextSelection->setEnabled(m_document);
|
||||
m_actionRedactPage->setEnabled(m_document);
|
||||
m_actionCreateRedactedDocument->setEnabled(m_document);
|
||||
}
|
||||
|
||||
void RedactPlugin::onRedactTextSelectionTriggered()
|
||||
{
|
||||
pdf::PDFTextSelection selectedText = m_dataExchangeInterface->getSelectedText();
|
||||
|
||||
if (selectedText.isEmpty())
|
||||
{
|
||||
QMessageBox::information(m_widget, tr("Information"), tr("Select text via 'Advanced Search' tool, and then redact it using this tool. Select rows in 'Result' table to select particular results."));
|
||||
return;
|
||||
}
|
||||
|
||||
pdf::PDFDocumentModifier modifier(m_document);
|
||||
|
||||
for (auto it = selectedText.begin(); it != selectedText.end(); it = selectedText.nextPageRange(it))
|
||||
{
|
||||
const pdf::PDFTextSelectionColoredItem& item = *it;
|
||||
const pdf::PDFInteger pageIndex = item.start.pageIndex;
|
||||
|
||||
pdf::PDFTextLayoutGetter textLayoutGetter = m_widget->getDrawWidgetProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
|
||||
|
||||
QPolygonF quadrilaterals;
|
||||
pdf::PDFTextSelectionPainter textSelectionPainter(&selectedText);
|
||||
QPainterPath path = textSelectionPainter.prepareGeometry(pageIndex, textLayoutGetter, QMatrix(), &quadrilaterals);
|
||||
|
||||
if (!path.isEmpty())
|
||||
{
|
||||
pdf::PDFObjectReference page = m_document->getCatalog()->getPage(pageIndex)->getPageReference();
|
||||
modifier.getBuilder()->createAnnotationRedact(page, quadrilaterals, Qt::black);
|
||||
modifier.markAnnotationsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if (modifier.finalize())
|
||||
{
|
||||
emit m_widget->getToolManager()->documentModified(pdf::PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||
}
|
||||
}
|
||||
|
||||
void RedactPlugin::onRedactPageTriggered()
|
||||
{
|
||||
pdf::PDFSelectPagesDialog dialog(tr("Redact Pages"), tr("Page Range to be Redacted"), m_document->getCatalog()->getPageCount(), m_widget->getDrawWidget()->getCurrentPages(), m_widget);
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
private:
|
||||
void updateActions();
|
||||
|
||||
void onRedactTextSelectionTriggered();
|
||||
void onRedactPageTriggered();
|
||||
void onCreateRedactedDocumentTriggered();
|
||||
|
||||
|
@ -50,6 +51,7 @@ private:
|
|||
|
||||
QAction* m_actionRedactRectangle;
|
||||
QAction* m_actionRedactText;
|
||||
QAction* m_actionRedactTextSelection;
|
||||
QAction* m_actionRedactPage;
|
||||
QAction* m_actionCreateRedactedDocument;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue