diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-24 09:46:21 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-24 12:47:33 +0000 |
commit | 1f2bccf2d28d4257aa0e325658d35182367b59d9 (patch) | |
tree | 5b4ef3eed66491c4ceabbc170fbb428d214ac672 /vcl/source/gdi | |
parent | ce3e3185f9ef64b44e26593a8300ae912b6fe68e (diff) |
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@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 92 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 8 |
2 files changed, 92 insertions, 8 deletions
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 */ |