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

Miklos Vajna vmiklos at collabora.co.uk
Fri Mar 24 12:47:58 UTC 2017


 include/vcl/filter/pdfdocument.hxx     |    4 +
 vcl/source/filter/ipdf/pdfdocument.cxx |    5 +
 vcl/source/gdi/pdfwriter_impl.cxx      |   92 ++++++++++++++++++++++++++++++---
 vcl/source/gdi/pdfwriter_impl.hxx      |    8 ++
 4 files changed, 100 insertions(+), 9 deletions(-)

New commits:
commit 1f2bccf2d28d4257aa0e325658d35182367b59d9
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Mar 24 09:46:21 2017 +0100

    tdf#106693 vcl PDF export, norefxobj: copy XObject references
    
    With this the images inside the PDF image show up correctly.
    
    Change-Id: I430502fb6ae9de8111dda7e67db33642ff263317
    Reviewed-on: https://gerrit.libreoffice.org/35621
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index 8d362e7e339c..135d30d8d8bb 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -44,13 +44,14 @@ public:
 /// Indirect object: something with a unique ID.
 class VCL_DLLPUBLIC PDFObjectElement : public PDFElement
 {
+    /// The document owning this element.
     PDFDocument& m_rDoc;
     double m_fObjectValue;
     double m_fGenerationValue;
     std::map<OString, PDFElement*> m_aDictionary;
     /// Position after the '<<' token.
     sal_uInt64 m_nDictionaryOffset;
-    /// Length of the dictionary buffer till (before) the '<<' token.
+    /// Length of the dictionary buffer till (before) the '>>' token.
     sal_uInt64 m_nDictionaryLength;
     PDFDictionaryElement* m_pDictionaryElement;
     /// The contained direct array, if any.
@@ -86,6 +87,7 @@ public:
     std::vector< std::unique_ptr<PDFElement> >& GetStoredElements();
     SvMemoryStream* GetStreamBuffer() const;
     void SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamBuffer);
+    PDFDocument& GetDocument();
 };
 
 /// Array object: a list.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 72996ecd652c..900c5f281863 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -2586,6 +2586,11 @@ void PDFObjectElement::SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamB
     m_pStreamBuffer = std::move(pStreamBuffer);
 }
 
+PDFDocument& PDFObjectElement::GetDocument()
+{
+    return m_rDoc;
+}
+
 PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue)
     : m_rDoc(rDoc),
       m_fObjectValue(fObjectValue),
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index f9e26a785c5b..3b7ee87f5e6c 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10852,6 +10852,64 @@ void PDFWriterImpl::writeJPG( JPGEmit& rObject )
     writeReferenceXObject(rObject.m_aReferenceXObject);
 }
 
+std::map<OString, sal_Int32> PDFWriterImpl::copyExternalResources(filter::PDFObjectElement& rPage, const OString& rKind)
+{
+    // A name - object ID map, IDs as they appear in our output, not the
+    // original ones.
+    std::map<OString, sal_Int32> aRet;
+
+    // Get the rKind subset of the resource dictionary.
+    auto pResources = dynamic_cast<filter::PDFDictionaryElement*>(rPage.Lookup("Resources"));
+    if (!pResources)
+        return aRet;
+
+    auto pDictionary = dynamic_cast<filter::PDFDictionaryElement*>(pResources->LookupElement(rKind));
+    if (!pDictionary)
+        return aRet;
+
+    const std::map<OString, filter::PDFElement*>& rItems = pDictionary->GetItems();
+    for (const auto& rItem : rItems)
+    {
+        // For each item copy it over to our output then insert it into aRet.
+        auto pReference = dynamic_cast<filter::PDFReferenceElement*>(rItem.second);
+        if (!pReference)
+            continue;
+
+        filter::PDFObjectElement* pValue = pReference->LookupObject();
+        if (!pValue)
+            continue;
+
+        sal_Int32 nObject = createObject();
+        if (!updateObject(nObject))
+            continue;
+
+        SvMemoryStream& rDocBuffer = rPage.GetDocument().GetEditBuffer();
+
+        // When copying over an object copy its dictionary and its stream.
+        OStringBuffer aLine;
+        aLine.append(nObject);
+        aLine.append(" 0 obj\n<<");
+        aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + pValue->GetDictionaryOffset(), pValue->GetDictionaryLength());
+        aLine.append(">>\nstream\n");
+
+        filter::PDFStreamElement* pStream = pValue->GetStream();
+        if (!pStream)
+            continue;
+
+        SvMemoryStream& rStream = pStream->GetMemory();
+        aLine.append(static_cast<const sal_Char*>(rStream.GetData()), rStream.GetSize());
+        aLine.append("\nendstream\nendobj\n\n");
+
+        // We have the whole object, now write it to the output.
+        if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+            continue;
+
+        aRet[rItem.first] = nObject;
+    }
+
+    return aRet;
+}
+
 void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
 {
     if (rEmit.m_nFormObject <= 0)
@@ -10872,12 +10930,6 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
     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;
@@ -10890,24 +10942,48 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
             return;
         }
         std::vector<filter::PDFObjectElement*> aPages = aPDFDocument.GetPages();
-        if (aPages.empty() || !aPages[0])
+        if (aPages.empty())
         {
             SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: no pages");
             return;
         }
 
-        filter::PDFObjectElement* pPageContents = aPages[0]->LookupObject("Contents");
+        filter::PDFObjectElement* pPage = aPages[0];
+        if (!pPage)
+        {
+            SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: no page");
+            return;
+        }
+
+        std::map<OString, sal_Int32> aXObjects = copyExternalResources(*pPage, "XObject");
+        OString sXObjects = "/XObject<<";
+        for (const auto& rPair : aXObjects)
+        {
+            sXObjects += "/" + rPair.first + " " + OString::number(rPair.second) + " 0 R";
+        }
+        sXObjects += ">>";
+
+        filter::PDFObjectElement* pPageContents = pPage->LookupObject("Contents");
         if (!pPageContents)
         {
             SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: page has no contents");
             return;
         }
 
+        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;
+
         OStringBuffer aLine;
         aLine.append(nWrappedFormObject);
         aLine.append(" 0 obj\n");
         aLine.append("<< /Type /XObject");
         aLine.append(" /Subtype /Form");
+        aLine.append(" /Resources <<");
+        aLine.append(sXObjects);
+        aLine.append(">>");
         aLine.append(" /BBox [ 0 0 ");
         aLine.append(aSize.Width());
         aLine.append(" ");
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
index b35c44050f46..3185d60d628a 100644
--- a/vcl/source/gdi/pdfwriter_impl.hxx
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -90,6 +90,11 @@ class PDFStreamIf;
 class Matrix3;
 class PdfBuiltinFontFace;
 
+namespace filter
+{
+class PDFObjectElement;
+}
+
 class PDFWriterImpl
 {
     friend class PDFStreamIf;
@@ -847,6 +852,9 @@ i12626
     void writeJPG( JPGEmit& rEmit );
     /// Writes the form XObject proxy for the image.
     void writeReferenceXObject(ReferenceXObjectEmit& rEmit);
+    /// Copies resources of a given kind from an external page to the output,
+    /// returning what has beeen copied (name) and where (object ID).
+    std::map<OString, sal_Int32> copyExternalResources(filter::PDFObjectElement& rPage, const OString& rKind);
 
     /* tries to find the bitmap by its id and returns its emit data if exists,
        else creates a new emit data block */


More information about the Libreoffice-commits mailing list