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

Miklos Vajna vmiklos at collabora.co.uk
Thu Mar 23 15:59:40 UTC 2017


 vcl/source/gdi/pdfwriter_impl.cxx |  126 +++++++++++++++++++++++++-------------
 1 file changed, 84 insertions(+), 42 deletions(-)

New commits:
commit d0c24cbb027130f3781bfc3475dd225190afd560
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Mar 23 14:26:42 2017 +0100

    tdf#106693 vcl PDF export, norefxobj: handle compressed page stream
    
    Since we want to avoid re-compressing the page stream create two form
    XObjects: one that resets the graphic state to the default (e.g. line
    width) and an other one that contains the original page stream as-is.
    
    With this PDF images where the page stream is compressed are handled
    correctly.
    
    Change-Id: Ib44dae2e167e4d5604a0a3a3cf91e09795137343

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 9e40b3fe5539..597b6996d6fe 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10863,10 +10863,6 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
     if (rEmit.m_nFormObject <= 0)
         return;
 
-    OStringBuffer aLine;
-    if (!updateObject(rEmit.m_nFormObject))
-        return;
-
     // Count /Matrix and /BBox.
     // vcl::ImportPDF() works with 96 DPI so use the same values here, too.
     sal_Int32 nOldDPIX = getReferenceDevice()->GetDPIX();
@@ -10879,15 +10875,92 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
     double fScaleX = 1.0 / aSize.Width();
     double fScaleY = 1.0 / aSize.Height();
 
+    sal_Int32 nWrappedFormObject = 0;
+    if (!m_aContext.UseReferenceXObject)
+    {
+        nWrappedFormObject = createObject();
+        // Write the form XObject wrapped below. This is a separate object from
+        // the wrapper, this way there is no need to alter the stream contents.
+        if (!updateObject(nWrappedFormObject))
+            return;
+
+        // Parse the PDF data, we need that to write the PDF dictionary of our
+        // object.
+        SvMemoryStream aPDFStream;
+        aPDFStream.WriteBytes(rEmit.m_aPDFData.getArray(), rEmit.m_aPDFData.getLength());
+        aPDFStream.Seek(0);
+        filter::PDFDocument aPDFDocument;
+        if (!aPDFDocument.Read(aPDFStream))
+        {
+            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: reading the PDF document failed");
+            return;
+        }
+        std::vector<filter::PDFObjectElement*> aPages = aPDFDocument.GetPages();
+        if (aPages.empty() || !aPages[0])
+        {
+            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: no pages");
+            return;
+        }
+
+        filter::PDFObjectElement* pPageContents = aPages[0]->LookupObject("Contents");
+        if (!pPageContents)
+        {
+            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: page has no contents");
+            return;
+        }
+
+        OStringBuffer aLine;
+        aLine.append(nWrappedFormObject);
+        aLine.append(" 0 obj\n");
+        aLine.append("<< /Type /XObject");
+        aLine.append(" /Subtype /Form");
+        aLine.append(" /BBox [ 0 0 ");
+        aLine.append(aSize.Width());
+        aLine.append(" ");
+        aLine.append(aSize.Height());
+        aLine.append(" ]");
+
+        auto pFilter = dynamic_cast<filter::PDFNameElement*>(pPageContents->Lookup("Filter"));
+        if (pFilter)
+        {
+            aLine.append(" /Filter /");
+            aLine.append(pFilter->GetValue());
+        }
+
+        aLine.append(" /Length ");
+
+        filter::PDFStreamElement* pPageStream = pPageContents->GetStream();
+        if (!pPageStream)
+        {
+            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: contents has no stream");
+            return;
+        }
+
+        SvMemoryStream& rPageStream = pPageStream->GetMemory();
+
+        aLine.append(static_cast<sal_Int32>(rPageStream.GetSize()));
+
+        aLine.append(">>\nstream\n");
+        // Copy the original page stream to the form XObject stream.
+        aLine.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
+        aLine.append("\nendstream\nendobj\n\n");
+        CHECK_RETURN2(writeBuffer(aLine.getStr(), aLine.getLength()));
+    }
+
+    OStringBuffer aLine;
+    if (!updateObject(rEmit.m_nFormObject))
+        return;
+
     // Now have all the info to write the form XObject.
     aLine.append(rEmit.m_nFormObject);
     aLine.append(" 0 obj\n");
     aLine.append("<< /Type /XObject");
     aLine.append(" /Subtype /Form");
     aLine.append(" /Resources << /XObject<</Im");
-    aLine.append(rEmit.m_nBitmapObject);
+    sal_Int32 nObject = m_aContext.UseReferenceXObject ? rEmit.m_nBitmapObject : nWrappedFormObject;
+    aLine.append(nObject);
     aLine.append(" ");
-    aLine.append(rEmit.m_nBitmapObject);
+    aLine.append(nObject);
     aLine.append(" 0 R>> >>");
     aLine.append(" /Matrix [ ");
     appendDouble(fScaleX, aLine);
@@ -10926,44 +10999,13 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
     }
     else
     {
-        // No reference XObject, include the original page stream.
         // Reset line width to the default.
         aStream.append(" 1 w\n");
-        SvMemoryStream aPDFStream;
-        aPDFStream.WriteBytes(rEmit.m_aPDFData.getArray(), rEmit.m_aPDFData.getLength());
-        aPDFStream.Seek(0);
-        filter::PDFDocument aPDFDocument;
-        if (!aPDFDocument.Read(aPDFStream))
-        {
-            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: reading the PDF document failed");
-            return;
-        }
-        std::vector<filter::PDFObjectElement*> aPages = aPDFDocument.GetPages();
-        if (aPages.empty() || !aPages[0])
-        {
-            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: no pages");
-            return;
-        }
-
-        filter::PDFObjectElement* pPageContents = aPages[0]->LookupObject("Contents");
-        if (!pPageContents)
-        {
-            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: page has no contents");
-            return;
-        }
-
-        filter::PDFStreamElement* pPageStream = pPageContents->GetStream();
-        if (!pPageStream)
-        {
-            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: contents has no stream");
-            return;
-        }
-
-        SvMemoryStream& rPageStream = pPageStream->GetMemory();
-
-        // Copy the original page stream to the end of the form XObject stream.
-        aStream.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
-        aStream.append("\n");
+        // No reference XObject, draw the form XObject containing the original
+        // page stream.
+        aStream.append("/Im");
+        aStream.append(nWrappedFormObject);
+        aStream.append(" Do\n");
     }
     aStream.append("Q");
     aLine.append(aStream.getLength());


More information about the Libreoffice-commits mailing list