diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-24 15:16:32 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-24 20:32:51 +0000 |
commit | f135a8bdeba15cf72dd31c7d613d335bbfc7017b (patch) | |
tree | 79c4573ef171e449299e20bc038f936254a0c1e2 /vcl/source/gdi | |
parent | 221247679bcbc2507d6f904f519040fc4467d4a1 (diff) |
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@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 100 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 3 |
2 files changed, 78 insertions, 25 deletions
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 */ |