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