[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - 2 commits - include/vcl sd/qa sd/source vcl/qa vcl/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Mon Jun 29 18:37:45 UTC 2020


 include/vcl/filter/PDFiumLibrary.hxx  |    6 +
 include/vcl/pdfread.hxx               |    2 
 sd/qa/unit/SdrPdfImportTest.cxx       |  132 ++++++++++++++++++++++++++++++++++
 sd/qa/unit/data/PdfWithAnnotation.pdf |binary
 sd/source/filter/pdf/sdpdffilter.cxx  |    1 
 vcl/qa/cppunit/PDFiumLibraryTest.cxx  |   25 ++++++
 vcl/source/filter/ipdf/pdfread.cxx    |   12 +++
 vcl/source/pdf/PDFiumLibrary.cxx      |   57 ++++++++++++++
 8 files changed, 234 insertions(+), 1 deletion(-)

New commits:
commit 8e1ce59359844bf22db431cac7ebb924c19075a8
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri Jun 19 12:59:59 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Jun 29 20:37:29 2020 +0200

    sd: Test PDF Annotation roundtrip
    
    Change-Id: I2532ecb451362b3b48c8c08b79c010dcad67d5da
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96760
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    (cherry picked from commit 037463d2617e5d7bbaea6b99f6b8ffd265cb38af)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97441
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>

diff --git a/sd/qa/unit/SdrPdfImportTest.cxx b/sd/qa/unit/SdrPdfImportTest.cxx
index a22579d67526..16b31774a784 100644
--- a/sd/qa/unit/SdrPdfImportTest.cxx
+++ b/sd/qa/unit/SdrPdfImportTest.cxx
@@ -16,7 +16,11 @@
 
 #include <comphelper/scopeguard.hxx>
 #include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
 
+#include <unotools/tempfile.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <tools/stream.hxx>
 #include <svx/svdograf.hxx>
 #include <editeng/outlobj.hxx>
 #include <editeng/editobj.hxx>
@@ -124,6 +128,134 @@ CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testImportSimpleText)
 #endif // HAVE_FEATURE_PDFIUM
 }
 
+CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testAnnotationsImportExport)
+{
+#if HAVE_FEATURE_PDFIUM && !defined(_WIN32)
+    // We need to enable PDFium import (and make sure to disable after the test)
+    bool bResetEnvVar = false;
+    if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr)
+    {
+        bResetEnvVar = true;
+        setenv("LO_IMPORT_USE_PDFIUM", "1", false);
+    }
+    comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() {
+        if (bResetEnvVar)
+            unsetenv("LO_IMPORT_USE_PDFIUM");
+    });
+
+    bool bPDFCompressorResetEnvVar = false;
+    if (getenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION") == nullptr)
+    {
+        bPDFCompressorResetEnvVar = true;
+        setenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION", "1", false);
+    }
+    comphelper::ScopeGuard aPDFCompressorEnvVarGuard([&]() {
+        if (bPDFCompressorResetEnvVar)
+            unsetenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION");
+    });
+
+    auto pPdfiumLibrary = vcl::pdf::PDFiumLibrary::get();
+
+    mxComponent
+        = loadFromDesktop(m_directories.getURLFromSrc("sd/qa/unit/data/PdfWithAnnotation.pdf"));
+    auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
+    sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+
+    const void* pData = nullptr;
+    int nLength = 0;
+
+    {
+        // Get the first page - there should be only one.
+        SdPage* pPage = pViewShell->GetActualPage();
+        CPPUNIT_ASSERT(pPage);
+
+        // Check the number of annotations
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pPage->getAnnotations().size());
+
+        // Get the first object - there should be only one.
+        SdrObject* pObject = pPage->GetObj(0);
+        CPPUNIT_ASSERT(pObject);
+
+        // Check the object is a graphic object
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+
+        // Check the graphic is a vector graphic and that it is PDF
+        Graphic aGraphic = pGraphicObject->GetGraphic();
+        auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+
+        // Write the PDF
+        pData = pVectorGraphicData->getVectorGraphicDataArray().getConstArray();
+        nLength = pVectorGraphicData->getVectorGraphicDataArrayLength();
+    }
+
+    { // check graphic PDF has annotations
+
+        auto pPDFDocument = pPdfiumLibrary->openDocument(pData, nLength);
+        auto pPDFPage = pPDFDocument->openPage(0);
+
+        CPPUNIT_ASSERT_EQUAL(2, pPDFPage->getAnnotationCount());
+
+        auto pPDFAnnotation1 = pPDFPage->getAnnotation(0);
+        CPPUNIT_ASSERT_EQUAL(1, pPDFAnnotation1->getSubType()); // Text annotation
+
+        auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
+        CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
+    }
+
+    { // save as PDF and check annotations
+        utl::TempFile aTempFile;
+        aTempFile.EnableKillingFile();
+
+        uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+        utl::MediaDescriptor aMediaDescriptor;
+        aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+        uno::Sequence<beans::PropertyValue> aFilterData(
+            comphelper::InitPropertySequence({ { "ExportBookmarks", uno::Any(true) } }));
+        aMediaDescriptor["FilterData"] <<= aFilterData;
+        xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+        mxComponent->dispose();
+
+        SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
+        SvMemoryStream aMemory;
+        aMemory.WriteStream(aFile);
+
+        // Check PDF for annotations
+        auto pPDFDocument = pPdfiumLibrary->openDocument(aMemory.GetData(), aMemory.GetSize());
+        CPPUNIT_ASSERT(pPDFDocument);
+        CPPUNIT_ASSERT_EQUAL(1, pPDFDocument->getPageCount());
+
+        auto pPDFPage = pPDFDocument->openPage(0);
+        CPPUNIT_ASSERT(pPDFPage);
+
+        // TODO: Should be 2 really
+        CPPUNIT_ASSERT_EQUAL(1, pPDFPage->getAnnotationCount());
+
+        auto pPDFAnnotation1 = pPDFPage->getAnnotation(0);
+        CPPUNIT_ASSERT_EQUAL(1, pPDFAnnotation1->getSubType()); // Text annotation
+
+        //auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
+        //CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
+
+        // Load document again
+        mxComponent = loadFromDesktop(aTempFile.GetURL());
+        auto pNewImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
+        sd::ViewShell* pNewViewShell = pNewImpressDocument->GetDocShell()->GetViewShell();
+        CPPUNIT_ASSERT(pNewViewShell);
+
+        SdPage* pPage = pNewViewShell->GetActualPage();
+        CPPUNIT_ASSERT(pPage);
+
+        //CPPUNIT_ASSERT_EQUAL(false, pPage->getAnnotations().empty());
+    }
+
+#endif // HAVE_FEATURE_PDFIUM
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/data/PdfWithAnnotation.pdf b/sd/qa/unit/data/PdfWithAnnotation.pdf
new file mode 100644
index 000000000000..09529ed17884
Binary files /dev/null and b/sd/qa/unit/data/PdfWithAnnotation.pdf differ
commit 3289b5f8556c16390f7c2fbba613196ebe52fe2a
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Thu Jun 18 13:50:15 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Jun 29 20:37:14 2020 +0200

    support date and time for PDFium and use it for annotations
    
    PDF annotations have the modification date and time accessible in
    the PDF specific format. With PDFium we read the annotation date
    and time and convert that to css::utils::DateTime (by converting
    to ISO8601 compatible string first).
    
    Add support for modification date and tme for annotations into
    ImportPDFUnloaded and when the annotations are inserted into the
    document as comments (in Draw document).
    
    Change-Id: I24aacde84b7530365d67ed335b1eefbaee706eca
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96759
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    (cherry picked from commit 4e3196ceedc2b79d58bb57dba86f2f0158d32998)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97440
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>

diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
index 9deff47e0ab9..2a70c3f89bce 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -29,7 +29,7 @@ namespace vcl::pdf
 constexpr char constDictionaryKeyTitle[] = "T";
 constexpr char constDictionaryKeyContents[] = "Contents";
 constexpr char constDictionaryKeyPopup[] = "Popup";
-
+constexpr char constDictionaryKeyModificationDate[] = "M";
 class PDFiumDocument;
 
 class VCL_DLLPUBLIC PDFium final
@@ -121,6 +121,10 @@ struct PDFiumLibrary final : public rtl::StaticWithInit<std::shared_ptr<PDFium>,
     std::shared_ptr<PDFium> operator()() { return std::make_shared<PDFium>(); }
 };
 
+// Tools
+
+VCL_DLLPUBLIC OUString convertPdfDateToISO8601(OUString const& rInput);
+
 } // namespace vcl::pdf
 
 #endif // HAVE_FEATURE_PDFIUM
diff --git a/include/vcl/pdfread.hxx b/include/vcl/pdfread.hxx
index d79115f40249..f1534c326ee6 100644
--- a/include/vcl/pdfread.hxx
+++ b/include/vcl/pdfread.hxx
@@ -15,6 +15,7 @@
 #include <tools/stream.hxx>
 #include <vcl/graph.hxx>
 #include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/util/DateTime.hpp>
 
 namespace com::sun::star::uno
 {
@@ -38,6 +39,7 @@ struct PDFGraphicAnnotation
     OUString maText;
     // In HMM
     basegfx::B2DRectangle maRectangle;
+    css::util::DateTime maDateTime;
 };
 
 struct PDFGraphicResult
diff --git a/sd/source/filter/pdf/sdpdffilter.cxx b/sd/source/filter/pdf/sdpdffilter.cxx
index 552e19f597e9..43c6c6fdac36 100644
--- a/sd/source/filter/pdf/sdpdffilter.cxx
+++ b/sd/source/filter/pdf/sdpdffilter.cxx
@@ -90,6 +90,7 @@ bool SdPdfFilter::Import()
                                           rPDFAnnotation.maRectangle.getHeight() / 100.00);
             xAnnotation->setPosition(aUnoPosition);
             xAnnotation->setSize(aUnoSize);
+            xAnnotation->setDateTime(rPDFAnnotation.maDateTime);
         }
     }
 
diff --git a/vcl/qa/cppunit/PDFiumLibraryTest.cxx b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
index c786b6edc211..61b3981731f6 100644
--- a/vcl/qa/cppunit/PDFiumLibraryTest.cxx
+++ b/vcl/qa/cppunit/PDFiumLibraryTest.cxx
@@ -16,6 +16,9 @@
 
 #include <unotest/bootstrapfixturebase.hxx>
 #include <unotest/directories.hxx>
+#include <unotools/datetime.hxx>
+
+#include <com/sun/star/util/DateTime.hpp>
 
 #include <vcl/graph.hxx>
 #include <vcl/graphicfilter.hxx>
@@ -34,12 +37,14 @@ class PDFiumLibraryTest : public test::BootstrapFixtureBase
     void testPages();
     void testAnnotationsMadeInEvince();
     void testAnnotationsMadeInAcrobat();
+    void testTools();
 
     CPPUNIT_TEST_SUITE(PDFiumLibraryTest);
     CPPUNIT_TEST(testDocument);
     CPPUNIT_TEST(testPages);
     CPPUNIT_TEST(testAnnotationsMadeInEvince);
     CPPUNIT_TEST(testAnnotationsMadeInAcrobat);
+    CPPUNIT_TEST(testTools);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -144,6 +149,10 @@ void PDFiumLibraryTest::testAnnotationsMadeInEvince()
 
         CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationIndex(pPopupAnnotation));
         CPPUNIT_ASSERT_EQUAL(16, pPopupAnnotation->getSubType());
+
+        OUString sDateTimeString
+            = pAnnotation->getString(vcl::pdf::constDictionaryKeyModificationDate);
+        CPPUNIT_ASSERT_EQUAL(OUString("D:20200612201322+02'00"), sDateTimeString);
     }
 
     {
@@ -231,6 +240,22 @@ void PDFiumLibraryTest::testAnnotationsMadeInAcrobat()
     }
 }
 
+void PDFiumLibraryTest::testTools()
+{
+    OUString sConverted = vcl::pdf::convertPdfDateToISO8601("D:20200612201322+02'00");
+
+    css::util::DateTime aDateTime;
+    CPPUNIT_ASSERT(utl::ISO8601parseDateTime(sConverted, aDateTime));
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2020), aDateTime.Year);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), aDateTime.Month);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(12), aDateTime.Day);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), aDateTime.Hours);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(13), aDateTime.Minutes);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(22), aDateTime.Seconds);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), aDateTime.NanoSeconds);
+    CPPUNIT_ASSERT_EQUAL(false, bool(aDateTime.IsUTC));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PDFiumLibraryTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index d3eb243bcbd4..5574f4a67778 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -20,6 +20,7 @@
 #include <vcl/graph.hxx>
 #include <bitmapwriteaccess.hxx>
 #include <unotools/ucbstreamhelper.hxx>
+#include <unotools/datetime.hxx>
 
 #include <vcl/filter/PDFiumLibrary.hxx>
 
@@ -294,10 +295,21 @@ size_t ImportPDFUnloaded(const OUString& rURL, std::vector<PDFGraphicResult>& rG
                     convertPointToMm100(rRectangle.getMaxX()),
                     convertPointToMm100(aPageSize.getY() - rRectangle.getMaxY()));
 
+                OUString sDateTimeString
+                    = pAnnotation->getString(vcl::pdf::constDictionaryKeyModificationDate);
+                OUString sISO8601String = vcl::pdf::convertPdfDateToISO8601(sDateTimeString);
+
+                css::util::DateTime aDateTime;
+                if (!sISO8601String.isEmpty())
+                {
+                    utl::ISO8601parseDateTime(sISO8601String, aDateTime);
+                }
+
                 PDFGraphicAnnotation aPDFGraphicAnnotation;
                 aPDFGraphicAnnotation.maRectangle = rRectangleHMM;
                 aPDFGraphicAnnotation.maAuthor = sAuthor;
                 aPDFGraphicAnnotation.maText = sText;
+                aPDFGraphicAnnotation.maDateTime = aDateTime;
                 aPDFGraphicAnnotations.push_back(aPDFGraphicAnnotation);
             }
         }
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index 344fac51aa76..cad2296eeea9 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -18,6 +18,63 @@
 
 namespace vcl::pdf
 {
+OUString convertPdfDateToISO8601(OUString const& rInput)
+{
+    if (rInput.getLength() < 6)
+        return OUString();
+
+    OUString prefix = rInput.copy(0, 2);
+    if (prefix != "D:")
+        return OUString();
+
+    OUString sYear = rInput.copy(2, 4);
+
+    OUString sMonth("01");
+    if (rInput.getLength() >= 8)
+        sMonth = rInput.copy(6, 2);
+
+    OUString sDay("01");
+    if (rInput.getLength() >= 10)
+        sDay = rInput.copy(8, 2);
+
+    OUString sHours("00");
+    if (rInput.getLength() >= 12)
+        sHours = rInput.copy(10, 2);
+
+    OUString sMinutes("00");
+    if (rInput.getLength() >= 14)
+        sMinutes = rInput.copy(12, 2);
+
+    OUString sSeconds("00");
+    if (rInput.getLength() >= 16)
+        sSeconds = rInput.copy(14, 2);
+
+    OUString sTimeZoneMark("Z");
+    if (rInput.getLength() >= 17)
+        sTimeZoneMark = rInput.copy(16, 1);
+
+    OUString sTimeZoneHours("00");
+    OUString sTimeZoneMinutes("00");
+    if ((sTimeZoneMark == "+" || sTimeZoneMark == "-") && rInput.getLength() >= 22)
+    {
+        OUString sTimeZoneSeparator = rInput.copy(19, 1);
+        if (sTimeZoneSeparator == "'")
+        {
+            sTimeZoneHours = rInput.copy(17, 2);
+            sTimeZoneMinutes = rInput.copy(20, 2);
+        }
+    }
+
+    OUString sTimeZoneString;
+    if (sTimeZoneMark == "+" || sTimeZoneString == "-")
+        sTimeZoneString = sTimeZoneMark + sTimeZoneHours + ":" + sTimeZoneMinutes;
+    else if (sTimeZoneMark == "Z")
+        sTimeZoneString = sTimeZoneMark;
+
+    return sYear + "-" + sMonth + "-" + sDay + "T" + sHours + ":" + sMinutes + ":" + sSeconds
+           + sTimeZoneString;
+}
+
 PDFium::PDFium()
 {
     FPDF_LIBRARY_CONFIG aConfig;


More information about the Libreoffice-commits mailing list