summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-06-17 16:05:36 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-06-17 17:34:51 +0200
commit4db25ccc736185c304f1bd090b8539868932700a (patch)
tree512af5721484ff188fa59ebf698c27b4e277ef4a
parent02c0e015f84ddcc6fa94433f603ef89f358a0391 (diff)
sd signature line: implement non-empty geometry during pdf sign
Parse the pdf output which contains just the signature line shape on a page, take the same from it and use it at both places where previously the position / size was just a stub. Change-Id: Ifb2e0ebf7b3514ee027701b9bf360a0c996cdc82 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96540 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--include/vcl/filter/pdfdocument.hxx10
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx77
2 files changed, 79 insertions, 8 deletions
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index 8700e4892df2..aaf64ae908fe 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -29,6 +29,11 @@ namespace com::sun::star::uno
template <class interface_type> class Reference;
}
+namespace tools
+{
+class Rectangle;
+}
+
namespace vcl::filter
{
class PDFTrailerElement;
@@ -353,10 +358,11 @@ class VCL_DLLPUBLIC PDFDocument
sal_Int32 WriteSignatureObject(const OUString& rDescription, bool bAdES,
sal_uInt64& rLastByteRangeOffset, sal_Int64& rContentOffset);
/// Write the appearance object as part of signing.
- sal_Int32 WriteAppearanceObject();
+ sal_Int32 WriteAppearanceObject(tools::Rectangle& rSignatureRectangle);
/// Write the annot object as part of signing.
sal_Int32 WriteAnnotObject(PDFObjectElement const& rFirstPage, sal_Int32 nSignatureId,
- sal_Int32 nAppearanceId);
+ sal_Int32 nAppearanceId,
+ const tools::Rectangle& rSignatureRectangle);
/// Write the updated Page object as part of signing.
bool WritePageObject(PDFObjectElement& rFirstPage, sal_Int32 nAnnotId);
/// Write the updated Catalog object as part of signing.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 316b8c74d169..928f22d8a8c7 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -236,8 +236,62 @@ sal_Int32 PDFDocument::WriteSignatureObject(const OUString& rDescription, bool b
return nSignatureId;
}
-sal_Int32 PDFDocument::WriteAppearanceObject()
+sal_Int32 PDFDocument::WriteAppearanceObject(tools::Rectangle& rSignatureRectangle)
{
+ if (!m_aSignatureLine.empty())
+ {
+ // Parse the PDF data of signature line: we can set the signature rectangle to non-empty
+ // based on it.
+ SvMemoryStream aPDFStream;
+ aPDFStream.WriteBytes(m_aSignatureLine.data(), m_aSignatureLine.size());
+ aPDFStream.Seek(0);
+ filter::PDFDocument aPDFDocument;
+ if (!aPDFDocument.Read(aPDFStream))
+ {
+ SAL_WARN("vcl.filter",
+ "PDFDocument::WriteAppearanceObject: failed to read the PDF document");
+ return -1;
+ }
+
+ std::vector<filter::PDFObjectElement*> aPages = aPDFDocument.GetPages();
+ if (aPages.empty())
+ {
+ SAL_WARN("vcl.filter", "PDFDocument::WriteAppearanceObject: no pages");
+ return -1;
+ }
+
+ filter::PDFObjectElement* pPage = aPages[0];
+ if (!pPage)
+ {
+ SAL_WARN("vcl.filter", "PDFDocument::WriteAppearanceObject: no page");
+ return -1;
+ }
+
+ // Calculate the bounding box.
+ PDFElement* pMediaBox = pPage->Lookup("MediaBox");
+ auto pMediaBoxArray = dynamic_cast<PDFArrayElement*>(pMediaBox);
+ if (!pMediaBoxArray || pMediaBoxArray->GetElements().size() < 4)
+ {
+ SAL_WARN("vcl.filter",
+ "PDFDocument::WriteAppearanceObject: MediaBox is not an array of 4");
+ return -1;
+ }
+ const std::vector<PDFElement*>& rMediaBoxElements = pMediaBoxArray->GetElements();
+ auto pWidth = dynamic_cast<PDFNumberElement*>(rMediaBoxElements[2]);
+ if (!pWidth)
+ {
+ SAL_WARN("vcl.filter", "PDFDocument::WriteAppearanceObject: MediaBox has no width");
+ return -1;
+ }
+ rSignatureRectangle.setWidth(pWidth->GetValue());
+ auto pHeight = dynamic_cast<PDFNumberElement*>(rMediaBoxElements[3]);
+ if (!pHeight)
+ {
+ SAL_WARN("vcl.filter", "PDFDocument::WriteAppearanceObject: MediaBox has no height");
+ return -1;
+ }
+ rSignatureRectangle.setHeight(pHeight->GetValue());
+ }
m_aSignatureLine.clear();
// Write appearance object.
@@ -249,14 +303,19 @@ sal_Int32 PDFDocument::WriteAppearanceObject()
m_aEditBuffer.WriteUInt32AsString(nAppearanceId);
m_aEditBuffer.WriteCharPtr(" 0 obj\n");
m_aEditBuffer.WriteCharPtr("<</Type/XObject\n/Subtype/Form\n");
- m_aEditBuffer.WriteCharPtr("/BBox[0 0 0 0]\n/Length 0\n>>\n");
+ m_aEditBuffer.WriteCharPtr("/BBox[0 0 ");
+ m_aEditBuffer.WriteOString(OString::number(rSignatureRectangle.getWidth()));
+ m_aEditBuffer.WriteCharPtr(" ");
+ m_aEditBuffer.WriteOString(OString::number(rSignatureRectangle.getHeight()));
+ m_aEditBuffer.WriteCharPtr("]\n/Length 0\n>>\n");
m_aEditBuffer.WriteCharPtr("stream\n\nendstream\nendobj\n\n");
return nAppearanceId;
}
sal_Int32 PDFDocument::WriteAnnotObject(PDFObjectElement const& rFirstPage, sal_Int32 nSignatureId,
- sal_Int32 nAppearanceId)
+ sal_Int32 nAppearanceId,
+ const tools::Rectangle& rSignatureRectangle)
{
// Decide what identifier to use for the new signature.
sal_uInt32 nNextSignature = GetNextSignature();
@@ -270,7 +329,11 @@ sal_Int32 PDFDocument::WriteAnnotObject(PDFObjectElement const& rFirstPage, sal_
m_aEditBuffer.WriteUInt32AsString(nAnnotId);
m_aEditBuffer.WriteCharPtr(" 0 obj\n");
m_aEditBuffer.WriteCharPtr("<</Type/Annot/Subtype/Widget/F 132\n");
- m_aEditBuffer.WriteCharPtr("/Rect[0 0 0 0]\n");
+ m_aEditBuffer.WriteCharPtr("/Rect[0 0 ");
+ m_aEditBuffer.WriteOString(OString::number(rSignatureRectangle.getWidth()));
+ m_aEditBuffer.WriteCharPtr(" ");
+ m_aEditBuffer.WriteOString(OString::number(rSignatureRectangle.getHeight()));
+ m_aEditBuffer.WriteCharPtr("]\n");
m_aEditBuffer.WriteCharPtr("/FT/Sig\n");
m_aEditBuffer.WriteCharPtr("/P ");
m_aEditBuffer.WriteUInt32AsString(rFirstPage.GetObjectValue());
@@ -807,7 +870,8 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat
sal_Int32 nSignatureId = WriteSignatureObject(
rDescription, bAdES, nSignatureLastByteRangeOffset, nSignatureContentOffset);
- sal_Int32 nAppearanceId = WriteAppearanceObject();
+ tools::Rectangle aSignatureRectangle;
+ sal_Int32 nAppearanceId = WriteAppearanceObject(aSignatureRectangle);
std::vector<PDFObjectElement*> aPages = GetPages();
if (aPages.empty() || !aPages[0])
@@ -817,7 +881,8 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat
}
PDFObjectElement& rFirstPage = *aPages[0];
- sal_Int32 nAnnotId = WriteAnnotObject(rFirstPage, nSignatureId, nAppearanceId);
+ sal_Int32 nAnnotId
+ = WriteAnnotObject(rFirstPage, nSignatureId, nAppearanceId, aSignatureRectangle);
if (!WritePageObject(rFirstPage, nAnnotId))
{