summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-04-10 16:19:52 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-04-10 20:14:51 +0200
commita876f982a56c0bcc04667d55a53b05c90a8c3354 (patch)
treeae2dec050c360781d0ef1811075d9fd20a70652a /vcl
parent95de10e0b02cece37ffe2428112773b6e096a221 (diff)
Related: tdf#107013 PDF export of PDF images: improve content streams
It can happen that the list of content streams have an equal number of "q" and "Q" operators when all of them is parsed. This means it's not correct to represent these separate streams with separate form objects, as those require equal number of "q" and "Q" operators by the end of each object. Instead concatenate the streams and always write a single form object, not only in case there is a single content stream. Change-Id: I62e4ee4c86403376155d10447404416686c84ef9 Reviewed-on: https://gerrit.libreoffice.org/36385 Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk> Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx135
1 files changed, 71 insertions, 64 deletions
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index d5c1f6e8e7ee..218ee883bdc5 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -11107,7 +11107,7 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
double fScaleX = 1.0 / aSize.Width();
double fScaleY = 1.0 / aSize.Height();
- std::vector<sal_Int32> aWrappedFormObjects;
+ sal_Int32 nWrappedFormObject = 0;
if (!m_aContext.UseReferenceXObject)
{
// Parse the PDF data, we need that to write the PDF dictionary of our
@@ -11154,45 +11154,55 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
}
}
+ if (aContentStreams.empty())
+ {
+ SAL_WARN("vcl.pdfwriter", "PDFWriterImpl::writeReferenceXObject: no content stream");
+ return;
+ }
+
// Maps from source object id (PDF image) to target object id (export result).
std::map<sal_Int32, sal_Int32> aCopiedResources;
- for (auto pContent : aContentStreams)
- {
- aWrappedFormObjects.push_back(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.
- OStringBuffer aLine;
- aLine.append(aWrappedFormObjects.back());
- aLine.append(" 0 obj\n");
- aLine.append("<< /Type /XObject");
- aLine.append(" /Subtype /Form");
- aLine.append(" /Resources <<");
- static const std::initializer_list<OString> aKeys =
- {
- "ColorSpace",
- "ExtGState",
- "Font",
- "XObject"
- };
- for (const auto& rKey : aKeys)
- aLine.append(copyExternalResources(*pPage, rKey, aCopiedResources));
- aLine.append(">>");
- aLine.append(" /BBox [ 0 0 ");
- aLine.append(aSize.Width());
- aLine.append(" ");
- aLine.append(aSize.Height());
- aLine.append(" ]");
-
- auto pFilter = dynamic_cast<filter::PDFNameElement*>(pContent->Lookup("Filter"));
- if (pFilter)
- {
- aLine.append(" /Filter /");
- aLine.append(pFilter->GetValue());
- }
+ 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.
- aLine.append(" /Length ");
+ OStringBuffer aLine;
+ aLine.append(nWrappedFormObject);
+ aLine.append(" 0 obj\n");
+ aLine.append("<< /Type /XObject");
+ aLine.append(" /Subtype /Form");
+ aLine.append(" /Resources <<");
+ static const std::initializer_list<OString> aKeys =
+ {
+ "ColorSpace",
+ "ExtGState",
+ "Font",
+ "XObject"
+ };
+ for (const auto& rKey : aKeys)
+ aLine.append(copyExternalResources(*pPage, rKey, aCopiedResources));
+ aLine.append(">>");
+ aLine.append(" /BBox [ 0 0 ");
+ aLine.append(aSize.Width());
+ aLine.append(" ");
+ aLine.append(aSize.Height());
+ aLine.append(" ]");
+
+ // For now assume that all the content streams have the same filter.
+ auto pFilter = dynamic_cast<filter::PDFNameElement*>(aContentStreams[0]->Lookup("Filter"));
+ if (pFilter)
+ {
+ aLine.append(" /Filter /");
+ aLine.append(pFilter->GetValue());
+ }
+
+ aLine.append(" /Length ");
+ sal_Int32 nLength = 0;
+ OStringBuffer aStream;
+ for (auto pContent : aContentStreams)
+ {
filter::PDFStreamElement* pPageStream = pContent->GetStream();
if (!pPageStream)
{
@@ -11202,17 +11212,20 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
SvMemoryStream& rPageStream = pPageStream->GetMemory();
- aLine.append(static_cast<sal_Int32>(rPageStream.GetSize()));
-
- aLine.append(">>\nstream\n");
- // Copy the original page stream to the form XObject stream.
- aLine.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
- aLine.append("\nendstream\nendobj\n\n");
- if (!updateObject(aWrappedFormObjects.back()))
- continue;
- if (!writeBuffer(aLine.getStr(), aLine.getLength()))
- continue;
+ nLength += rPageStream.GetSize();
+ aStream.append(static_cast<const sal_Char*>(rPageStream.GetData()), rPageStream.GetSize());
}
+
+ aLine.append(nLength);
+
+ aLine.append(">>\nstream\n");
+ // Copy the original page streams to the form XObject stream.
+ aLine.append(aStream.makeStringAndClear());
+ aLine.append("\nendstream\nendobj\n\n");
+ if (!updateObject(nWrappedFormObject))
+ return;
+ if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+ return;
}
OStringBuffer aLine;
@@ -11225,18 +11238,14 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
aLine.append("<< /Type /XObject");
aLine.append(" /Subtype /Form");
aLine.append(" /Resources << /XObject<<");
- for (const auto nWrappedFormObject : aWrappedFormObjects)
- {
- sal_Int32 nObject = m_aContext.UseReferenceXObject ? rEmit.m_nBitmapObject : nWrappedFormObject;
- aLine.append(" /Im");
- aLine.append(nObject);
- aLine.append(" ");
- aLine.append(nObject);
- aLine.append(" 0 R");
- if (m_aContext.UseReferenceXObject)
- break;
- }
+ sal_Int32 nObject = m_aContext.UseReferenceXObject ? rEmit.m_nBitmapObject : nWrappedFormObject;
+ aLine.append(" /Im");
+ aLine.append(nObject);
+ aLine.append(" ");
+ aLine.append(nObject);
+ aLine.append(" 0 R");
+
aLine.append(">> >>");
aLine.append(" /Matrix [ ");
appendDouble(fScaleX, aLine);
@@ -11277,14 +11286,12 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
{
// Reset line width to the default.
aStream.append(" 1 w\n");
- for (const auto nWrappedFormObject : aWrappedFormObjects)
- {
- // No reference XObject, draw the form XObject containing the original
- // page stream.
- aStream.append("/Im");
- aStream.append(nWrappedFormObject);
- aStream.append(" Do\n");
- }
+
+ // No reference XObject, draw the form XObject containing the original
+ // page streams.
+ aStream.append("/Im");
+ aStream.append(nWrappedFormObject);
+ aStream.append(" Do\n");
}
aStream.append("Q");
aLine.append(aStream.getLength());