diff options
author | Caolán McNamara <caolan.mcnamara@collabora.com> | 2024-07-23 15:39:24 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2024-07-23 23:12:36 +0200 |
commit | 315ea3acca1196c91c05a37844524fadb1628d6f (patch) | |
tree | 7cdd56aed32163c99bdebfd1caed26fdf4173de9 | |
parent | c877ca6fc9889614f9a3f5bf1f4aa8cb06f82c7a (diff) |
Resolves: tdf#162161 reexport of specific pdf appears blank
the contents of the referenced colorspace obj disappears so it gets
rendered blank
Change-Id: Iaa76d355b5903c695e74edadc329043156bad3b6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170906
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | include/vcl/filter/pdfdocument.hxx | 5 | ||||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdf | bin | 0 -> 1249 bytes | |||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 66 | ||||
-rw-r--r-- | vcl/source/filter/ipdf/pdfdocument.cxx | 16 | ||||
-rw-r--r-- | vcl/source/gdi/pdfobjectcopier.cxx | 15 |
5 files changed, 102 insertions, 0 deletions
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx index 7e9d6dd8045a..0055ba50071c 100644 --- a/include/vcl/filter/pdfdocument.hxx +++ b/include/vcl/filter/pdfdocument.hxx @@ -44,6 +44,7 @@ class PDFDocument; class PDFDictionaryElement; class PDFArrayElement; class PDFStreamElement; +class PDFNameElement; class PDFNumberElement; /// A byte range in a PDF file. @@ -73,6 +74,8 @@ class VCL_DLLPUBLIC PDFObjectElement final : public PDFElement double m_fGenerationValue; /// If set, the object contains this number element (outside any dictionary/array). PDFNumberElement* m_pNumberElement; + /// If set, the object contains this name element (outside any dictionary/array). + PDFNameElement* m_pNameElement; /// Position after the '<<' token. sal_uInt64 m_nDictionaryOffset; /// Length of the dictionary buffer till (before) the '>>' token. @@ -114,6 +117,8 @@ public: void SetDictionary(PDFDictionaryElement* pDictionaryElement); void SetNumberElement(PDFNumberElement* pNumberElement); PDFNumberElement* GetNumberElement() const; + void SetNameElement(PDFNameElement* pNameElement); + PDFNameElement* GetNameElement() const; /// Get access to the parsed key-value items from the object dictionary. const std::map<OString, PDFElement*>& GetDictionaryItems(); const std::vector<PDFReferenceElement*>& GetDictionaryReferences() const; diff --git a/vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdf b/vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdf Binary files differnew file mode 100644 index 000000000000..0370c2bbd2e6 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdf diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 7da0dbc62f70..66c1f02b1e12 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -4911,6 +4911,72 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf159817) CPPUNIT_ASSERT_EQUAL(basegfx::B2DPoint(138.6, 623.7), roundPoint(37)); } +// tdf#162161 reexport appears to have blank image +CPPUNIT_TEST_FIXTURE(PdfExportTest2, testRexportXnViewColorspace) +{ + // We need to enable PDFium import (and make sure to disable after the test) + bool bResetEnvVar = false; + if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) + { + bResetEnvVar = true; + osl_setEnvironment(u"LO_IMPORT_USE_PDFIUM"_ustr.pData, u"1"_ustr.pData); + } + comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { + if (bResetEnvVar) + osl_clearEnvironment(u"LO_IMPORT_USE_PDFIUM"_ustr.pData); + }); + + // Load the PDF and save as PDF + vcl::filter::PDFDocument aDocument; + load(u"xnview-colorspace.pdf", aDocument); + + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(size_t(1), aPages.size()); + + // Get access to the only image on the only page. + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"_ostr); + CPPUNIT_ASSERT(pResources); + + auto pXObjects + = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"_ostr)); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(size_t(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject + = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + auto pSubResources + = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"_ostr)); + CPPUNIT_ASSERT(pSubResources); + pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( + pSubResources->LookupElement("XObject"_ostr)); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(size_t(1), pXObjects->GetItems().size()); + pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + pSubResources + = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources"_ostr)); + CPPUNIT_ASSERT(pSubResources); + pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( + pSubResources->LookupElement("XObject"_ostr)); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(size_t(1), pXObjects->GetItems().size()); + pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Dig all the way down to this element which is originally + // 8 0 obj + // /DeviceRGB + // endobj + // and appeared blank when we lost the /DeviceRGB line + auto pColorspace = pXObject->LookupObject("ColorSpace"_ostr); + CPPUNIT_ASSERT(pColorspace); + auto pColorSpaceElement = pColorspace->GetNameElement(); + CPPUNIT_ASSERT(pColorSpaceElement); + CPPUNIT_ASSERT_EQUAL("DeviceRGB"_ostr, pColorSpaceElement->GetValue()); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 159db9a38ba2..dac68d5344af 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -1102,6 +1102,14 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, pObjectStream = pObject; else pObjectKey = pNameElement; + + if (bInObject && !nDepth && pObject) + { + // Name element inside an object, but outside a + // dictionary / array: remember it. + pObject->SetNameElement(pNameElement); + } + break; } case '(': @@ -2291,6 +2299,7 @@ PDFObjectElement::PDFObjectElement(PDFDocument& rDoc, double fObjectValue, doubl , m_fObjectValue(fObjectValue) , m_fGenerationValue(fGenerationValue) , m_pNumberElement(nullptr) + , m_pNameElement(nullptr) , m_nDictionaryOffset(0) , m_nDictionaryLength(0) , m_pDictionaryElement(nullptr) @@ -2462,6 +2471,13 @@ void PDFObjectElement::SetNumberElement(PDFNumberElement* pNumberElement) PDFNumberElement* PDFObjectElement::GetNumberElement() const { return m_pNumberElement; } +void PDFObjectElement::SetNameElement(PDFNameElement* pNameElement) +{ + m_pNameElement = pNameElement; +} + +PDFNameElement* PDFObjectElement::GetNameElement() const { return m_pNameElement; } + const std::vector<PDFReferenceElement*>& PDFObjectElement::GetDictionaryReferences() const { return m_aDictionaryReferences; diff --git a/vcl/source/gdi/pdfobjectcopier.cxx b/vcl/source/gdi/pdfobjectcopier.cxx index 0d07c0df7f67..56c3ba6e8138 100644 --- a/vcl/source/gdi/pdfobjectcopier.cxx +++ b/vcl/source/gdi/pdfobjectcopier.cxx @@ -139,6 +139,21 @@ sal_Int32 PDFObjectCopier::copyExternalResource(SvMemoryStream& rDocBuffer, pNumber->writeString(aLine); aLine.append("\n"); } + // If the object has a name element outside a dictionary or array, copy that. + else if (filter::PDFNameElement* pName = rObject.GetNameElement()) + { + // currently just handle the exact case seen in the real world + if (pName->GetValue() == "DeviceRGB") + { + pName->writeString(aLine); + aLine.append("\n"); + } + else + { + SAL_INFO("vcl.pdfwriter", + "PDFObjectCopier::copyExternalResource: skipping: " << pName->GetValue()); + } + } // We have the whole object, now write it to the output. if (!m_rContainer.updateObject(nObject)) |