diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-06-18 12:12:52 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-06-29 09:09:29 +0200 |
commit | 6e267f362fec03662e36641d275a42119f1798ce (patch) | |
tree | 291d177cbd6fe6bd9572e1ee1f6494e89444b929 /vcl/source | |
parent | a35b5c26691fe938843a48a56e471eb048b9a182 (diff) |
sd signature line: extract copyExternalResources() from the pdf export code
Because I would like to reuse this in the "sign existing pdf" code, in
vcl::filter::PDFDocument::WriteAppearanceObject().
(cherry picked from commit 8277073ce3e33788d93b3df490a8f03d1814863b)
Conflicts:
vcl/source/gdi/pdfwriter_impl.cxx
vcl/source/gdi/pdfwriter_impl.hxx
Change-Id: Ia5e5c1e452bb0d0486bde2a082375b5131eea8c7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97248
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/gdi/pdfobjectcopier.cxx | 273 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 233 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 22 |
3 files changed, 283 insertions, 245 deletions
diff --git a/vcl/source/gdi/pdfobjectcopier.cxx b/vcl/source/gdi/pdfobjectcopier.cxx new file mode 100644 index 000000000000..4ba93b3a746d --- /dev/null +++ b/vcl/source/gdi/pdfobjectcopier.cxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <pdf/objectcopier.hxx> + +#include <rtl/strbuf.hxx> +#include <sal/log.hxx> +#include <sal/types.h> +#include <tools/stream.hxx> +#include <vcl/filter/pdfdocument.hxx> + +#include <pdf/objectcontainer.hxx> + +namespace vcl +{ +PDFObjectCopier::PDFObjectCopier(PDFObjectContainer& rContainer) + : m_rContainer(rContainer) +{ +} + +sal_Int32 PDFObjectCopier::copyExternalResource(SvMemoryStream& rDocBuffer, + filter::PDFObjectElement& rObject, + std::map<sal_Int32, sal_Int32>& rCopiedResources) +{ + auto it = rCopiedResources.find(rObject.GetObjectValue()); + if (it != rCopiedResources.end()) + // This resource was already copied once, nothing to do. + return it->second; + + sal_Int32 nObject = m_rContainer.createObject(); + // Remember what is the ID of this object in our output. + rCopiedResources[rObject.GetObjectValue()] = nObject; + SAL_INFO("vcl.pdfwriter", "PDFWriterImpl::copyExternalResource: " << rObject.GetObjectValue() + << " -> " << nObject); + + OStringBuffer aLine; + aLine.append(nObject); + aLine.append(" 0 obj\n"); + if (rObject.GetDictionary()) + { + aLine.append("<<"); + + // Complex case: can't copy the dictionary byte array as is, as it may contain references. + bool bDone = false; + sal_uInt64 nCopyStart = 0; + for (auto pReference : rObject.GetDictionaryReferences()) + { + if (pReference) + { + filter::PDFObjectElement* pReferenced = pReference->LookupObject(); + if (pReferenced) + { + // Copy the referenced object. + sal_Int32 nRef + = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); + + sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); + sal_uInt64 nReferenceEnd = pReference->GetOffset(); + sal_uInt64 nOffset = 0; + if (nCopyStart == 0) + // Dict start -> reference start. + nOffset = rObject.GetDictionaryOffset(); + else + // Previous reference end -> reference start. + nOffset = nCopyStart; + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + nOffset, + nReferenceStart - nOffset); + // Write the updated reference. + aLine.append(" "); + aLine.append(nRef); + aLine.append(" 0 R"); + // Start copying here next time. + nCopyStart = nReferenceEnd; + + bDone = true; + } + } + } + + if (bDone) + { + // Copy the last part here, in the complex case. + sal_uInt64 nDictEnd = rObject.GetDictionaryOffset() + rObject.GetDictionaryLength(); + const sal_Int32 nLen = nDictEnd - nCopyStart; + if (nLen < 0) + SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); + else + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + nCopyStart, nLen); + } + else + // Can copy it as-is. + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + + rObject.GetDictionaryOffset(), + rObject.GetDictionaryLength()); + + aLine.append(">>\n"); + } + + if (filter::PDFStreamElement* pStream = rObject.GetStream()) + { + aLine.append("stream\n"); + SvMemoryStream& rStream = pStream->GetMemory(); + aLine.append(static_cast<const char*>(rStream.GetData()), rStream.GetSize()); + aLine.append("\nendstream\n"); + } + + if (filter::PDFArrayElement* pArray = rObject.GetArray()) + { + aLine.append("["); + + const std::vector<filter::PDFElement*>& rElements = pArray->GetElements(); + bool bDone = false; + // Complex case: can't copy the array byte array as is, as it may contain references. + sal_uInt64 nCopyStart = 0; + for (const auto pElement : rElements) + { + auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pElement); + if (pReference) + { + filter::PDFObjectElement* pReferenced = pReference->LookupObject(); + if (pReferenced) + { + // Copy the referenced object. + sal_Int32 nRef + = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); + + sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); + sal_uInt64 nReferenceEnd = pReference->GetOffset(); + sal_uInt64 nOffset = 0; + if (nCopyStart == 0) + // Array start -> reference start. + nOffset = rObject.GetArrayOffset(); + else + // Previous reference end -> reference start. + nOffset = nCopyStart; + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + nOffset, + nReferenceStart - nOffset); + + // Write the updated reference. + aLine.append(" "); + aLine.append(nRef); + aLine.append(" 0 R"); + // Start copying here next time. + nCopyStart = nReferenceEnd; + + bDone = true; + } + } + } + + if (bDone) + { + // Copy the last part here, in the complex case. + sal_uInt64 nArrEnd = rObject.GetArrayOffset() + rObject.GetArrayLength(); + const sal_Int32 nLen = nArrEnd - nCopyStart; + if (nLen < 0) + SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); + else + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + nCopyStart, nLen); + } + else + // Can copy it as-is. + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + rObject.GetArrayOffset(), + rObject.GetArrayLength()); + + aLine.append("]\n"); + } + + // If the object has a number element outside a dictionary or array, copy that. + if (filter::PDFNumberElement* pNumber = rObject.GetNumberElement()) + { + aLine.append(static_cast<const char*>(rDocBuffer.GetData()) + pNumber->GetLocation(), + pNumber->GetLength()); + aLine.append("\n"); + } + + aLine.append("endobj\n\n"); + + // We have the whole object, now write it to the output. + if (!m_rContainer.updateObject(nObject)) + return -1; + if (!m_rContainer.writeBuffer(aLine.getStr(), aLine.getLength())) + return -1; + + return nObject; +} + +OString PDFObjectCopier::copyExternalResources(filter::PDFObjectElement& rPage, + const OString& rKind, + std::map<sal_Int32, sal_Int32>& rCopiedResources) +{ + // 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. + std::map<OString, filter::PDFElement*> aItems; + if (auto pResources = dynamic_cast<filter::PDFDictionaryElement*>(rPage.Lookup("Resources"))) + { + // Resources is a direct dictionary. + filter::PDFElement* pLookup = pResources->LookupElement(rKind); + if (auto pDictionary = dynamic_cast<filter::PDFDictionaryElement*>(pLookup)) + { + // rKind is an inline dictionary. + aItems = pDictionary->GetItems(); + } + else if (auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pLookup)) + { + // rKind refers to a dictionary. + filter::PDFObjectElement* pReferenced = pReference->LookupObject(); + if (!pReferenced) + { + return OString(); + } + + aItems = pReferenced->GetDictionaryItems(); + } + } + else if (filter::PDFObjectElement* pPageResources = rPage.LookupObject("Resources")) + { + // Resources is an indirect object. + filter::PDFElement* pValue = pPageResources->Lookup(rKind); + if (auto pDictionary = dynamic_cast<filter::PDFDictionaryElement*>(pValue)) + // Kind is a direct dictionary. + aItems = pDictionary->GetItems(); + else if (filter::PDFObjectElement* pObject = pPageResources->LookupObject(rKind)) + // Kind is an indirect object. + aItems = pObject->GetDictionaryItems(); + } + if (aItems.empty()) + return OString(); + + SvMemoryStream& rDocBuffer = rPage.GetDocument().GetEditBuffer(); + + for (const auto& rItem : aItems) + { + // 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; + + // Then copying over an object copy its dictionary and its stream. + sal_Int32 nObject = copyExternalResource(rDocBuffer, *pValue, rCopiedResources); + aRet[rItem.first] = nObject; + } + + // Build the dictionary entry string. + OStringBuffer sRet("/" + rKind + "<<"); + for (const auto& rPair : aRet) + { + sRet.append("/") + .append(rPair.first) + .append(" ") + .append(OString::number(rPair.second)) + .append(" 0 R"); + } + sRet.append(">>"); + + return sRet.makeStringAndClear(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index bba48ab61347..cda14f8885c2 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -74,6 +74,7 @@ #include <textlineinfo.hxx> #include <bitmapwriteaccess.hxx> #include <impglyphitem.hxx> +#include <pdf/objectcopier.hxx> #include "pdfwriter_impl.hxx" @@ -8574,235 +8575,6 @@ void PDFWriterImpl::writeJPG( JPGEmit& rObject ) writeReferenceXObject(rObject.m_aReferenceXObject); } -sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject, std::map<sal_Int32, sal_Int32>& rCopiedResources) -{ - auto it = rCopiedResources.find(rObject.GetObjectValue()); - if (it != rCopiedResources.end()) - // This resource was already copied once, nothing to do. - return it->second; - - sal_Int32 nObject = createObject(); - // Remember what is the ID of this object in our output. - rCopiedResources[rObject.GetObjectValue()] = nObject; - SAL_INFO("vcl.pdfwriter", "PDFWriterImpl::copyExternalResource: " << rObject.GetObjectValue() << " -> " << nObject); - - OStringBuffer aLine; - aLine.append(nObject); - aLine.append(" 0 obj\n"); - if (rObject.GetDictionary()) - { - aLine.append("<<"); - - // Complex case: can't copy the dictionary byte array as is, as it may contain references. - bool bDone = false; - sal_uInt64 nCopyStart = 0; - for (auto pReference : rObject.GetDictionaryReferences()) - { - if (pReference) - { - filter::PDFObjectElement* pReferenced = pReference->LookupObject(); - if (pReferenced) - { - // Copy the referenced object. - sal_Int32 nRef = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); - - sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); - sal_uInt64 nReferenceEnd = pReference->GetOffset(); - sal_uInt64 nOffset = 0; - if (nCopyStart == 0) - // Dict start -> reference start. - nOffset = rObject.GetDictionaryOffset(); - else - // Previous reference end -> reference start. - nOffset = nCopyStart; - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nOffset, nReferenceStart - nOffset); - // Write the updated reference. - aLine.append(" "); - aLine.append(nRef); - aLine.append(" 0 R"); - // Start copying here next time. - nCopyStart = nReferenceEnd; - - bDone = true; - } - } - } - - if (bDone) - { - // Copy the last part here, in the complex case. - sal_uInt64 nDictEnd = rObject.GetDictionaryOffset() + rObject.GetDictionaryLength(); - const sal_Int32 nLen = nDictEnd - nCopyStart; - if (nLen < 0) - SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); - else - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nCopyStart, nLen); - } - else - // Can copy it as-is. - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetDictionaryOffset(), rObject.GetDictionaryLength()); - - aLine.append(">>\n"); - } - - if (filter::PDFStreamElement* pStream = rObject.GetStream()) - { - aLine.append("stream\n"); - SvMemoryStream& rStream = pStream->GetMemory(); - aLine.append(static_cast<const sal_Char*>(rStream.GetData()), rStream.GetSize()); - aLine.append("\nendstream\n"); - } - - if (filter::PDFArrayElement* pArray = rObject.GetArray()) - { - aLine.append("["); - - const std::vector<filter::PDFElement*>& rElements = pArray->GetElements(); - bool bDone = false; - // Complex case: can't copy the array byte array as is, as it may contain references. - sal_uInt64 nCopyStart = 0; - for (const auto pElement : rElements) - { - auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pElement); - if (pReference) - { - filter::PDFObjectElement* pReferenced = pReference->LookupObject(); - if (pReferenced) - { - // Copy the referenced object. - sal_Int32 nRef = copyExternalResource(rDocBuffer, *pReferenced, rCopiedResources); - - sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); - sal_uInt64 nReferenceEnd = pReference->GetOffset(); - sal_uInt64 nOffset = 0; - if (nCopyStart == 0) - // Array start -> reference start. - nOffset = rObject.GetArrayOffset(); - else - // Previous reference end -> reference start. - nOffset = nCopyStart; - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nOffset, nReferenceStart - nOffset); - - // Write the updated reference. - aLine.append(" "); - aLine.append(nRef); - aLine.append(" 0 R"); - // Start copying here next time. - nCopyStart = nReferenceEnd; - - bDone = true; - } - } - } - - if (bDone) - { - // Copy the last part here, in the complex case. - sal_uInt64 nArrEnd = rObject.GetArrayOffset() + rObject.GetArrayLength(); - const sal_Int32 nLen = nArrEnd - nCopyStart; - if (nLen < 0) - SAL_WARN("vcl.pdfwriter", "copyExternalResource() failed"); - else - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nCopyStart, nLen); - } - else - // Can copy it as-is. - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetArrayOffset(), rObject.GetArrayLength()); - - aLine.append("]\n"); - } - - // If the object has a number element outside a dictionary or array, copy that. - if (filter::PDFNumberElement* pNumber = rObject.GetNumberElement()) - { - aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + pNumber->GetLocation(), pNumber->GetLength()); - aLine.append("\n"); - } - - - aLine.append("endobj\n\n"); - - // We have the whole object, now write it to the output. - if (!updateObject(nObject)) - return -1; - if (!writeBuffer(aLine.getStr(), aLine.getLength())) - return -1; - - return nObject; -} - -OString PDFWriterImpl::copyExternalResources(filter::PDFObjectElement& rPage, const OString& rKind, std::map<sal_Int32, sal_Int32>& rCopiedResources) -{ - // 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. - std::map<OString, filter::PDFElement*> aItems; - if (auto pResources = dynamic_cast<filter::PDFDictionaryElement*>(rPage.Lookup("Resources"))) - { - // Resources is a direct dictionary. - filter::PDFElement* pLookup = pResources->LookupElement(rKind); - if (auto pDictionary = dynamic_cast<filter::PDFDictionaryElement*>(pLookup)) - { - // rKind is an inline dictionary. - aItems = pDictionary->GetItems(); - } - else if (auto pReference = dynamic_cast<filter::PDFReferenceElement*>(pLookup)) - { - // rKind refers to a dictionary. - filter::PDFObjectElement* pReferenced = pReference->LookupObject(); - if (!pReferenced) - { - return OString(); - } - - aItems = pReferenced->GetDictionaryItems(); - } - } - else if (filter::PDFObjectElement* pPageResources = rPage.LookupObject("Resources")) - { - // Resources is an indirect object. - filter::PDFElement* pValue = pPageResources->Lookup(rKind); - if (auto pDictionary = dynamic_cast<filter::PDFDictionaryElement*>(pValue)) - // Kind is a direct dictionary. - aItems = pDictionary->GetItems(); - else if (filter::PDFObjectElement* pObject = pPageResources->LookupObject(rKind)) - // Kind is an indirect object. - aItems = pObject->GetDictionaryItems(); - } - if (aItems.empty()) - return OString(); - - SvMemoryStream& rDocBuffer = rPage.GetDocument().GetEditBuffer(); - - for (const auto& rItem : aItems) - { - // 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; - - // Then copying over an object copy its dictionary and its stream. - sal_Int32 nObject = copyExternalResource(rDocBuffer, *pValue, rCopiedResources); - aRet[rItem.first] = nObject; - } - - // Build the dictionary entry string. - OStringBuffer sRet("/" + rKind + "<<"); - for (const auto& rPair : aRet) - { - sRet.append("/").append(rPair.first).append(" ").append(OString::number(rPair.second)).append(" 0 R"); - } - sRet.append(">>"); - - return sRet.makeStringAndClear(); -} - void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit) { if (rEmit.m_nFormObject <= 0) @@ -8924,8 +8696,9 @@ void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit) "XObject", "Shading" }; + PDFObjectCopier aCopier(*this); for (const auto& rKey : aKeys) - aLine.append(copyExternalResources(*pPage, rKey, aCopiedResources)); + aLine.append(aCopier.copyExternalResources(*pPage, rKey, aCopiedResources)); aLine.append(">>"); aLine.append(" /BBox [ 0 0 "); aLine.append(nWidth); diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index f8e89949b1be..d3a7fd8c6c16 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -45,6 +45,7 @@ #include <tools/stream.hxx> #include <outdata.hxx> +#include <pdf/objectcontainer.hxx> #include "pdffontcache.hxx" #include "pdfbuildin_fonts.hxx" @@ -94,7 +95,7 @@ namespace filter class PDFObjectElement; } -class PDFWriterImpl : public VirtualDevice +class PDFWriterImpl : public VirtualDevice, public PDFObjectContainer { friend class PDFStreamIf; @@ -821,12 +822,6 @@ 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 to be included in the new resource dictionary. - OString copyExternalResources(filter::PDFObjectElement& rPage, const OString& rKind, std::map<sal_Int32, sal_Int32>& rCopiedResources); - /// Copies a single resource from an external document, returns the new - /// object ID in our document. - sal_Int32 copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject, std::map<sal_Int32, sal_Int32>& rCopiedResources); /* tries to find the bitmap by its id and returns its emit data if exists, else creates a new emit data block */ @@ -954,15 +949,12 @@ i12626 /* ensure proper escapement and uniqueness of field names */ void createWidgetFieldName( sal_Int32 i_nWidgetsIndex, const PDFWriter::AnyWidget& i_rInWidget ); - /* adds an entry to m_aObjects and returns its index+1, - * sets the offset to ~0 - */ - sal_Int32 createObject(); - /* sets the offset of object n to the current position of output file+1 - */ - bool updateObject( sal_Int32 n ); + /// See vcl::PDFObjectContainer::createObject(). + sal_Int32 createObject() override; + /// See vcl::PDFObjectContainer::updateObject(). + bool updateObject( sal_Int32 n ) override; - bool writeBuffer( const void* pBuffer, sal_uInt64 nBytes ); + bool writeBuffer( const void* pBuffer, sal_uInt64 nBytes ) override; void beginCompression(); void endCompression(); void beginRedirect( SvStream* pStream, const tools::Rectangle& ); |