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

Miklos Vajna vmiklos at collabora.co.uk
Fri Mar 24 20:33:16 UTC 2017


 include/vcl/filter/pdfdocument.hxx     |    5 +
 vcl/source/filter/ipdf/pdfdocument.cxx |   16 ++++-
 vcl/source/gdi/pdfwriter_impl.cxx      |  100 ++++++++++++++++++++++++---------
 vcl/source/gdi/pdfwriter_impl.hxx      |    3 
 4 files changed, 98 insertions(+), 26 deletions(-)

New commits:
commit f135a8bdeba15cf72dd31c7d613d335bbfc7017b
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Mar 24 15:16:32 2017 +0100

    tdf#106693 vcl PDF export, norefxobj: update XObject refs
    
    Start copying referenced objects recursively, and also take care of
    updating references to the object IDs as they appear in our output.
    
    With this, the 4th image referenced from the PDF image has a correctly
    updated reference in its dictionary's ColorSpace key.
    
    Change-Id: I8b49701c1f60bd0ef5a097b24ce59164554c44fa
    Reviewed-on: https://gerrit.libreoffice.org/35653
    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 135d30d8d8bb..fbfb81ed10a2 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -77,6 +77,8 @@ public:
     sal_uInt64 GetDictionaryLength();
     PDFDictionaryElement* GetDictionary() const;
     void SetDictionary(PDFDictionaryElement* pDictionaryElement);
+    /// Get access to the parsed key-value items from the object dictionary.
+    const std::map<OString, PDFElement*>& GetDictionaryItems() const;
     void SetArray(PDFArrayElement* pArrayElement);
     void SetStream(PDFStreamElement* pStreamElement);
     /// Access to the stream of the object, if it has any.
@@ -109,6 +111,8 @@ class VCL_DLLPUBLIC PDFReferenceElement : public PDFElement
     PDFDocument& m_rDoc;
     int m_fObjectValue;
     int m_fGenerationValue;
+    /// Location after the 'R' token.
+    sal_uInt64 m_nOffset = 0;
 
 public:
     PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue);
@@ -119,6 +123,7 @@ public:
     PDFObjectElement* LookupObject();
     int GetObjectValue() const;
     int GetGenerationValue() const;
+    sal_uInt64 GetOffset() const;
 };
 
 /// Stream object: a byte array with a known length.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 900c5f281863..8744729fdd83 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -2224,7 +2224,10 @@ size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement
             {
                 rDictionary[aName] = pReference;
                 if (pThisDictionary)
+                {
                     pThisDictionary->SetKeyOffset(aName, nNameOffset);
+                    pThisDictionary->SetKeyValueLength(aName, pReference->GetOffset() - nNameOffset);
+                }
                 aName.clear();
             }
             else
@@ -2421,6 +2424,11 @@ void PDFObjectElement::SetDictionary(PDFDictionaryElement* pDictionaryElement)
     m_pDictionaryElement = pDictionaryElement;
 }
 
+const std::map<OString, PDFElement*>& PDFObjectElement::GetDictionaryItems() const
+{
+    return m_aDictionary;
+}
+
 void PDFObjectElement::SetArray(PDFArrayElement* pArrayElement)
 {
     m_pArrayElement = pArrayElement;
@@ -2598,12 +2606,18 @@ PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, in
 {
 }
 
-bool PDFReferenceElement::Read(SvStream& /*rStream*/)
+bool PDFReferenceElement::Read(SvStream& rStream)
 {
     SAL_INFO("vcl.filter", "PDFReferenceElement::Read: " << m_fObjectValue << " " << m_fGenerationValue << " R");
+    m_nOffset = rStream.Tell();
     return true;
 }
 
+sal_uInt64 PDFReferenceElement::GetOffset() const
+{
+    return m_nOffset;
+}
+
 double PDFReferenceElement::LookupNumber(SvStream& rStream) const
 {
     size_t nOffset = m_rDoc.GetObjectOffset(m_fObjectValue);
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 3b7ee87f5e6c..061bc825d7a4 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10852,6 +10852,77 @@ void PDFWriterImpl::writeJPG( JPGEmit& rObject )
     writeReferenceXObject(rObject.m_aReferenceXObject);
 }
 
+sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject)
+{
+    sal_Int32 nObject = createObject();
+
+    OStringBuffer aLine;
+    aLine.append(nObject);
+    aLine.append(" 0 obj\n");
+    if (filter::PDFDictionaryElement* pDictionary = rObject.GetDictionary())
+    {
+        aLine.append("<<");
+
+        // Complex case: can't copy the dictionary byte array as is, as it contains a reference.
+        bool bDone = false;
+        const std::map<OString, filter::PDFElement*>& rItems = rObject.GetDictionaryItems();
+        OString aReferenceName("ColorSpace");
+        auto it = rItems.find(aReferenceName);
+        if (it != rItems.end())
+        {
+            auto pReference = dynamic_cast<filter::PDFReferenceElement*>(it->second);
+            if (pReference)
+            {
+                filter::PDFObjectElement* pReferenced = pReference->LookupObject();
+                if (pReferenced)
+                {
+                    // Copy the referenced object.
+                    sal_Int32 nRef = copyExternalResource(rDocBuffer, *pReferenced);
+
+                    sal_uInt64 nDictStart = rObject.GetDictionaryOffset();
+                    sal_uInt64 nReferenceStart = pDictionary->GetKeyOffset(aReferenceName) + aReferenceName.getLength();
+                    sal_uInt64 nReferenceEnd = pDictionary->GetKeyOffset(aReferenceName) + pDictionary->GetKeyValueLength(aReferenceName);
+                    sal_uInt64 nDictEnd = nDictStart + rObject.GetDictionaryLength();
+                    // Dict start -> reference start.
+                    aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nDictStart, nReferenceStart - nDictStart);
+                    // Write the updated reference.
+                    aLine.append(" ");
+                    aLine.append(nRef);
+                    aLine.append(" 0 R");
+                    // Reference end -> dict end.
+                    aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nReferenceEnd, nDictEnd - nReferenceEnd);
+
+                    bDone = true;
+                }
+            }
+        }
+
+        // Can copy it as-is.
+        if (!bDone)
+            aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetDictionaryOffset(), rObject.GetDictionaryLength());
+
+        aLine.append(">>\n");
+    }
+
+    if (filter::PDFStreamElement* pStream = rObject.GetStream())
+    {
+        aLine.append("stream\n");
+        SvMemoryStream& rStream = pStream->GetMemory();
+        aLine.append(static_cast<const sal_Char*>(rStream.GetData()), rStream.GetSize());
+        aLine.append("\nendstream\n");
+    }
+
+    aLine.append("endobj\n\n");
+
+    // We have the whole object, now write it to the output.
+    if (!updateObject(nObject))
+        return -1;
+    if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+        return -1;
+
+    return nObject;
+}
+
 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
@@ -10867,6 +10938,8 @@ std::map<OString, sal_Int32> PDFWriterImpl::copyExternalResources(filter::PDFObj
     if (!pDictionary)
         return aRet;
 
+    SvMemoryStream& rDocBuffer = rPage.GetDocument().GetEditBuffer();
+
     const std::map<OString, filter::PDFElement*>& rItems = pDictionary->GetItems();
     for (const auto& rItem : rItems)
     {
@@ -10879,31 +10952,8 @@ std::map<OString, sal_Int32> PDFWriterImpl::copyExternalResources(filter::PDFObj
         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;
-
+        // Then copying over an object copy its dictionary and its stream.
+        sal_Int32 nObject = copyExternalResource(rDocBuffer, *pValue);
         aRet[rItem.first] = nObject;
     }
 
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
index 3185d60d628a..47956ce72022 100644
--- a/vcl/source/gdi/pdfwriter_impl.hxx
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -855,6 +855,9 @@ i12626
     /// 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);
+    /// Copies a single resource from an external document, returns the new
+    /// object ID in our document.
+    sal_Int32 copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject);
 
     /* 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