[Libreoffice-commits] core.git: include/vcl vcl/source
Miklos Vajna
vmiklos at collabora.co.uk
Fri Mar 24 12:47:58 UTC 2017
include/vcl/filter/pdfdocument.hxx | 4 +
vcl/source/filter/ipdf/pdfdocument.cxx | 5 +
vcl/source/gdi/pdfwriter_impl.cxx | 92 ++++++++++++++++++++++++++++++---
vcl/source/gdi/pdfwriter_impl.hxx | 8 ++
4 files changed, 100 insertions(+), 9 deletions(-)
New commits:
commit 1f2bccf2d28d4257aa0e325658d35182367b59d9
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Fri Mar 24 09:46:21 2017 +0100
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 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 8d362e7e339c..135d30d8d8bb 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -44,13 +44,14 @@ public:
/// Indirect object: something with a unique ID.
class VCL_DLLPUBLIC PDFObjectElement : public PDFElement
{
+ /// The document owning this element.
PDFDocument& m_rDoc;
double m_fObjectValue;
double m_fGenerationValue;
std::map<OString, PDFElement*> m_aDictionary;
/// Position after the '<<' token.
sal_uInt64 m_nDictionaryOffset;
- /// Length of the dictionary buffer till (before) the '<<' token.
+ /// Length of the dictionary buffer till (before) the '>>' token.
sal_uInt64 m_nDictionaryLength;
PDFDictionaryElement* m_pDictionaryElement;
/// The contained direct array, if any.
@@ -86,6 +87,7 @@ public:
std::vector< std::unique_ptr<PDFElement> >& GetStoredElements();
SvMemoryStream* GetStreamBuffer() const;
void SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamBuffer);
+ PDFDocument& GetDocument();
};
/// Array object: a list.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 72996ecd652c..900c5f281863 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -2586,6 +2586,11 @@ void PDFObjectElement::SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamB
m_pStreamBuffer = std::move(pStreamBuffer);
}
+PDFDocument& PDFObjectElement::GetDocument()
+{
+ return m_rDoc;
+}
+
PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue)
: m_rDoc(rDoc),
m_fObjectValue(fObjectValue),
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 */
More information about the Libreoffice-commits
mailing list