mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Signature plugin: Sign electronically
This commit is contained in:
@ -703,9 +703,13 @@ std::array<PDFReal, 4> PDFDocumentBuilder::getAnnotationReductionRectangle(const
|
|||||||
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
|
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFPageContentStreamBuilder::PDFPageContentStreamBuilder(PDFDocumentBuilder* builder) :
|
PDFPageContentStreamBuilder::PDFPageContentStreamBuilder(PDFDocumentBuilder* builder,
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem coordinateSystem,
|
||||||
|
Mode mode) :
|
||||||
m_documentBuilder(builder),
|
m_documentBuilder(builder),
|
||||||
m_contentStreamBuilder(nullptr)
|
m_contentStreamBuilder(nullptr),
|
||||||
|
m_coordinateSystem(coordinateSystem),
|
||||||
|
m_mode(mode)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -733,7 +737,7 @@ QPainter* PDFPageContentStreamBuilder::begin(PDFObjectReference page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_pageReference = page;
|
m_pageReference = page;
|
||||||
m_contentStreamBuilder = new PDFContentStreamBuilder(mediaBox.size(), PDFContentStreamBuilder::CoordinateSystem::Qt);
|
m_contentStreamBuilder = new PDFContentStreamBuilder(mediaBox.size(), m_coordinateSystem);
|
||||||
return m_contentStreamBuilder->begin();
|
return m_contentStreamBuilder->begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,21 +766,86 @@ void PDFPageContentStreamBuilder::end(QPainter* painter)
|
|||||||
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
|
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
|
||||||
PDFObjectReference contentsReference = copiedObjects[1].getReference();
|
PDFObjectReference contentsReference = copiedObjects[1].getReference();
|
||||||
|
|
||||||
PDFObjectFactory pageUpdateFactory;
|
if (m_mode == Mode::Replace)
|
||||||
|
{
|
||||||
|
PDFObjectFactory pageUpdateFactory;
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionary();
|
pageUpdateFactory.beginDictionary();
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionaryItem("Contents");
|
pageUpdateFactory.beginDictionaryItem("Contents");
|
||||||
pageUpdateFactory << contentsReference;
|
pageUpdateFactory << contentsReference;
|
||||||
pageUpdateFactory.endDictionaryItem();
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionaryItem("Resources");
|
pageUpdateFactory.beginDictionaryItem("Resources");
|
||||||
pageUpdateFactory << resourcesReference;
|
pageUpdateFactory << resourcesReference;
|
||||||
pageUpdateFactory.endDictionaryItem();
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
pageUpdateFactory.endDictionary();
|
pageUpdateFactory.endDictionary();
|
||||||
|
|
||||||
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<PDFObjectReference> contentReferences;
|
||||||
|
PDFObject pageObject = m_documentBuilder->getObjectByReference(m_pageReference);
|
||||||
|
|
||||||
|
if (pageObject.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* pageDictionary = pageObject.getDictionary();
|
||||||
|
const PDFObject& oldContents = pageDictionary->get("Contents");
|
||||||
|
const PDFObject& oldContentsObject = m_documentBuilder->getObject(oldContents);
|
||||||
|
|
||||||
|
if (oldContentsObject.isStream())
|
||||||
|
{
|
||||||
|
if (oldContents.isReference())
|
||||||
|
{
|
||||||
|
contentReferences.push_back(oldContents.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (oldContentsObject.isArray())
|
||||||
|
{
|
||||||
|
const PDFArray* contentsArray = oldContentsObject.getArray();
|
||||||
|
for (const PDFObject& object : *contentsArray)
|
||||||
|
{
|
||||||
|
if (object.isReference())
|
||||||
|
{
|
||||||
|
contentReferences.push_back(object.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_mode)
|
||||||
|
{
|
||||||
|
case Mode::PlaceBefore:
|
||||||
|
contentReferences.insert(contentReferences.begin(), contentsReference);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::PlaceAfter:
|
||||||
|
contentReferences.push_back(contentsReference);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory pageUpdateFactory;
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionary();
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionaryItem("Contents");
|
||||||
|
pageUpdateFactory << contentReferences;
|
||||||
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionaryItem("Resources");
|
||||||
|
pageUpdateFactory << resourcesReference;
|
||||||
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
pageUpdateFactory.endDictionary();
|
||||||
|
|
||||||
|
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
|
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
|
||||||
|
@ -261,9 +261,20 @@ private:
|
|||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentStreamBuilder
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentStreamBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PDFPageContentStreamBuilder(PDFDocumentBuilder* builder);
|
|
||||||
|
|
||||||
/// Starts painting onto the page. Old page content is erased. This
|
enum class Mode
|
||||||
|
{
|
||||||
|
Replace,
|
||||||
|
PlaceBefore,
|
||||||
|
PlaceAfter
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Vytvoří nový builder, který vytváří obsah stránek.
|
||||||
|
PDFPageContentStreamBuilder(PDFDocumentBuilder* builder,
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem coordinateSystem = PDFContentStreamBuilder::CoordinateSystem::Qt,
|
||||||
|
Mode mode = Mode::Replace);
|
||||||
|
|
||||||
|
/// Starts painting onto the page. Old page content is erased (in Replace mode). This
|
||||||
/// function returns painter, onto which can be graphics drawn. Painter
|
/// function returns painter, onto which can be graphics drawn. Painter
|
||||||
/// uses Qt's coordinate system. Calling begin multiple times, without
|
/// uses Qt's coordinate system. Calling begin multiple times, without
|
||||||
/// subsequent calls to end function, is invalid and can result
|
/// subsequent calls to end function, is invalid and can result
|
||||||
@ -287,6 +298,8 @@ private:
|
|||||||
PDFDocumentBuilder* m_documentBuilder;
|
PDFDocumentBuilder* m_documentBuilder;
|
||||||
PDFContentStreamBuilder* m_contentStreamBuilder;
|
PDFContentStreamBuilder* m_contentStreamBuilder;
|
||||||
PDFObjectReference m_pageReference;
|
PDFObjectReference m_pageReference;
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem m_coordinateSystem;
|
||||||
|
Mode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFDocumentBuilder
|
class PDF4QTLIBSHARED_EXPORT PDFDocumentBuilder
|
||||||
|
@ -868,6 +868,18 @@ std::set<PDFInteger> PDFPageContentScene::getSelectedElementIds() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<PDFInteger> PDFPageContentScene::getPageIndices() const
|
||||||
|
{
|
||||||
|
std::set<PDFInteger> result;
|
||||||
|
|
||||||
|
for (const auto& element : m_elements)
|
||||||
|
{
|
||||||
|
result.insert(element->getPageIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds)
|
void PDFPageContentScene::setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds)
|
||||||
{
|
{
|
||||||
m_manipulator.selectNew(selectedElementIds);
|
m_manipulator.selectNew(selectedElementIds);
|
||||||
|
@ -504,6 +504,9 @@ public:
|
|||||||
/// Returns set of selected element ids
|
/// Returns set of selected element ids
|
||||||
std::set<PDFInteger> getSelectedElementIds() const;
|
std::set<PDFInteger> getSelectedElementIds() const;
|
||||||
|
|
||||||
|
/// Returns set of involved pages
|
||||||
|
std::set<PDFInteger> getPageIndices() const;
|
||||||
|
|
||||||
/// Set selected items
|
/// Set selected items
|
||||||
void setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds);
|
void setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds);
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ void PDFWidgetTool::setActive(bool active)
|
|||||||
setActiveImpl(active);
|
setActiveImpl(active);
|
||||||
updateActions();
|
updateActions();
|
||||||
|
|
||||||
m_proxy->repaintNeeded();
|
emit m_proxy->repaintNeeded();
|
||||||
emit toolActivityChanged(active);
|
emit toolActivityChanged(active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
#include "pdfutils.h"
|
#include "pdfutils.h"
|
||||||
#include "pdfpagecontenteditorwidget.h"
|
#include "pdfpagecontenteditorwidget.h"
|
||||||
#include "pdfpagecontenteditorstylesettings.h"
|
#include "pdfpagecontenteditorstylesettings.h"
|
||||||
|
#include "pdfdocumentbuilder.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
namespace pdfplugin
|
namespace pdfplugin
|
||||||
{
|
{
|
||||||
@ -152,6 +154,7 @@ void SignaturePlugin::setWidget(pdf::PDFWidget* widget)
|
|||||||
connect(&m_scene, &pdf::PDFPageContentScene::editElementRequest, this, &SignaturePlugin::onSceneEditElement);
|
connect(&m_scene, &pdf::PDFPageContentScene::editElementRequest, this, &SignaturePlugin::onSceneEditElement);
|
||||||
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
|
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
|
||||||
connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive);
|
connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive);
|
||||||
|
connect(signElectronicallyAction, &QAction::triggered, this, &SignaturePlugin::onSignElectronically);
|
||||||
|
|
||||||
updateActions();
|
updateActions();
|
||||||
}
|
}
|
||||||
@ -268,6 +271,36 @@ void SignaturePlugin::onSceneEditElement(const std::set<pdf::PDFInteger>& elemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSignElectronically()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_document);
|
||||||
|
Q_ASSERT(!m_scene.isEmpty());
|
||||||
|
|
||||||
|
if (QMessageBox::question(m_dataExchangeInterface->getMainWindow(), tr("Confirm Signature"), tr("Document will be signed electronically. Do you want to continue?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
pdf::PDFDocumentModifier modifier(m_document);
|
||||||
|
|
||||||
|
std::set<pdf::PDFInteger> pageIndices = m_scene.getPageIndices();
|
||||||
|
for (pdf::PDFInteger pageIndex : pageIndices)
|
||||||
|
{
|
||||||
|
const pdf::PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
|
||||||
|
pdf::PDFPageContentStreamBuilder pageContentStreamBuilder(modifier.getBuilder(),
|
||||||
|
pdf::PDFContentStreamBuilder::CoordinateSystem::PDF,
|
||||||
|
pdf::PDFPageContentStreamBuilder::Mode::PlaceAfter);
|
||||||
|
QPainter* painter = pageContentStreamBuilder.begin(page->getPageReference());
|
||||||
|
QList<pdf::PDFRenderError> errors;
|
||||||
|
pdf::PDFTextLayoutGetter nullGetter(nullptr, pageIndex);
|
||||||
|
m_scene.drawPage(painter, pageIndex, nullptr, nullGetter, QMatrix(), errors);
|
||||||
|
pageContentStreamBuilder.end(painter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier.finalize())
|
||||||
|
{
|
||||||
|
emit m_widget->getToolManager()->documentModified(pdf::PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SignaturePlugin::onPenChanged(const QPen& pen)
|
void SignaturePlugin::onPenChanged(const QPen& pen)
|
||||||
{
|
{
|
||||||
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
@ -53,6 +53,7 @@ private:
|
|||||||
void onWidgetSelectionChanged();
|
void onWidgetSelectionChanged();
|
||||||
void onToolActivityChanged();
|
void onToolActivityChanged();
|
||||||
void onSceneEditElement(const std::set<pdf::PDFInteger>& elements);
|
void onSceneEditElement(const std::set<pdf::PDFInteger>& elements);
|
||||||
|
void onSignElectronically();
|
||||||
|
|
||||||
void onPenChanged(const QPen& pen);
|
void onPenChanged(const QPen& pen);
|
||||||
void onBrushChanged(const QBrush& brush);
|
void onBrushChanged(const QBrush& brush);
|
||||||
|
Reference in New Issue
Block a user