diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-06-18 12:12:52 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-06-18 14:36:29 +0200 |
commit | 8277073ce3e33788d93b3df490a8f03d1814863b (patch) | |
tree | 51094d52c1a629ddbb6d3e24d9b583ba74e5f042 /vcl/source/gdi/pdfwriter_impl.cxx | |
parent | a60a5e769a407fa13b087a111123ceff5a96bc03 (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().
Change-Id: Ia5e5c1e452bb0d0486bde2a082375b5131eea8c7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96595
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
Diffstat (limited to 'vcl/source/gdi/pdfwriter_impl.cxx')
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 233 |
1 files changed, 3 insertions, 230 deletions
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 304ae011ee72..44c21afb2214 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -76,6 +76,7 @@ #include <bitmapwriteaccess.hxx> #include <impglyphitem.hxx> #include <pdf/XmpMetadata.hxx> +#include <pdf/objectcopier.hxx> #include "pdfwriter_impl.hxx" @@ -8344,235 +8345,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 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 (!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) @@ -8694,8 +8466,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); |