[Libreoffice-commits] core.git: include/vcl vcl/qa vcl/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Wed May 5 11:34:46 UTC 2021


 include/vcl/filter/PDFiumLibrary.hxx |    4 -
 vcl/qa/cppunit/PDFiumLibraryTest.cxx |   39 ++++++++++++++
 vcl/qa/cppunit/data/form-fields.pdf  |   95 +++++++++++++++++++++++++++++++++++
 vcl/source/filter/ipdf/pdfread.cxx   |    2 
 vcl/source/pdf/PDFiumLibrary.cxx     |   48 ++++++++++++++++-
 5 files changed, 181 insertions(+), 7 deletions(-)

New commits:
commit 92cba30d5ce45e4f4a9516a80c9fe9915add6905
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed May 5 11:18:30 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed May 5 13:34:04 2021 +0200

    vcl pdfium render: handle widget annotations for form fields
    
    Note that we render the bitmaps without FPDF_ANNOT, so comments are not
    rendered into the bitmaps, rather we create them on top of the bitmaps
    in Draw, explicitly.
    
    FPDF_FFLDraw() draws content which is already an annotation, but not yet
    interactive content; so this just fixes "missing text", as far as the
    user is concerned.
    
    Verified that e.g. vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf
    indeed still doesn't render comments into bitmaps after this.
    
    Change-Id: I2b74d585729305cc1d3a9fefa258d4d76d1bd038
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115122
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins

diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
index 3d6f379c683a..c5f1766f60c0 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -67,8 +67,8 @@ class VCL_DLLPUBLIC PDFiumBitmap
 public:
     virtual ~PDFiumBitmap() = default;
     virtual void fillRect(int left, int top, int width, int height, sal_uInt32 nColor) = 0;
-    virtual void renderPageBitmap(PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX,
-                                  int nSizeY)
+    virtual void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY,
+                                  int nSizeX, int nSizeY)
         = 0;
     virtual ConstScanline getBuffer() = 0;
     virtual int getStride() = 0;
diff --git a/vcl/qa/cppunit/PDFiumLibraryTest.cxx b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
index 71ed79dd59e3..707d60fd1c3b 100644
--- a/vcl/qa/cppunit/PDFiumLibraryTest.cxx
+++ b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
@@ -23,6 +23,8 @@
 #include <tools/stream.hxx>
 
 #include <vcl/filter/PDFiumLibrary.hxx>
+#include <vcl/pdfread.hxx>
+#include <vcl/BitmapReadAccess.hxx>
 
 class PDFiumLibraryTest : public test::BootstrapFixtureBase
 {
@@ -38,6 +40,7 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
     void testAnnotationsMadeInAcrobat();
     void testAnnotationsDifferentTypes();
     void testTools();
+    void testFormFields();
 
     CPPUNIT_TEST_SUITE(PDFiumLibraryTest);
     CPPUNIT_TEST(testDocument);
@@ -47,6 +50,7 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
     CPPUNIT_TEST(testAnnotationsMadeInAcrobat);
     CPPUNIT_TEST(testAnnotationsDifferentTypes);
     CPPUNIT_TEST(testTools);
+    CPPUNIT_TEST(testFormFields);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -279,6 +283,41 @@ void PDFiumLibraryTest::testAnnotationsMadeInAcrobat()
     }
 }
 
+void PDFiumLibraryTest::testFormFields()
+{
+    // Given a document with a form field that looks like plain text:
+    OUString aURL = getFullUrl(u"form-fields.pdf");
+    SvFileStream aFileStream(aURL, StreamMode::READ);
+    SvMemoryStream aMemory;
+    aMemory.WriteStream(aFileStream);
+    aMemory.Seek(0);
+
+    // When rendering its first (and only) page to a bitmap:
+    std::vector<BitmapEx> aBitmaps;
+    int nRet = vcl::RenderPDFBitmaps(aMemory.GetData(), aMemory.GetSize(), aBitmaps);
+    CPPUNIT_ASSERT(nRet);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aBitmaps.size());
+
+    // Then make sure the bitmap contains that text:
+    Bitmap aBitmap = aBitmaps[0].GetBitmap();
+    BitmapReadAccess aAccess(aBitmap);
+    Size aSize = aBitmap.GetSizePixel();
+    std::set<sal_uInt32> aColors;
+    for (tools::Long y = 0; y < aSize.Height(); ++y)
+    {
+        for (tools::Long x = 0; x < aSize.Width(); ++x)
+        {
+            aColors.insert(static_cast<sal_uInt32>(aAccess.GetPixel(y, x)));
+        }
+    }
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 1
+    // - Actual  : 1
+    // i.e. at least black text and white background is expected (possibly more, due to
+    // anti-aliasing), but nothing was rendered.
+    CPPUNIT_ASSERT_GREATER(static_cast<size_t>(1), aColors.size());
+}
+
 void PDFiumLibraryTest::testAnnotationsDifferentTypes()
 {
     OUString aURL = getFullUrl(u"PangramWithMultipleTypeOfAnnotations.pdf");
diff --git a/vcl/qa/cppunit/data/form-fields.pdf b/vcl/qa/cppunit/data/form-fields.pdf
new file mode 100644
index 000000000000..a014b36c9821
--- /dev/null
+++ b/vcl/qa/cppunit/data/form-fields.pdf
@@ -0,0 +1,95 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 5 0 R
+>>
+endobj
+
+2 0 obj <<
+  /Length 0
+>>
+stream
+endstream 
+endobj
+
+3 0 obj <<
+  /Font <<
+    /TT1 4 0 R
+  >>
+>>
+endobj
+
+4 0 obj <<
+ /Type /Font
+ /Subtype /Type1
+ /Name /TT1
+ /BaseFont/Helvetica
+>>
+endobj
+
+5 0 obj <<
+  /Type /Pages
+  /Kids [6 0 R]
+  /Count 1
+  /MediaBox [ 0 0 612 446 ]
+>>
+endobj
+
+6 0 obj <<
+  /Type /Page
+  /Parent 5 0 R
+  /Resources 3 0 R
+  /Contents 2 0 R
+  /Annots [7 0 R]
+>>
+endobj
+
+7 0 obj <<
+  /Type /Annot
+  /Subtype /Widget
+  /T (T)
+  /V (V)
+  /DA (/Helv 0 Tf 0 g)
+  /Rect [ 0 0 612 446 ]
+  /FT /Tx
+  /AP <<
+    /N 8 0 R
+  >>
+>>
+endobj
+
+8 0 obj <<
+  /Type /XObject
+  /Subtype /Form
+  /Matrix [1.0 0.0 0.0 1.0 0.0 0.0]
+  /Resources 3 0 R
+  /BBox [ 0 0 612 446 ]
+  /Length 55
+>>
+stream
+  BT
+  /TT1 24 Tf
+  1 0 0 1 260 254 Tm
+  (test)Tj
+  ET
+endstream 
+endobj
+xref
+0 9
+0000000000 65535 f 
+0000000015 00000 n 
+0000000069 00000 n 
+0000000121 00000 n 
+0000000174 00000 n 
+0000000259 00000 n 
+0000000351 00000 n 
+0000000458 00000 n 
+0000000616 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 9
+>>
+startxref
+836
+%%EOF
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index be9738a9f32f..d97259d52807 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -185,7 +185,7 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<BitmapEx>& r
         }
         const sal_uInt32 nColor = bTransparent ? 0x00000000 : 0xFFFFFFFF;
         pPdfBitmap->fillRect(0, 0, nPageWidth, nPageHeight, nColor);
-        pPdfBitmap->renderPageBitmap(pPdfPage.get(), /*start_x=*/0,
+        pPdfBitmap->renderPageBitmap(pPdfDocument.get(), pPdfPage.get(), /*start_x=*/0,
                                      /*start_y=*/0, nPageWidth, nPageHeight);
 
         // Save the buffer as a bitmap.
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index e8951c476648..adfa4db4fa45 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -18,6 +18,7 @@
 #include <fpdf_text.h>
 #include <fpdf_save.h>
 #include <fpdf_signature.h>
+#include <fpdf_formfill.h>
 
 #include <osl/endian.h>
 #include <vcl/bitmap.hxx>
@@ -174,8 +175,8 @@ public:
     FPDF_BITMAP getPointer() { return mpBitmap; }
 
     void fillRect(int left, int top, int width, int height, sal_uInt32 nColor) override;
-    void renderPageBitmap(PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX,
-                          int nSizeY) override;
+    void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY,
+                          int nSizeX, int nSizeY) override;
     ConstScanline getBuffer() override;
     int getStride() override;
     int getWidth() override;
@@ -366,10 +367,27 @@ public:
     bool hasLinks() override;
 };
 
+/// Wrapper around FPDF_FORMHANDLE.
+class PDFiumFormHandle final
+{
+private:
+    FPDF_FORMHANDLE mpHandle;
+
+    PDFiumFormHandle(const PDFiumFormHandle&) = delete;
+    PDFiumFormHandle& operator=(const PDFiumFormHandle&) = delete;
+
+public:
+    PDFiumFormHandle(FPDF_FORMHANDLE pHandle);
+    ~PDFiumFormHandle();
+    FPDF_FORMHANDLE getPointer();
+};
+
 class PDFiumDocumentImpl : public PDFiumDocument
 {
 private:
     FPDF_DOCUMENT mpPdfDocument;
+    FPDF_FORMFILLINFO m_aFormCallbacks;
+    std::unique_ptr<PDFiumFormHandle> m_pFormHandle;
 
 private:
     PDFiumDocumentImpl(const PDFiumDocumentImpl&) = delete;
@@ -378,6 +396,7 @@ private:
 public:
     PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument);
     ~PDFiumDocumentImpl() override;
+    FPDF_FORMHANDLE getFormHandlePointer();
 
     // Page size in points
     basegfx::B2DSize getPageSize(int nIndex) override;
@@ -574,15 +593,22 @@ util::DateTime PDFiumSignatureImpl::getTime()
 
 PDFiumDocumentImpl::PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument)
     : mpPdfDocument(pPdfDocument)
+    , m_aFormCallbacks()
 {
+    m_aFormCallbacks.version = 1;
+    m_pFormHandle = std::make_unique<PDFiumFormHandle>(
+        FPDFDOC_InitFormFillEnvironment(pPdfDocument, &m_aFormCallbacks));
 }
 
 PDFiumDocumentImpl::~PDFiumDocumentImpl()
 {
+    m_pFormHandle.reset();
     if (mpPdfDocument)
         FPDF_CloseDocument(mpPdfDocument);
 }
 
+FPDF_FORMHANDLE PDFiumDocumentImpl::getFormHandlePointer() { return m_pFormHandle->getPointer(); }
+
 std::unique_ptr<PDFiumPage> PDFiumDocumentImpl::openPage(int nIndex)
 {
     std::unique_ptr<PDFiumPage> pPDFiumPage;
@@ -931,6 +957,15 @@ PDFSegmentType PDFiumPathSegmentImpl::getType() const
     return static_cast<PDFSegmentType>(FPDFPathSegment_GetType(mpPathSegment));
 }
 
+PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle)
+    : mpHandle(pHandle)
+{
+}
+
+PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle); }
+
+FPDF_FORMHANDLE PDFiumFormHandle::getPointer() { return mpHandle; }
+
 PDFiumBitmapImpl::PDFiumBitmapImpl(FPDF_BITMAP pBitmap)
     : mpBitmap(pBitmap)
 {
@@ -949,12 +984,17 @@ void PDFiumBitmapImpl::fillRect(int left, int top, int width, int height, sal_uI
     FPDFBitmap_FillRect(mpBitmap, left, top, width, height, nColor);
 }
 
-void PDFiumBitmapImpl::renderPageBitmap(PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX,
-                                        int nSizeY)
+void PDFiumBitmapImpl::renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX,
+                                        int nStartY, int nSizeX, int nSizeY)
 {
     auto pPageImpl = static_cast<PDFiumPageImpl*>(pPage);
     FPDF_RenderPageBitmap(mpBitmap, pPageImpl->getPointer(), nStartX, nStartY, nSizeX, nSizeY,
                           /*rotate=*/0, /*flags=*/0);
+
+    // Render widget annotations for FormFields.
+    auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
+    FPDF_FFLDraw(pDocImpl->getFormHandlePointer(), mpBitmap, pPageImpl->getPointer(), nStartX,
+                 nStartY, nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0);
 }
 
 ConstScanline PDFiumBitmapImpl::getBuffer()


More information about the Libreoffice-commits mailing list