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

Miklos Vajna vmiklos at collabora.co.uk
Tue Apr 11 11:48:52 UTC 2017


 vcl/qa/cppunit/pdfexport/data/tdf107089.odt |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx      |   38 ++++++++++++++++++++++++++++
 vcl/source/gdi/pdfwriter_impl.cxx           |   38 +++++++++++++++++++---------
 3 files changed, 65 insertions(+), 11 deletions(-)

New commits:
commit 9e8598c42a1a6f2fbd88711aa9bea5961eaf7b4a
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Apr 11 12:42:23 2017 +0200

    tdf#107089 PDF export of PDF images: handle mixed filters of page streams
    
    It's allowed to compress different page streams differently, and we must
    have a single object stream for our form XObject, so just incompress all
    of them to be consistent.
    
    Change-Id: I7a20dc2084a902a37dcefa3420d59a576f120bcd
    Reviewed-on: https://gerrit.libreoffice.org/36409
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107089.odt b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt
new file mode 100644
index 000000000000..5aaaab944a98
Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index aacf36b2796b..1b9eaf153d2c 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -54,6 +54,7 @@ public:
     void testTdf106972Pdf17();
     void testTdf107013();
     void testTdf107018();
+    void testTdf107089();
 #endif
 
     CPPUNIT_TEST_SUITE(PdfExportTest);
@@ -67,6 +68,7 @@ public:
     CPPUNIT_TEST(testTdf106972Pdf17);
     CPPUNIT_TEST(testTdf107013);
     CPPUNIT_TEST(testTdf107018);
+    CPPUNIT_TEST(testTdf107089);
 #endif
     CPPUNIT_TEST_SUITE_END();
 };
@@ -452,6 +454,42 @@ void PdfExportTest::testTdf107018()
     // copying the page stream of a PDF image.
     CPPUNIT_ASSERT_EQUAL(OString("Pages"), pName->GetValue());
 }
+
+void PdfExportTest::testTdf107089()
+{
+    vcl::filter::PDFDocument aDocument;
+    load("tdf107089.odt", aDocument);
+
+    // Get access to the only image on the only page.
+    std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size());
+    vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
+    CPPUNIT_ASSERT(pResources);
+    auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
+    CPPUNIT_ASSERT(pXObjects);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size());
+    vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
+    CPPUNIT_ASSERT(pXObject);
+
+    // Get access to the form object inside the image.
+    auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"));
+    CPPUNIT_ASSERT(pXObjectResources);
+    auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
+    CPPUNIT_ASSERT(pXObjectForms);
+    vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
+    CPPUNIT_ASSERT(pForm);
+
+    // Make sure 'Hello' is part of the form object's stream.
+    vcl::filter::PDFStreamElement* pStream = pForm->GetStream();
+    CPPUNIT_ASSERT(pStream);
+    SvMemoryStream& rObjectStream = pStream->GetMemory();
+    OString aHello("Hello");
+    auto pStart = static_cast<const char*>(rObjectStream.GetData());
+    const char* pEnd = pStart + rObjectStream.GetSize();
+    auto it = std::search(pStart, pEnd, aHello.getStr(), aHello.getStr() + aHello.getLength());
+    // This failed, 'Hello' was part only a mixed compressed/uncompressed stream, i.e. garbage.
+    CPPUNIT_ASSERT(it != pEnd);
+}
 #endif
 
 CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest);
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 218ee883bdc5..f05c94e78e32 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -11178,7 +11178,8 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
             "ColorSpace",
             "ExtGState",
             "Font",
-            "XObject"
+            "XObject",
+            "Shading"
         };
         for (const auto& rKey : aKeys)
             aLine.append(copyExternalResources(*pPage, rKey, aCopiedResources));
@@ -11189,14 +11190,6 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
         aLine.append(aSize.Height());
         aLine.append(" ]");
 
-        // For now assume that all the content streams have the same filter.
-        auto pFilter = dynamic_cast<filter::PDFNameElement*>(aContentStreams[0]->Lookup("Filter"));
-        if (pFilter)
-        {
-            aLine.append(" /Filter /");
-            aLine.append(pFilter->GetValue());
-        }
-
         aLine.append(" /Length ");
 
         sal_Int32 nLength = 0;
@@ -11212,8 +11205,31 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
 
             SvMemoryStream& rPageStream = pPageStream->GetMemory();
 
-            nLength += rPageStream.GetSize();
-            aStream.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
+            auto pFilter = dynamic_cast<filter::PDFNameElement*>(pContent->Lookup("Filter"));
+            if (pFilter)
+            {
+                if (pFilter->GetValue() != "FlateDecode")
+                    continue;
+
+                SvMemoryStream aMemoryStream;
+                ZCodec aZCodec;
+                rPageStream.Seek(0);
+                aZCodec.BeginCompression();
+                aZCodec.Decompress(rPageStream, aMemoryStream);
+                if (!aZCodec.EndCompression())
+                {
+                    SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: decompression failed");
+                    continue;
+                }
+
+                nLength += aMemoryStream.GetSize();
+                aStream.append(static_cast<const sal_Char*>(aMemoryStream.GetData()), aMemoryStream.GetSize());
+            }
+            else
+            {
+                nLength += rPageStream.GetSize();
+                aStream.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
+            }
         }
 
         aLine.append(nLength);


More information about the Libreoffice-commits mailing list