diff options
-rw-r--r-- | include/vcl/filter/pdfdocument.hxx | 14 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfdocument.cxx | 46 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 45 |
3 files changed, 100 insertions, 5 deletions
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx index fbfb81ed10a2..9ccbb43d0225 100644 --- a/include/vcl/filter/pdfdocument.hxx +++ b/include/vcl/filter/pdfdocument.hxx @@ -32,6 +32,7 @@ class PDFDocument; class PDFDictionaryElement; class PDFArrayElement; class PDFStreamElement; +class PDFNumberElement; /// A byte range in a PDF file. class VCL_DLLPUBLIC PDFElement @@ -54,6 +55,10 @@ class VCL_DLLPUBLIC PDFObjectElement : public PDFElement /// Length of the dictionary buffer till (before) the '>>' token. sal_uInt64 m_nDictionaryLength; PDFDictionaryElement* m_pDictionaryElement; + /// Position after the '[' token, if m_pArrayElement is set. + sal_uInt64 m_nArrayOffset; + /// Length of the array buffer till (before) the ']' token. + sal_uInt64 m_nArrayLength; /// The contained direct array, if any. PDFArrayElement* m_pArrayElement; /// The stream of this object, used when this is an object stream. @@ -83,6 +88,10 @@ public: void SetStream(PDFStreamElement* pStreamElement); /// Access to the stream of the object, if it has any. PDFStreamElement* GetStream() const; + void SetArrayOffset(sal_uInt64 nArrayOffset); + sal_uInt64 GetArrayOffset(); + void SetArrayLength(sal_uInt64 nArrayLength); + sal_uInt64 GetArrayLength(); PDFArrayElement* GetArray() const; /// Parse objects stored in this object stream. void ParseStoredObjects(); @@ -113,9 +122,11 @@ class VCL_DLLPUBLIC PDFReferenceElement : public PDFElement int m_fGenerationValue; /// Location after the 'R' token. sal_uInt64 m_nOffset = 0; + /// The element providing the object number. + PDFNumberElement& m_rObject; public: - PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue); + PDFReferenceElement(PDFDocument& rDoc, PDFNumberElement& rObject, PDFNumberElement& rGeneration); bool Read(SvStream& rStream) override; /// Assuming the reference points to a number object, return its value. double LookupNumber(SvStream& rStream) const; @@ -124,6 +135,7 @@ public: int GetObjectValue() const; int GetGenerationValue() const; sal_uInt64 GetOffset() const; + PDFNumberElement& GetObjectElement() const; }; /// Stream object: a byte array with a known length. diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 8744729fdd83..926ebb0500fd 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -944,7 +944,10 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s // The array is attached directly, inform the object. pArray = pArr; if (pObject) + { pObject->SetArray(pArray); + pObject->SetArrayOffset(rStream.Tell()); + } } rStream.SeekRel(-1); if (!rElements.back()->Read(rStream)) @@ -959,6 +962,13 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s rElements.push_back(std::unique_ptr<PDFElement>(new PDFEndArrayElement())); pArray = nullptr; rStream.SeekRel(-1); + if (nDictionaryDepth == 0) + { + if (pObject) + { + pObject->SetArrayLength(rStream.Tell() - pObject->GetArrayOffset()); + } + } if (!rElements.back()->Read(rStream)) { SAL_WARN("vcl.filter", "PDFDocument::Tokenize: PDFEndArrayElement::Read() failed"); @@ -1049,7 +1059,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s } else { - rElements.push_back(std::unique_ptr<PDFElement>(new PDFReferenceElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue()))); + rElements.push_back(std::unique_ptr<PDFElement>(new PDFReferenceElement(*this, *pObjectNumber, *pGenerationNumber))); if (pArray) // Reference is part of a direct (non-dictionary) array, inform the array. pArray->PushBack(rElements.back().get()); @@ -2068,6 +2078,8 @@ PDFObjectElement::PDFObjectElement(PDFDocument& rDoc, double fObjectValue, doubl m_nDictionaryOffset(0), m_nDictionaryLength(0), m_pDictionaryElement(nullptr), + m_nArrayOffset(0), + m_nArrayLength(0), m_pArrayElement(nullptr), m_pStreamElement(nullptr) { @@ -2368,6 +2380,16 @@ sal_uInt64 PDFObjectElement::GetDictionaryOffset() return m_nDictionaryOffset; } +void PDFObjectElement::SetArrayOffset(sal_uInt64 nArrayOffset) +{ + m_nArrayOffset = nArrayOffset; +} + +sal_uInt64 PDFObjectElement::GetArrayOffset() +{ + return m_nArrayOffset; +} + void PDFDictionaryElement::SetKeyOffset(const OString& rKey, sal_uInt64 nOffset) { m_aDictionaryKeyOffset[rKey] = nOffset; @@ -2414,6 +2436,16 @@ sal_uInt64 PDFObjectElement::GetDictionaryLength() return m_nDictionaryLength; } +void PDFObjectElement::SetArrayLength(sal_uInt64 nArrayLength) +{ + m_nArrayLength = nArrayLength; +} + +sal_uInt64 PDFObjectElement::GetArrayLength() +{ + return m_nArrayLength; +} + PDFDictionaryElement* PDFObjectElement::GetDictionary() const { return m_pDictionaryElement; @@ -2599,11 +2631,17 @@ PDFDocument& PDFObjectElement::GetDocument() return m_rDoc; } -PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue) +PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, PDFNumberElement& rObject, PDFNumberElement& rGeneration) : m_rDoc(rDoc), - m_fObjectValue(fObjectValue), - m_fGenerationValue(fGenerationValue) + m_fObjectValue(rObject.GetValue()), + m_fGenerationValue(rGeneration.GetValue()), + m_rObject(rObject) +{ +} + +PDFNumberElement& PDFReferenceElement::GetObjectElement() const { + return m_rObject; } bool PDFReferenceElement::Read(SvStream& rStream) diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 061bc825d7a4..6d6e7eec9993 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -10912,6 +10912,51 @@ sal_Int32 PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter 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 contains a reference. + 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); + + sal_uInt64 nArrStart = rObject.GetArrayOffset(); + sal_uInt64 nReferenceStart = pReference->GetObjectElement().GetLocation(); + sal_uInt64 nReferenceEnd = pReference->GetOffset(); + sal_uInt64 nArrEnd = nArrStart + rObject.GetArrayLength(); + + // Array start -> reference start. + aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nArrStart, nReferenceStart - nArrStart); + // Write the updated reference. + aLine.append(" "); + aLine.append(nRef); + aLine.append(" 0 R"); + // Reference end -> array end. + aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + nReferenceEnd, nArrEnd - nReferenceEnd); + + bDone = true; + break; + } + } + } + + // Can copy it as-is. + if (!bDone) + aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + rObject.GetArrayOffset(), rObject.GetArrayLength()); + + aLine.append("]\n"); + } + aLine.append("endobj\n\n"); // We have the whole object, now write it to the output. |