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

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Sat Jun 20 12:25:14 UTC 2020


 include/vcl/filter/PDFiumLibrary.hxx              |   30 ++++
 vcl/qa/cppunit/PDFiumLibraryTest.cxx              |  135 ++++++++++++++++++++++
 vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf |binary
 vcl/qa/cppunit/data/PangramWithAnnotations.pdf    |binary
 vcl/source/pdf/PDFiumLibrary.cxx                  |   73 +++++++++++
 5 files changed, 238 insertions(+)

New commits:
commit 7e4dc3b1eabcb1993d4143c046a2f32fedc852ed
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Mon Jun 15 14:44:19 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Sat Jun 20 14:24:33 2020 +0200

    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 at gmail.com>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

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
Binary files /dev/null and b/vcl/qa/cppunit/data/PangramAcrobatAnnotations.pdf differ
diff --git a/vcl/qa/cppunit/data/PangramWithAnnotations.pdf b/vcl/qa/cppunit/data/PangramWithAnnotations.pdf
new file mode 100644
index 000000000000..f69ddd987060
Binary files /dev/null and b/vcl/qa/cppunit/data/PangramWithAnnotations.pdf 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


More information about the Libreoffice-commits mailing list