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 <[email protected]> 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 <[email protected]> Tested-by: Jenkins <[email protected]> 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 */ _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
