summaryrefslogtreecommitdiff
path: root/vcl/source/gdi
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-03-24 09:46:21 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-03-24 12:47:33 +0000
commit1f2bccf2d28d4257aa0e325658d35182367b59d9 (patch)
tree5b4ef3eed66491c4ceabbc170fbb428d214ac672 /vcl/source/gdi
parentce3e3185f9ef64b44e26593a8300ae912b6fe68e (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.cxx92
-rw-r--r--vcl/source/gdi/pdfwriter_impl.hxx8
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 */