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

New commits:
commit 58e6fce28f7d3e1c1504f048be5766dc732af4e7
Author:     Miklos Vajna <[email protected]>
AuthorDate: Fri Jan 7 12:23:34 2022 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Mon Jan 10 14:10:14 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.
    
    (cherry picked from commit 1984a5c140cc3c7c291047dacf3bddd7061d2047)
    
    Conflicts:
            vcl/qa/cppunit/pdfexport/pdfexport.cxx
    
    Change-Id: I96e8bc9d33440b91f3514486d6a8bd75047546b2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128127
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>

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 3a5b11784f27..ba1468af5253 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2552,6 +2552,36 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, 
testPdfImageRotate180)
     // flip).
     CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, aScale.getX(), 0.01);
 }
+
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfImageHyperlink)
+{
+    // Given a Draw file, containing a PDF image, which has a hyperlink in it:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"pdf-image-hyperlink.odg";
+    mxComponent = loadFromDesktop(aURL);
+    CPPUNIT_ASSERT(mxComponent.is());
+
+    // When saving to PDF:
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    utl::MediaDescriptor aMediaDescriptor;
+    aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export");
+    xStorable->storeToURL(maTempFile.GetURL(), 
aMediaDescriptor.getAsConstPropertyValueList());
+
+    // Then make sure that link is preserved:
+    SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ);
+    maMemory.WriteStream(aFile);
+    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
+        = pPDFium->openDocument(maMemory.GetData(), maMemory.GetSize());
+    CPPUNIT_ASSERT(pPdfDocument);
+    CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
+    std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = 
pPdfDocument->openPage(/*nIndex=*/0);
+    CPPUNIT_ASSERT(pPdfPage);
+    int nStartPos = 0;
+    FPDF_LINK pLinkAnnot = nullptr;
+    // Without the accompanying fix in place, this test would have failed, the 
hyperlink of the PDF
+    // image was lost.
+    CPPUNIT_ASSERT(FPDFLink_Enumerate(pPdfPage->getPointer(), &nStartPos, 
&pLinkAnnot));
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 811fdeb14ce3..63f466a962d1 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -8511,6 +8511,41 @@ void 
PDFWriterImpl::writeReferenceXObject(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