qt6/src/poppler-annotation-private.h | 4 qt6/src/poppler-annotation-private.h.orig | 115 --------------- qt6/src/poppler-annotation.cc | 18 +- qt6/src/poppler-annotation.h | 2 qt6/src/poppler-document.cc | 2 qt6/src/poppler-form.cc | 119 +++++++++++++++- qt6/src/poppler-form.h | 55 +++++++ qt6/src/poppler-pdf-converter.cc | 220 +++++++++++++++++++++++++++++- qt6/src/poppler-qt6.h | 83 +++++++++++ 9 files changed, 489 insertions(+), 129 deletions(-)
New commits: commit fbc4d13d075ff30d6fccb5b81d8f3b8b19d673cb Author: Albert Astals Cid <[email protected]> Date: Fri Dec 18 13:40:49 2020 +0100 qt6: Port the signing code from qt5 diff --git a/qt6/src/poppler-annotation-private.h b/qt6/src/poppler-annotation-private.h index 288ab6f1..1e8b6d32 100644 --- a/qt6/src/poppler-annotation-private.h +++ b/qt6/src/poppler-annotation-private.h @@ -3,6 +3,7 @@ * Copyright (C) 2012, Tobias Koenig <[email protected]> * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]> * Copyright (C) 2012, 2014, 2018-2020, Albert Astals Cid <[email protected]> + * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +38,8 @@ class PDFRectangle; namespace Poppler { class DocumentData; +PDFRectangle boundaryToPdfRectangle(::Page *pdfPage, const QRectF &r, int flags); + class AnnotationPrivate : public QSharedData { public: @@ -87,7 +90,6 @@ public: /* The following helpers only work if pdfPage is set */ void flushBaseAnnotationProperties(); - void fillNormalizationMTX(double MTX[6], int pageRotation) const; void fillTransformationMTX(double MTX[6]) const; QRectF fromPdfRectangle(const PDFRectangle &r) const; PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const; diff --git a/qt6/src/poppler-annotation-private.h.orig b/qt6/src/poppler-annotation-private.h.orig deleted file mode 100644 index 937edad4..00000000 --- a/qt6/src/poppler-annotation-private.h.orig +++ /dev/null @@ -1,115 +0,0 @@ -/* poppler-annotation-private.h: qt interface to poppler - * Copyright (C) 2007, Pino Toscano <[email protected]> - * Copyright (C) 2012, Tobias Koenig <[email protected]> - * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]> - * Copyright (C) 2012, 2014, 2018, Albert Astals Cid <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _POPPLER_ANNOTATION_PRIVATE_H_ -#define _POPPLER_ANNOTATION_PRIVATE_H_ - -#include <QtCore/QLinkedList> -#include <QtCore/QPointF> -#include <QtCore/QSharedDataPointer> - -#include "poppler-annotation.h" - -#include <Object.h> - -class Annot; -class AnnotPath; -class Link; -class Page; -class PDFRectangle; - -namespace Poppler -{ -class DocumentData; - -class AnnotationPrivate : public QSharedData -{ - public: - AnnotationPrivate(); - virtual ~AnnotationPrivate(); - - AnnotationPrivate(const AnnotationPrivate &) = delete; - AnnotationPrivate& operator=(const AnnotationPrivate &) = delete; - - void addRevision(Annotation *ann, Annotation::RevScope scope, Annotation::RevType type); - - /* Returns an Annotation of the right subclass whose d_ptr points to - * this AnnotationPrivate */ - virtual Annotation * makeAlias() = 0; - - /* properties: contents related */ - QString author; - QString contents; - QString uniqueName; - QDateTime modDate; // before or equal to currentDateTime() - QDateTime creationDate; // before or equal to modifyDate - - /* properties: look/interaction related */ - int flags; - QRectF boundary; - - /* style and popup */ - Annotation::Style style; - Annotation::Popup popup; - - /* revisions */ - Annotation::RevScope revisionScope; - Annotation::RevType revisionType; - QList<Annotation*> revisions; - - /* After this call, the Annotation object will behave like a wrapper for - * the specified Annot object. All cached values are discarded */ - void tieToNativeAnnot(Annot *ann, ::Page *page, DocumentData *doc); - - /* Creates a new Annot object on the specified page, flushes current - * values to that object and ties this Annotation to that object */ - virtual Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) = 0; - - /* Inited to 0 (i.e. untied annotation) */ - Annot *pdfAnnot; - ::Page *pdfPage; - DocumentData * parentDoc; - - /* The following helpers only work if pdfPage is set */ - void flushBaseAnnotationProperties(); - void fillNormalizationMTX(double MTX[6], int pageRotation) const; - void fillTransformationMTX(double MTX[6]) const; - QRectF fromPdfRectangle(const PDFRectangle &r) const; - PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const; - AnnotPath * toAnnotPath(const QLinkedList<QPointF> &l) const; - - /* Scan page for annotations, parentId=0 searches for root annotations, subtypes empty means all subtypes */ - static QList<Annotation*> findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentId = -1); - - /* Add given annotation to given page */ - static void addAnnotationToPage(::Page *pdfPage, DocumentData *doc, const Annotation * ann); - - /* Remove annotation from page and destroy ann */ - static void removeAnnotationFromPage(::Page *pdfPage, const Annotation * ann); - - Ref pdfObjectReference() const; - - Link* additionalAction( Annotation::AdditionalActionType type ) const; -}; - -} - -#endif diff --git a/qt6/src/poppler-annotation.cc b/qt6/src/poppler-annotation.cc index 9724e2df..609130b6 100644 --- a/qt6/src/poppler-annotation.cc +++ b/qt6/src/poppler-annotation.cc @@ -11,6 +11,9 @@ * Copyright (C) 2018, 2019 Tobias Deiminger <[email protected]> * Copyright (C) 2018 Carlos Garcia Campos <[email protected]> * Copyright (C) 2020 Oliver Sander <[email protected]> + * Copyright (C) 2020 Katarina Behrens <[email protected]> + * Copyright (C) 2020 Thorsten Behrens <[email protected]> + * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * Adapting code from * Copyright (C) 2004 by Enrico Ros <[email protected]> * @@ -133,7 +136,7 @@ void AnnotationPrivate::flushBaseAnnotationProperties() // Returns matrix to convert from user space coords (oriented according to the // specified rotation) to normalized coords -void AnnotationPrivate::fillNormalizationMTX(double MTX[6], int pageRotation) const +void fillNormalizationMTX(::Page *pdfPage, double MTX[6], int pageRotation) { Q_ASSERT(pdfPage); @@ -171,7 +174,7 @@ void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const if (pageRotate == 0 || (pdfAnnot->getFlags() & Annot::flagNoRotate) == 0) { // Use the normalization matrix for this page's rotation - fillNormalizationMTX(MTX, pageRotate); + fillNormalizationMTX(pdfPage, MTX, pageRotate); } else { // Clients expect coordinates relative to this page's rotation, but // FixedRotation annotations internally use unrotated coordinates: @@ -179,7 +182,7 @@ void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const // top-left corner as rotation pivot double MTXnorm[6]; - fillNormalizationMTX(MTXnorm, pageRotate); + fillNormalizationMTX(pdfPage, MTXnorm, pageRotate); QTransform transform(MTXnorm[0], MTXnorm[1], MTXnorm[2], MTXnorm[3], MTXnorm[4], MTXnorm[5]); transform.translate(+pdfAnnot->getXMin(), +pdfAnnot->getYMax()); @@ -230,14 +233,14 @@ QRectF AnnotationPrivate::fromPdfRectangle(const PDFRectangle &r) const // the transformation produced by fillTransformationMTX, but we can't use // fillTransformationMTX here because it relies on the native annotation // object's boundary rect to be already set up. -PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFlags) const +PDFRectangle boundaryToPdfRectangle(::Page *pdfPage, const QRectF &r, int rFlags) { Q_ASSERT(pdfPage); const int pageRotate = pdfPage->getRotate(); double MTX[6]; - fillNormalizationMTX(MTX, pageRotate); + fillNormalizationMTX(pdfPage, MTX, pageRotate); double tl_x, tl_y, br_x, br_y, swp; XPDFReader::invTransform(MTX, r.topLeft(), tl_x, tl_y); @@ -269,6 +272,11 @@ PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFla return PDFRectangle(br_x, br_y - width, br_x + height, br_y); } +PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFlags) const +{ + return Poppler::boundaryToPdfRectangle(pdfPage, r, rFlags); +} + AnnotPath *AnnotationPrivate::toAnnotPath(const QVector<QPointF> &list) const { const int count = list.size(); diff --git a/qt6/src/poppler-annotation.h b/qt6/src/poppler-annotation.h index 6fad7e3e..857b0f19 100644 --- a/qt6/src/poppler-annotation.h +++ b/qt6/src/poppler-annotation.h @@ -8,6 +8,8 @@ * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]> * Copyright (C) 2013, Anthony Granger <[email protected]> * Copyright (C) 2018, Dileep Sankhla <[email protected]> + * Copyright (C) 2020, Katarina Behrens <[email protected]> + * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * Adapting code from * Copyright (C) 2004 by Enrico Ros <[email protected]> * diff --git a/qt6/src/poppler-document.cc b/qt6/src/poppler-document.cc index 65077e6f..9b5edc62 100644 --- a/qt6/src/poppler-document.cc +++ b/qt6/src/poppler-document.cc @@ -16,6 +16,8 @@ * Copyright (C) 2019, 2020 Oliver Sander <[email protected]> * Copyright (C) 2019 Alexander Volkov <[email protected]> * Copyright (C) 2020 Philipp Knechtges <[email protected]> + * Copyright (C) 2020 Katarina Behrens <[email protected]> + * Copyright (C) 2020 Thorsten Behrens <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/qt6/src/poppler-form.cc b/qt6/src/poppler-form.cc index de0b540c..f70cea84 100644 --- a/qt6/src/poppler-form.cc +++ b/qt6/src/poppler-form.cc @@ -11,6 +11,8 @@ * Copyright (C) 2018, 2020 Oliver Sander <[email protected]> * Copyright (C) 2019 João Netto <[email protected]> * Copyright (C) 2020 David García Garzón <[email protected]> + * Copyright (C) 2020 Thorsten Behrens <[email protected]> + * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,13 +31,19 @@ #include "poppler-qt6.h" +#include <config.h> + #include <QtCore/QSizeF> +#include <QUrl> #include <Form.h> #include <Object.h> #include <Link.h> #include <SignatureInfo.h> #include <CertificateInfo.h> +#ifdef ENABLE_NSS3 +# include <SignatureHandler.h> +#endif #include "poppler-form.h" #include "poppler-page-private.h" @@ -571,6 +579,7 @@ public: EntityInfo issuer_info; EntityInfo subject_info; + QString nick_name; QByteArray certificate_der; QByteArray serial_number; QByteArray public_key; @@ -584,6 +593,11 @@ public: bool is_null; }; +CertificateInfo::CertificateInfo() : d_ptr(new CertificateInfoPrivate()) +{ + d_ptr->is_null = true; +} + CertificateInfo::CertificateInfo(CertificateInfoPrivate *priv) : d_ptr(priv) { } CertificateInfo::CertificateInfo(const CertificateInfo &other) : d_ptr(other.d_ptr) { } @@ -650,6 +664,12 @@ QString CertificateInfo::subjectInfo(EntityInfoKey key) const } } +QString CertificateInfo::nickName() const +{ + Q_D(const CertificateInfo); + return d->nick_name; +} + QDateTime CertificateInfo::validityStart() const { Q_D(const CertificateInfo); @@ -726,6 +746,21 @@ QByteArray CertificateInfo::certificateData() const return d->certificate_der; } +bool CertificateInfo::checkPassword(const QString &password) const +{ +#ifdef ENABLE_NSS3 + Q_D(const CertificateInfo); + SignatureHandler sigHandler(d->nick_name.toUtf8().constData(), SEC_OID_SHA256); + unsigned char buffer[5]; + memcpy(buffer, "test", 5); + sigHandler.updateHash(buffer, 5); + std::unique_ptr<GooString> tmpSignature = sigHandler.signDetached(password.toUtf8().constData()); + return tmpSignature.get() != nullptr; +#else + return false; +#endif +} + class SignatureValidationInfoPrivate { public: @@ -897,14 +932,8 @@ SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const return validate(opt, QDateTime()); } -SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &validationTime) const +static CertificateInfoPrivate *createCertificateInfoPrivate(const X509CertificateInfo *ci) { - FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm); - const time_t validationTimeT = validationTime.isValid() ? validationTime.toSecsSinceEpoch() : -1; - SignatureInfo *si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT); - - // get certificate info - const X509CertificateInfo *ci = si->getCertificateInfo(); CertificateInfoPrivate *certPriv = new CertificateInfoPrivate; certPriv->is_null = true; if (ci) { @@ -926,6 +955,8 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v certPriv->subject_info.email_address = subjectInfo.email.c_str(); certPriv->subject_info.org_name = subjectInfo.organization.c_str(); + certPriv->nick_name = ci->getNickName().c_str(); + X509CertificateInfo::Validity certValidity = ci->getValidity(); certPriv->validity_start = QDateTime::fromSecsSinceEpoch(certValidity.notBefore, Qt::UTC); certPriv->validity_end = QDateTime::fromSecsSinceEpoch(certValidity.notAfter, Qt::UTC); @@ -941,6 +972,19 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v certPriv->is_null = false; } + return certPriv; +} + +SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &validationTime) const +{ + FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm); + const time_t validationTimeT = validationTime.isValid() ? validationTime.toSecsSinceEpoch() : -1; + SignatureInfo *si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT); + + // get certificate info + const X509CertificateInfo *ci = si->getCertificateInfo(); + CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(ci); + SignatureValidationInfoPrivate *priv = new SignatureValidationInfoPrivate(CertificateInfo(certPriv)); switch (si->getSignatureValStatus()) { case SIGNATURE_VALID: @@ -1012,4 +1056,65 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v return SignatureValidationInfo(priv); } +bool hasNSSSupport() +{ +#ifdef ENABLE_NSS3 + return true; +#else + return false; +#endif +} + +QVector<CertificateInfo> getAvailableSigningCertificates() +{ + QVector<CertificateInfo> vReturnCerts; + +#ifdef ENABLE_NSS3 + std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = SignatureHandler::getAvailableSigningCertificates(); + + for (auto &cert : vCerts) { + CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(cert.get()); + vReturnCerts.append(CertificateInfo(certPriv)); + } +#endif + + return vReturnCerts; +} + +QString POPPLER_QT6_EXPORT getNSSDir() +{ +#ifdef ENABLE_NSS3 + return QString::fromLocal8Bit(SignatureHandler::getNSSDir().c_str()); +#else + return QString(); +#endif +} + +void setNSSDir(const QString &path) +{ +#ifdef ENABLE_NSS3 + if (path.isEmpty()) + return; + + GooString *goo = QStringToGooString(path); + SignatureHandler::setNSSDir(*goo); + delete goo; +#else + (void)path; +#endif +} + +namespace { +std::function<QString(const QString &)> nssPasswordCall; +} + +void setNSSPasswordCallback(const std::function<char *(const char *)> &f) +{ +#ifdef ENABLE_NSS3 + SignatureHandler::setNSSPasswordCallback(f); +#else + qWarning() << "setNSSPasswordCallback called but this poppler is built without NSS support"; + (void)f; +#endif +} } diff --git a/qt6/src/poppler-form.h b/qt6/src/poppler-form.h index cfb72d9b..dfc8142a 100644 --- a/qt6/src/poppler-form.h +++ b/qt6/src/poppler-form.h @@ -9,6 +9,9 @@ * Copyright (C) 2018, Chinmoy Ranjan Pradhan <[email protected]> * Copyright (C) 2018, Oliver Sander <[email protected]> * Copyright (C) 2019 João Netto <[email protected]> + * Copyright (C) 2019, Adrian Johnson <[email protected]> + * Copyright (C) 2020, Thorsten Behrens <[email protected]> + * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,9 +31,11 @@ #ifndef _POPPLER_QT6_FORM_H_ #define _POPPLER_QT6_FORM_H_ +#include <functional> #include <memory> #include <ctime> #include <QtCore/QDateTime> +#include <QtCore/QVector> #include <QtCore/QList> #include <QtCore/QRectF> #include <QtCore/QStringList> @@ -38,6 +43,7 @@ #include "poppler-export.h" #include "poppler-annotation.h" +class Object; class Page; class FormWidget; class FormWidgetButton; @@ -491,6 +497,7 @@ public: Organization, }; + CertificateInfo(); CertificateInfo(CertificateInfoPrivate *priv); ~CertificateInfo(); @@ -519,6 +526,13 @@ public: */ QString subjectInfo(EntityInfoKey key) const; + /** + The certificate internal database nickname + + \since 20.12 + */ + QString nickName() const; + /** The date-time when certificate becomes valid. */ @@ -559,6 +573,13 @@ public: */ QByteArray certificateData() const; + /** + Checks if the given password is the correct one for this certificate + + \since 20.12 + */ + bool checkPassword(const QString &password) const; + CertificateInfo(const CertificateInfo &other); CertificateInfo &operator=(const CertificateInfo &other); @@ -750,6 +771,40 @@ private: Q_DISABLE_COPY(FormFieldSignature) }; +/** + Returns is poppler was compiled with NSS support + + \since 20.12 +*/ +bool POPPLER_QT6_EXPORT hasNSSSupport(); + +/** + Return vector of suitable signing certificates + + \since 20.12 +*/ +QVector<CertificateInfo> POPPLER_QT6_EXPORT getAvailableSigningCertificates(); + +/** + Gets the current NSS CertDB directory + + \since 20.12 +*/ +QString POPPLER_QT6_EXPORT getNSSDir(); + +/** + Set a custom NSS CertDB directory. Needs to be called before doing any other signature operation + + \since 20.12 +*/ +void POPPLER_QT6_EXPORT setNSSDir(const QString &pathURL); + +/** + Sets the callback for NSS password requests + + \since 20.12 +*/ +void POPPLER_QT6_EXPORT setNSSPasswordCallback(const std::function<char *(const char *)> &f); } #endif diff --git a/qt6/src/poppler-pdf-converter.cc b/qt6/src/poppler-pdf-converter.cc index fe6ac4e2..91705f6e 100644 --- a/qt6/src/poppler-pdf-converter.cc +++ b/qt6/src/poppler-pdf-converter.cc @@ -1,6 +1,8 @@ /* poppler-pdf-converter.cc: qt interface to poppler * Copyright (C) 2008, Pino Toscano <[email protected]> * Copyright (C) 2008, 2009, 2020, Albert Astals Cid <[email protected]> + * Copyright (C) 2020, Thorsten Behrens <[email protected]> + * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,12 +21,17 @@ #include "poppler-qt6.h" +#include "poppler-annotation-helper.h" +#include "poppler-annotation-private.h" #include "poppler-private.h" #include "poppler-converter-private.h" #include "poppler-qiodeviceoutstream-private.h" -#include <QtCore/QFile> +#include <QFile> +#include <QUuid> +#include "Array.h" +#include "Form.h" #include <ErrorCodes.h> namespace Poppler { @@ -103,4 +110,215 @@ bool PDFConverter::convert() return (errorCode == errNone); } +bool PDFConverter::sign(const NewSignatureData &data) +{ + Q_D(PDFConverter); + d->lastError = NoError; + + if (d->document->locked) { + d->lastError = FileLockedError; + return false; + } + + if (data.signatureText().isEmpty()) { + qWarning() << "No signature text given"; + return false; + } + + ::PDFDoc *doc = d->document->doc; + ::Page *destPage = doc->getPage(data.page() + 1); + + const DefaultAppearance da { { objName, "SigFont" }, data.fontSize(), std::unique_ptr<AnnotColor> { convertQColor(data.fontColor()) } }; + const PDFRectangle rect = boundaryToPdfRectangle(destPage, data.boundingRectangle(), 0 /* no flags */); + + Object annotObj = Object(new Dict(doc->getXRef())); + annotObj.dictSet("Type", Object(objName, "Annot")); + annotObj.dictSet("Subtype", Object(objName, "Widget")); + annotObj.dictSet("FT", Object(objName, "Sig")); + annotObj.dictSet("T", Object(QStringToGooString(data.fieldPartialName()))); + Array *rectArray = new Array(doc->getXRef()); + rectArray->add(Object(rect.x1)); + rectArray->add(Object(rect.y1)); + rectArray->add(Object(rect.x2)); + rectArray->add(Object(rect.y2)); + annotObj.dictSet("Rect", Object(rectArray)); + + GooString *daStr = da.toAppearanceString(); + annotObj.dictSet("DA", Object(daStr)); + + const Ref ref = doc->getXRef()->addIndirectObject(&annotObj); + Catalog *catalog = doc->getCatalog(); + catalog->addFormToAcroForm(ref); + + std::unique_ptr<::FormFieldSignature> field = std::make_unique<::FormFieldSignature>(doc, Object(annotObj.getDict()), ref, nullptr, nullptr); + + std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText())); + field->setCustomAppearanceContent(*gSignatureText); + + Object refObj(ref); + AnnotWidget *signatureAnnot = new AnnotWidget(doc, &annotObj, &refObj, field.get()); + signatureAnnot->setFlags(signatureAnnot->getFlags() | Annot::flagPrint | Annot::flagLocked); + Dict dummy(doc->getXRef()); + auto appearCharacs = std::make_unique<AnnotAppearanceCharacs>(&dummy); + appearCharacs->setBorderColor(std::unique_ptr<AnnotColor> { convertQColor(data.borderColor()) }); + appearCharacs->setBackColor(std::unique_ptr<AnnotColor> { convertQColor(data.backgroundColor()) }); + signatureAnnot->setAppearCharacs(std::move(appearCharacs)); + + bool dummyAddDingbatsResource = false; // This is only update so if we didn't need to add + // the dingbats resource we should not need it now + signatureAnnot->generateFieldAppearance(&dummyAddDingbatsResource); + signatureAnnot->updateAppearanceStream(); + + FormWidget *formWidget = field->getWidget(field->getNumWidgets() - 1); + formWidget->setWidgetAnnotation(signatureAnnot); + + destPage->addAnnot(signatureAnnot); + + std::unique_ptr<AnnotBorder> border(new AnnotBorderArray()); + border->setWidth(1.5); + signatureAnnot->setBorder(std::move(border)); + + FormWidgetSignature *fws = dynamic_cast<FormWidgetSignature *>(formWidget); + if (fws) { + const bool res = fws->signDocument(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), "SHA256", data.password().toUtf8().constData()); + + // Now remove the signature stuff in case the user wants to continue editing stuff + // So the document object is clean + const Object &vRefObj = annotObj.dictLookupNF("V"); + if (vRefObj.isRef()) { + doc->getXRef()->removeIndirectObject(vRefObj.getRef()); + } + destPage->removeAnnot(signatureAnnot); + catalog->removeFormFromAcroForm(ref); + doc->getXRef()->removeIndirectObject(ref); + + return res; + } + + return false; +} + +struct PDFConverter::NewSignatureData::NewSignatureDataPrivate +{ + NewSignatureDataPrivate() = default; + + QString certNickname; + QString password; + int page; + QRectF boundingRectangle; + QString signatureText; + double fontSize = 10.0; + QColor fontColor = Qt::red; + QColor borderColor = Qt::red; + QColor backgroundColor = QColor(240, 240, 240); + + QString partialName = QUuid::createUuid().toString(); +}; + +PDFConverter::NewSignatureData::NewSignatureData() : d(new NewSignatureDataPrivate()) { } + +PDFConverter::NewSignatureData::~NewSignatureData() +{ + delete d; +} + +QString PDFConverter::NewSignatureData::certNickname() const +{ + return d->certNickname; +} + +void PDFConverter::NewSignatureData::setCertNickname(const QString &certNickname) +{ + d->certNickname = certNickname; +} + +QString PDFConverter::NewSignatureData::password() const +{ + return d->password; +} + +void PDFConverter::NewSignatureData::setPassword(const QString &password) +{ + d->password = password; +} + +int PDFConverter::NewSignatureData::page() const +{ + return d->page; +} + +void PDFConverter::NewSignatureData::setPage(int page) +{ + d->page = page; +} + +QRectF PDFConverter::NewSignatureData::boundingRectangle() const +{ + return d->boundingRectangle; +} + +void PDFConverter::NewSignatureData::setBoundingRectangle(const QRectF &rect) +{ + d->boundingRectangle = rect; +} + +QString PDFConverter::NewSignatureData::signatureText() const +{ + return d->signatureText; +} + +void PDFConverter::NewSignatureData::setSignatureText(const QString &text) +{ + d->signatureText = text; +} + +double PDFConverter::NewSignatureData::fontSize() const +{ + return d->fontSize; +} + +void PDFConverter::NewSignatureData::setFontSize(double fontSize) +{ + d->fontSize = fontSize; +} + +QColor PDFConverter::NewSignatureData::fontColor() const +{ + return d->fontColor; +} + +void PDFConverter::NewSignatureData::setFontColor(const QColor &color) +{ + d->fontColor = color; +} + +QColor PDFConverter::NewSignatureData::borderColor() const +{ + return d->borderColor; +} + +void PDFConverter::NewSignatureData::setBorderColor(const QColor &color) +{ + d->borderColor = color; +} + +QColor PDFConverter::NewSignatureData::backgroundColor() const +{ + return d->backgroundColor; +} + +void PDFConverter::NewSignatureData::setBackgroundColor(const QColor &color) +{ + d->backgroundColor = color; +} + +QString PDFConverter::NewSignatureData::fieldPartialName() const +{ + return d->partialName; +} + +void PDFConverter::NewSignatureData::setFieldPartialName(const QString &name) +{ + d->partialName = name; +} } diff --git a/qt6/src/poppler-qt6.h b/qt6/src/poppler-qt6.h index c3c3f631..229f6c93 100644 --- a/qt6/src/poppler-qt6.h +++ b/qt6/src/poppler-qt6.h @@ -22,6 +22,9 @@ * Copyright (C) 2019 Jan Grulich <[email protected]> * Copyright (C) 2019 Alexander Volkov <[email protected]> * Copyright (C) 2020 Philipp Knechtges <[email protected]> + * Copyright (C) 2020 Katarina Behrens <[email protected]> + * Copyright (C) 2020 Thorsten Behrens <[email protected]> + * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <[email protected]>. Work sponsored by Technische Universität Dresden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1944,6 +1947,86 @@ public: */ PDFOptions pdfOptions() const; + /** + * Holds data for a new signature + * - Common Name of cert to sign (aka nickname) + * - password for the cert + * - page where to add the signature + * - rect for the signature annotation + * - text that will be shown inside the rect + * - font size and color + * - border and background color + * \since 20.12 + */ + class NewSignatureData + { + public: + NewSignatureData(); + ~NewSignatureData(); + NewSignatureData(const NewSignatureData &) = delete; + NewSignatureData &operator=(const NewSignatureData &) = delete; + + QString certNickname() const; + void setCertNickname(const QString &certNickname); + + QString password() const; + void setPassword(const QString &password); + + int page() const; + void setPage(int page); + + QRectF boundingRectangle() const; + void setBoundingRectangle(const QRectF &rect); + + QString signatureText() const; + void setSignatureText(const QString &text); + + /** + * Default: 10 + */ + double fontSize() const; + void setFontSize(double fontSize); + + /** + * Default: red + */ + QColor fontColor() const; + void setFontColor(const QColor &color); + + /** + * Default: red + */ + QColor borderColor() const; + void setBorderColor(const QColor &color); + + /** + * Default: QColor(240, 240, 240) + */ + QColor backgroundColor() const; + void setBackgroundColor(const QColor &color); + + /** + * Default: QUuid::createUuid().toString() + */ + QString fieldPartialName() const; + void setFieldPartialName(const QString &name); + + private: + struct NewSignatureDataPrivate; + NewSignatureDataPrivate *const d; + }; + + /** + Sign PDF at given Annotation / signature form + + \param data new signature data + + \return whether the signing succeeded + + \since 20.12 + */ + bool sign(const NewSignatureData &data); + bool convert() override; private: _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
