From 34d3315af070ce0278363c14a1d85cf4416985d1 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 7 Jan 2022 12:23:34 +0100 Subject: PDF export of PDF images: preserve hyperlinks The input file has a single page, with a full-page PDF image, which contains a hyperlink. Similar to pdfcrop, we used to wrap this into a form XObject, so page-level annotations like hyperlinks were lost. Explicitly merge page-level annotations from the source page to the page that contains the PDF image to preserve those annotations. Change-Id: I96e8bc9d33440b91f3514486d6a8bd75047546b2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128108 Reviewed-by: Miklos Vajna Tested-by: Jenkins (cherry picked from commit 1984a5c140cc3c7c291047dacf3bddd7061d2047) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128156 Reviewed-by: Xisco Fauli --- .../cppunit/pdfexport/data/pdf-image-hyperlink.odg | Bin 0 -> 28633 bytes vcl/qa/cppunit/pdfexport/pdfexport.cxx | 18 +++++++++++ vcl/source/gdi/pdfwriter_impl.cxx | 35 +++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 vcl/qa/cppunit/pdfexport/data/pdf-image-hyperlink.odg diff --git a/vcl/qa/cppunit/pdfexport/data/pdf-image-hyperlink.odg b/vcl/qa/cppunit/pdfexport/data/pdf-image-hyperlink.odg new file mode 100644 index 000000000000..aa0f89300b2c Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/pdf-image-hyperlink.odg differ diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index f4b6031ea4c3..ee2a7938d0d4 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -2858,6 +2858,24 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf145873) CPPUNIT_ASSERT_DOUBLES_EQUAL(3.49, pObject->getBounds().getHeight(), 0.1); } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfImageHyperlink) +{ + // Given a Draw file, containing a PDF image, which has a hyperlink in it: + aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); + + // When saving to PDF: + saveAsPDF(u"pdf-image-hyperlink.odg"); + + // Then make sure that link is preserved: + std::unique_ptr pPdfDocument = parseExport(); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); + CPPUNIT_ASSERT(pPdfPage); + // Without the accompanying fix in place, this test would have failed, the hyperlink of the PDF + // image was lost. + CPPUNIT_ASSERT(pPdfPage->hasLinks()); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 3db1ca90f235..e9a61fab394c 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -8434,6 +8434,41 @@ void PDFWriterImpl::writeReferenceXObject(const ReferenceXObjectEmit& rEmit) return; } + // Merge page annotations (links, etc) from pPage to our page. + std::vector aAnnots; + if (auto pArray = dynamic_cast(pPage->Lookup("Annots"))) + { + for (const auto pElement : pArray->GetElements()) + { + auto pReference = dynamic_cast(pElement); + if (!pReference) + { + continue; + } + + filter::PDFObjectElement* pObject = pReference->LookupObject(); + if (!pObject) + { + continue; + } + + // Annotation refers to an object, remember it. + aAnnots.push_back(pObject); + } + } + if (!aAnnots.empty()) + { + PDFObjectCopier aCopier(*this); + SvMemoryStream& rDocBuffer = pPage->GetDocument().GetEditBuffer(); + std::map aMap; + for (const auto& pAnnot : aAnnots) + { + // Copy over the annotation and refer to its new id. + sal_Int32 nNewId = aCopier.copyExternalResource(rDocBuffer, *pAnnot, aMap); + m_aPages.back().m_aAnnotations.push_back(nNewId); + } + } + nWrappedFormObject = createObject(); // Write the form XObject wrapped below. This is a separate object from // the wrapper, this way there is no need to alter the stream contents. -- cgit