diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-04-10 16:19:52 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-04-10 20:14:51 +0200 |
commit | a876f982a56c0bcc04667d55a53b05c90a8c3354 (patch) | |
tree | ae2dec050c360781d0ef1811075d9fd20a70652a | |
parent | 95de10e0b02cece37ffe2428112773b6e096a221 (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>
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 135 |
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()); |