aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2021-05-05 11:18:30 +0200
committerTomaž Vajngerl <quikee@gmail.com>2021-05-06 11:22:20 +0200
commit521241d0b73812389bec03b4d5ab028dbe672fb0 (patch)
tree67e8aec3f737a1c78744ee1e94d53847d750b4fb
parent01765acee6b4931b6c69252b8357f81fd26e33bd (diff)
vcl pdfium render: handle widget annotations for form fields distro/collabora/co-2021
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. (cherry picked from commit 92cba30d5ce45e4f4a9516a80c9fe9915add6905) Conflicts: include/vcl/filter/PDFiumLibrary.hxx vcl/source/pdf/PDFiumLibrary.cxx Change-Id: I2b74d585729305cc1d3a9fefa258d4d76d1bd038 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115149 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r--include/vcl/filter/PDFiumLibrary.hxx22
-rw-r--r--vcl/qa/cppunit/PDFiumLibraryTest.cxx39
-rw-r--r--vcl/qa/cppunit/data/form-fields.pdf95
-rw-r--r--vcl/source/filter/ipdf/pdfread.cxx2
-rw-r--r--vcl/source/pdf/PDFiumLibrary.cxx25
5 files changed, 179 insertions, 4 deletions
diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
index 8d139889591a..c61860b3a530 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -31,6 +31,7 @@
#include <vcl/pdf/PDFPageObjectType.hxx>
#include <fpdf_doc.h>
+#include <fpdf_formfill.h>
class SvMemoryStream;
@@ -79,7 +80,8 @@ public:
~PDFiumBitmap();
FPDF_BITMAP getPointer() { return mpBitmap; }
void fillRect(int left, int top, int width, int height, sal_uInt32 nColor);
- void renderPageBitmap(PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX, int nSizeY);
+ void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY,
+ int nSizeX, int nSizeY);
ConstScanline getBuffer();
int getStride();
};
@@ -244,10 +246,27 @@ public:
FPDF_SIGNATURE getPointer() { return mpSignature; }
};
+/// 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 VCL_DLLPUBLIC PDFiumDocument final
{
private:
FPDF_DOCUMENT mpPdfDocument;
+ FPDF_FORMFILLINFO m_aFormCallbacks;
+ std::unique_ptr<PDFiumFormHandle> m_pFormHandle;
private:
PDFiumDocument(const PDFiumDocument&) = delete;
@@ -256,6 +275,7 @@ private:
public:
PDFiumDocument(FPDF_DOCUMENT pPdfDocument);
~PDFiumDocument();
+ FPDF_FORMHANDLE getFormHandlePointer();
// Page size in points
basegfx::B2DSize getPageSize(int nIndex);
diff --git a/vcl/qa/cppunit/PDFiumLibraryTest.cxx b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
index 577f73ed1130..9ae14625b4f7 100644
--- a/vcl/qa/cppunit/PDFiumLibraryTest.cxx
+++ b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
@@ -25,6 +25,8 @@
#include <tools/stream.hxx>
#include <vcl/filter/PDFiumLibrary.hxx>
+#include <vcl/pdfread.hxx>
+#include <vcl/bitmapaccess.hxx>
class PDFiumLibraryTest : public test::BootstrapFixtureBase
{
@@ -40,6 +42,7 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
void testAnnotationsMadeInAcrobat();
void testAnnotationsDifferentTypes();
void testTools();
+ void testFormFields();
CPPUNIT_TEST_SUITE(PDFiumLibraryTest);
CPPUNIT_TEST(testDocument);
@@ -49,6 +52,7 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
CPPUNIT_TEST(testAnnotationsMadeInAcrobat);
CPPUNIT_TEST(testAnnotationsDifferentTypes);
CPPUNIT_TEST(testTools);
+ CPPUNIT_TEST(testFormFields);
CPPUNIT_TEST_SUITE_END();
};
@@ -291,6 +295,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("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 715333b2d561..899b652049b0 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -198,7 +198,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 3e9ae64dc950..76a70ad107b1 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -20,6 +20,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>
@@ -198,15 +199,22 @@ PDFiumSignature::PDFiumSignature(FPDF_SIGNATURE pSignature)
PDFiumDocument::PDFiumDocument(FPDF_DOCUMENT pPdfDocument)
: mpPdfDocument(pPdfDocument)
+ , m_aFormCallbacks()
{
+ m_aFormCallbacks.version = 1;
+ m_pFormHandle = std::make_unique<PDFiumFormHandle>(
+ FPDFDOC_InitFormFillEnvironment(pPdfDocument, &m_aFormCallbacks));
}
PDFiumDocument::~PDFiumDocument()
{
+ m_pFormHandle.reset();
if (mpPdfDocument)
FPDF_CloseDocument(mpPdfDocument);
}
+FPDF_FORMHANDLE PDFiumDocument::getFormHandlePointer() { return m_pFormHandle->getPointer(); }
+
std::unique_ptr<PDFiumPage> PDFiumDocument::openPage(int nIndex)
{
std::unique_ptr<PDFiumPage> pPDFiumPage;
@@ -524,6 +532,15 @@ bool PDFiumPathSegment::isClosed() const { return FPDFPathSegment_GetClose(mpPat
int PDFiumPathSegment::getType() const { return FPDFPathSegment_GetType(mpPathSegment); }
+PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle)
+ : mpHandle(pHandle)
+{
+}
+
+PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle); }
+
+FPDF_FORMHANDLE PDFiumFormHandle::getPointer() { return mpHandle; }
+
PDFiumBitmap::PDFiumBitmap(FPDF_BITMAP pBitmap)
: mpBitmap(pBitmap)
{
@@ -542,11 +559,15 @@ void PDFiumBitmap::fillRect(int left, int top, int width, int height, sal_uInt32
FPDFBitmap_FillRect(mpBitmap, left, top, width, height, nColor);
}
-void PDFiumBitmap::renderPageBitmap(PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX,
- int nSizeY)
+void PDFiumBitmap::renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX,
+ int nStartY, int nSizeX, int nSizeY)
{
FPDF_RenderPageBitmap(mpBitmap, pPage->getPointer(), nStartX, nStartY, nSizeX, nSizeY,
/*rotate=*/0, /*flags=*/0);
+
+ // Render widget annotations for FormFields.
+ FPDF_FFLDraw(pDoc->getFormHandlePointer(), mpBitmap, pPage->getPointer(), nStartX, nStartY,
+ nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0);
}
ConstScanline PDFiumBitmap::getBuffer()