summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolan.mcnamara@collabora.com>2024-07-23 15:39:24 +0100
committerTomaž Vajngerl <quikee@gmail.com>2024-07-23 23:12:36 +0200
commit315ea3acca1196c91c05a37844524fadb1628d6f (patch)
tree7cdd56aed32163c99bdebfd1caed26fdf4173de9
parentc877ca6fc9889614f9a3f5bf1f4aa8cb06f82c7a (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.hxx5
-rw-r--r--vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdfbin0 -> 1249 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport2.cxx66
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx16
-rw-r--r--vcl/source/gdi/pdfobjectcopier.cxx15
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
new file mode 100644
index 000000000000..0370c2bbd2e6
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/xnview-colorspace.pdf
Binary files differ
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))