vcl/qa/cppunit/pdfexport/data/pdf-image-hyperlink.odg |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                |   18 +++++++++
 vcl/source/gdi/pdfwriter_impl.cxx                     |   35 ++++++++++++++++++
 3 files changed, 53 insertions(+)

New commits:
commit 34d3315af070ce0278363c14a1d85cf4416985d1
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Jan 7 12:23:34 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Jan 11 09:57:47 2022 +0100

    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 <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 1984a5c140cc3c7c291047dacf3bddd7061d2047)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128156
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

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<vcl::pdf::PDFiumDocument> pPdfDocument = parseExport();
+    CPPUNIT_ASSERT(pPdfDocument);
+    std::unique_ptr<vcl::pdf::PDFiumPage> 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<filter::PDFObjectElement*> aAnnots;
+        if (auto pArray = 
dynamic_cast<filter::PDFArrayElement*>(pPage->Lookup("Annots")))
+        {
+            for (const auto pElement : pArray->GetElements())
+            {
+                auto pReference = 
dynamic_cast<filter::PDFReferenceElement*>(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<sal_Int32, sal_Int32> 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.

Reply via email to