summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-06-18 12:12:52 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-06-29 09:09:29 +0200
commit6e267f362fec03662e36641d275a42119f1798ce (patch)
tree291d177cbd6fe6bd9572e1ee1f6494e89444b929 /vcl/source
parenta35b5c26691fe938843a48a56e471eb048b9a182 (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.cxx273
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx233
-rw-r--r--vcl/source/gdi/pdfwriter_impl.hxx22
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& );