summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2020-06-15 14:44:19 +0200
committerTomaž Vajngerl <quikee@gmail.com>2020-06-20 14:24:33 +0200
commit7e4dc3b1eabcb1993d4143c046a2f32fedc852ed (patch)
tree20af7c9e4d2502e713e2ed0f672c1cc2d9c293e5
parent03f0ea92bc381ef5a8df7de1ae9edf4aed45a3b2 (diff)
vcl: Add annotation reading to PDFiumLibrary c++ wrapper
Also add tests readin annotations from Evince and Acrobat modified PDF files. Change-Id: I4565c6b621774fc8485a6c33bc18708664917b73 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96756 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r--include/vcl/filter/PDFiumLibrary.hxx30
-rw-r--r--vcl/qa/cppunit/PDFiumLibraryTest.cxx135
-rw-r--r--vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdfbin0 -> 21709 bytes
-rw-r--r--vcl/qa/cppunit/data/PangramWithAnnotations.pdfbin0 -> 17785 bytes
-rw-r--r--vcl/source/pdf/PDFiumLibrary.cxx73
5 files changed, 238 insertions, 0 deletions
diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
index 6dde31f2927b..9deff47e0ab9 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -19,12 +19,17 @@
#include <memory>
#include <rtl/instance.hxx>
#include <basegfx/vector/b2dsize.hxx>
+#include <basegfx/range/b2drectangle.hxx>
#include <rtl/ustring.hxx>
#include <fpdf_doc.h>
namespace vcl::pdf
{
+constexpr char constDictionaryKeyTitle[] = "T";
+constexpr char constDictionaryKeyContents[] = "Contents";
+constexpr char constDictionaryKeyPopup[] = "Popup";
+
class PDFiumDocument;
class VCL_DLLPUBLIC PDFium final
@@ -44,6 +49,26 @@ public:
std::unique_ptr<PDFiumDocument> openDocument(const void* pData, int nSize);
};
+class VCL_DLLPUBLIC PDFiumAnnotation final
+{
+private:
+ FPDF_ANNOTATION mpAnnotation;
+
+ PDFiumAnnotation(const PDFiumAnnotation&) = delete;
+ PDFiumAnnotation& operator=(const PDFiumAnnotation&) = delete;
+
+public:
+ PDFiumAnnotation(FPDF_ANNOTATION pAnnotation);
+ ~PDFiumAnnotation();
+ FPDF_ANNOTATION getPointer() { return mpAnnotation; }
+
+ int getSubType();
+ basegfx::B2DRectangle getRectangle();
+ bool hasKey(OString const& rKey);
+ OUString getString(OString const& rKey);
+ std::unique_ptr<PDFiumAnnotation> getLinked(OString const& rKey);
+};
+
class VCL_DLLPUBLIC PDFiumPage final
{
private:
@@ -64,6 +89,11 @@ public:
if (mpPage)
FPDF_ClosePage(mpPage);
}
+
+ int getAnnotationCount();
+ int getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation);
+
+ std::unique_ptr<PDFiumAnnotation> getAnnotation(int nIndex);
};
class VCL_DLLPUBLIC PDFiumDocument final
diff --git a/vcl/qa/cppunit/PDFiumLibraryTest.cxx b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
index 422325aa9b1d..c786b6edc211 100644
--- a/vcl/qa/cppunit/PDFiumLibraryTest.cxx
+++ b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
@@ -32,10 +32,14 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
void testDocument();
void testPages();
+ void testAnnotationsMadeInEvince();
+ void testAnnotationsMadeInAcrobat();
CPPUNIT_TEST_SUITE(PDFiumLibraryTest);
CPPUNIT_TEST(testDocument);
CPPUNIT_TEST(testPages);
+ CPPUNIT_TEST(testAnnotationsMadeInEvince);
+ CPPUNIT_TEST(testAnnotationsMadeInAcrobat);
CPPUNIT_TEST_SUITE_END();
};
@@ -96,6 +100,137 @@ void PDFiumLibraryTest::testPages()
CPPUNIT_ASSERT(pPage);
}
+void PDFiumLibraryTest::testAnnotationsMadeInEvince()
+{
+ OUString aURL = getFullUrl("PangramWithAnnotations.pdf");
+ SvFileStream aStream(aURL, StreamMode::READ);
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+ aGraphic.makeAvailable();
+
+ auto pVectorGraphicData = aGraphic.getVectorGraphicData();
+ CPPUNIT_ASSERT(pVectorGraphicData);
+ CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+ pVectorGraphicData->getVectorGraphicDataType());
+
+ const void* pData = pVectorGraphicData->getVectorGraphicDataArray().getConstArray();
+ int nLength = pVectorGraphicData->getVectorGraphicDataArrayLength();
+
+ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+ auto pDocument = pPdfium->openDocument(pData, nLength);
+ CPPUNIT_ASSERT(pDocument);
+
+ CPPUNIT_ASSERT_EQUAL(1, pDocument->getPageCount());
+
+ auto pPage = pDocument->openPage(0);
+ CPPUNIT_ASSERT(pPage);
+
+ CPPUNIT_ASSERT_EQUAL(2, pPage->getAnnotationCount());
+
+ {
+ auto pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(1, pAnnotation->getSubType()); // FPDF_ANNOT_TEXT
+
+ OUString aPopupString = pAnnotation->getString(vcl::pdf::constDictionaryKeyTitle);
+ CPPUNIT_ASSERT_EQUAL(OUString("quikee"), aPopupString);
+
+ OUString aContentsString = pAnnotation->getString(vcl::pdf::constDictionaryKeyContents);
+ CPPUNIT_ASSERT_EQUAL(OUString("Annotation test"), aContentsString);
+
+ CPPUNIT_ASSERT_EQUAL(true, pAnnotation->hasKey(vcl::pdf::constDictionaryKeyPopup));
+ auto pPopupAnnotation = pAnnotation->getLinked(vcl::pdf::constDictionaryKeyPopup);
+ CPPUNIT_ASSERT(pPopupAnnotation);
+
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationIndex(pPopupAnnotation));
+ CPPUNIT_ASSERT_EQUAL(16, pPopupAnnotation->getSubType());
+ }
+
+ {
+ auto pAnnotation = pPage->getAnnotation(1);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(16, pAnnotation->getSubType()); // FPDF_ANNOT_POPUP
+ }
+}
+
+void PDFiumLibraryTest::testAnnotationsMadeInAcrobat()
+{
+ OUString aURL = getFullUrl("PangramAcrobatAnnotations.pdf");
+ SvFileStream aStream(aURL, StreamMode::READ);
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+ aGraphic.makeAvailable();
+
+ auto pVectorGraphicData = aGraphic.getVectorGraphicData();
+ CPPUNIT_ASSERT(pVectorGraphicData);
+ CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+ pVectorGraphicData->getVectorGraphicDataType());
+
+ const void* pData = pVectorGraphicData->getVectorGraphicDataArray().getConstArray();
+ int nLength = pVectorGraphicData->getVectorGraphicDataArrayLength();
+
+ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+ auto pDocument = pPdfium->openDocument(pData, nLength);
+ CPPUNIT_ASSERT(pDocument);
+
+ CPPUNIT_ASSERT_EQUAL(1, pDocument->getPageCount());
+
+ auto pPage = pDocument->openPage(0);
+ CPPUNIT_ASSERT(pPage);
+
+ CPPUNIT_ASSERT_EQUAL(4, pPage->getAnnotationCount());
+
+ {
+ auto pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(1, pAnnotation->getSubType()); // FPDF_ANNOT_TEXT
+
+ OUString aPopupString = pAnnotation->getString(vcl::pdf::constDictionaryKeyTitle);
+ CPPUNIT_ASSERT_EQUAL(OUString("quikee"), aPopupString);
+
+ OUString aContentsString = pAnnotation->getString(vcl::pdf::constDictionaryKeyContents);
+ CPPUNIT_ASSERT_EQUAL(OUString("YEEEY"), aContentsString);
+
+ CPPUNIT_ASSERT_EQUAL(true, pAnnotation->hasKey(vcl::pdf::constDictionaryKeyPopup));
+ auto pPopupAnnotation = pAnnotation->getLinked(vcl::pdf::constDictionaryKeyPopup);
+ CPPUNIT_ASSERT(pPopupAnnotation);
+
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationIndex(pPopupAnnotation));
+ CPPUNIT_ASSERT_EQUAL(16, pPopupAnnotation->getSubType());
+ }
+
+ {
+ auto pAnnotation = pPage->getAnnotation(1);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(16, pAnnotation->getSubType()); // FPDF_ANNOT_POPUP
+ }
+
+ {
+ auto pAnnotation = pPage->getAnnotation(2);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(1, pAnnotation->getSubType()); // FPDF_ANNOT_TEXT
+
+ OUString aPopupString = pAnnotation->getString(vcl::pdf::constDictionaryKeyTitle);
+ CPPUNIT_ASSERT_EQUAL(OUString("quikee"), aPopupString);
+
+ OUString aContentsString = pAnnotation->getString(vcl::pdf::constDictionaryKeyContents);
+ CPPUNIT_ASSERT_EQUAL(OUString("Note"), aContentsString);
+
+ CPPUNIT_ASSERT_EQUAL(true, pAnnotation->hasKey(vcl::pdf::constDictionaryKeyPopup));
+ auto pPopupAnnotation = pAnnotation->getLinked(vcl::pdf::constDictionaryKeyPopup);
+ CPPUNIT_ASSERT(pPopupAnnotation);
+
+ CPPUNIT_ASSERT_EQUAL(3, pPage->getAnnotationIndex(pPopupAnnotation));
+ CPPUNIT_ASSERT_EQUAL(16, pPopupAnnotation->getSubType());
+ }
+
+ {
+ auto pAnnotation = pPage->getAnnotation(3);
+ CPPUNIT_ASSERT(pAnnotation);
+ CPPUNIT_ASSERT_EQUAL(16, pAnnotation->getSubType()); // FPDF_ANNOT_POPUP
+ }
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(PDFiumLibraryTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf b/vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf
new file mode 100644
index 000000000000..f97003a7f397
--- /dev/null
+++ b/vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf
Binary files differ
diff --git a/vcl/qa/cppunit/data/PangramWithAnnotations.pdf b/vcl/qa/cppunit/data/PangramWithAnnotations.pdf
new file mode 100644
index 000000000000..f69ddd987060
--- /dev/null
+++ b/vcl/qa/cppunit/data/PangramWithAnnotations.pdf
Binary files differ
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index edd7fe9f5283..faf59c24a5a3 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -13,6 +13,7 @@
#if HAVE_FEATURE_PDFIUM
#include <vcl/filter/PDFiumLibrary.hxx>
+#include <fpdf_annot.h>
#include <fpdf_edit.h>
namespace vcl::pdf
@@ -108,6 +109,78 @@ basegfx::B2DSize PDFiumDocument::getPageSize(int nIndex)
int PDFiumDocument::getPageCount() { return FPDF_GetPageCount(mpPdfDocument); }
+int PDFiumPage::getAnnotationCount() { return FPDFPage_GetAnnotCount(mpPage); }
+
+int PDFiumPage::getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation)
+{
+ return FPDFPage_GetAnnotIndex(mpPage, rAnnotation->getPointer());
+}
+
+std::unique_ptr<PDFiumAnnotation> PDFiumPage::getAnnotation(int nIndex)
+{
+ std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
+ FPDF_ANNOTATION pAnnotation = FPDFPage_GetAnnot(mpPage, nIndex);
+ if (pAnnotation)
+ {
+ pPDFiumAnnotation = std::make_unique<PDFiumAnnotation>(pAnnotation);
+ }
+ return pPDFiumAnnotation;
+}
+
+PDFiumAnnotation::PDFiumAnnotation(FPDF_ANNOTATION pAnnotation)
+ : mpAnnotation(pAnnotation)
+{
+}
+
+PDFiumAnnotation::~PDFiumAnnotation()
+{
+ if (mpAnnotation)
+ FPDFPage_CloseAnnot(mpAnnotation);
+}
+
+int PDFiumAnnotation::getSubType() { return FPDFAnnot_GetSubtype(mpAnnotation); }
+
+basegfx::B2DRectangle PDFiumAnnotation::getRectangle()
+{
+ basegfx::B2DRectangle aB2DRectangle;
+ FS_RECTF aRect;
+ if (FPDFAnnot_GetRect(mpAnnotation, &aRect))
+ {
+ aB2DRectangle = basegfx::B2DRectangle(aRect.left, aRect.top, aRect.right, aRect.bottom);
+ }
+ return aB2DRectangle;
+}
+
+bool PDFiumAnnotation::hasKey(OString const& rKey)
+{
+ return FPDFAnnot_HasKey(mpAnnotation, rKey.getStr());
+}
+
+OUString PDFiumAnnotation::getString(OString const& rKey)
+{
+ OUString rString;
+ unsigned long nSize = FPDFAnnot_GetStringValue(mpAnnotation, rKey.getStr(), nullptr, 0);
+ if (nSize > 2)
+ {
+ std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
+ unsigned long nStringSize = FPDFAnnot_GetStringValue(
+ mpAnnotation, rKey.getStr(), reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize);
+ if (nStringSize > 0)
+ rString = OUString(pText.get());
+ }
+ return rString;
+}
+
+std::unique_ptr<PDFiumAnnotation> PDFiumAnnotation::getLinked(OString const& rKey)
+{
+ std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
+ FPDF_ANNOTATION pAnnotation = FPDFAnnot_GetLinkedAnnot(mpAnnotation, rKey.getStr());
+ if (pAnnotation)
+ {
+ pPDFiumAnnotation = std::make_unique<PDFiumAnnotation>(pAnnotation);
+ }
+ return pPDFiumAnnotation;
+}
} // end vcl::pdf
#endif // HAVE_FEATURE_PDFIUM