[Libreoffice-commits] core.git: sd/qa vcl/source
Tomaž Vajngerl (via logerrit)
logerrit at kemper.freedesktop.org
Mon Jun 22 06:14:12 UTC 2020
sd/qa/unit/SdrPdfImportTest.cxx | 9 +-
vcl/source/gdi/pdfwriter_impl.cxx | 128 ++++++++++++++++++++++++++++----------
vcl/source/gdi/pdfwriter_impl.hxx | 14 +++-
3 files changed, 113 insertions(+), 38 deletions(-)
New commits:
commit 51d529c18dadb05754590a01ce4c1f06f41cf412
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sat Jun 20 08:43:58 2020 +0200
Commit: Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Jun 22 08:13:31 2020 +0200
pdf export: support pop-up annotation for notes / comments
This changes pdf export for annotation, so the comments are
exported as "text" annotation with an child "pop-up" annotations.
This seems to be more common what PDF readers do (even when text
annotation only should be enough).
Also changes the test, so that it now works as expected.
Change-Id: I95bc12939f490effe7759dad54e136c44e44a2f8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96765
Tested-by: Tomaž Vajngerl <quikee at gmail.com>
Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
diff --git a/sd/qa/unit/SdrPdfImportTest.cxx b/sd/qa/unit/SdrPdfImportTest.cxx
index 4bbb24de4035..e8dd60b0a806 100644
--- a/sd/qa/unit/SdrPdfImportTest.cxx
+++ b/sd/qa/unit/SdrPdfImportTest.cxx
@@ -231,14 +231,13 @@ CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testAnnotationsImportExport)
auto pPDFPage = pPDFDocument->openPage(0);
CPPUNIT_ASSERT(pPDFPage);
- // TODO: Should be 2 really
- CPPUNIT_ASSERT_EQUAL(1, pPDFPage->getAnnotationCount());
+ CPPUNIT_ASSERT_EQUAL(2, pPDFPage->getAnnotationCount());
auto pPDFAnnotation1 = pPDFPage->getAnnotation(0);
CPPUNIT_ASSERT_EQUAL(1, pPDFAnnotation1->getSubType()); // Text annotation
- //auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
- //CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
+ auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
+ CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
// Load document again
mxComponent = loadFromDesktop(aTempFile.GetURL());
@@ -249,7 +248,7 @@ CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testAnnotationsImportExport)
SdPage* pPage = pNewViewShell->GetActualPage();
CPPUNIT_ASSERT(pPage);
- //CPPUNIT_ASSERT_EQUAL(false, pPage->getAnnotations().empty());
+ CPPUNIT_ASSERT(!pPage->getAnnotations().empty());
}
#endif // HAVE_FEATURE_PDFIUM
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 04fcb70a152f..c7e56544f58a 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -3418,50 +3418,111 @@ we check in the following sequence:
return true;
}
+namespace
+{
+
+void appendAnnotationRect(tools::Rectangle const & rRectangle, OStringBuffer & aLine)
+{
+ aLine.append("/Rect[");
+ appendFixedInt(rRectangle.Left(), aLine);
+ aLine.append(' ');
+ appendFixedInt(rRectangle.Top(), aLine);
+ aLine.append(' ');
+ appendFixedInt(rRectangle.Right(), aLine);
+ aLine.append(' ');
+ appendFixedInt(rRectangle.Bottom(), aLine);
+ aLine.append("] ");
+}
+
+void appendObjectID(sal_Int32 nObjectID, OStringBuffer & aLine)
+{
+ aLine.append(nObjectID);
+ aLine.append(" 0 obj\n");
+}
+
+void appendObjectReference(sal_Int32 nObjectID, OStringBuffer & aLine)
+{
+ aLine.append(nObjectID);
+ aLine.append(" 0 R ");
+}
+
+} // end anonymous namespace
+
+void PDFWriterImpl::emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote)
+{
+ appendObjectID(rNote.m_nObject, aLine);
+
+ aLine.append("<</Type /Annot /Subtype /Text ");
+
+// i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
+// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
+ if (m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3)
+ aLine.append("/F 4 ");
+
+ appendAnnotationRect(rNote.m_aRect, aLine);
+
+ aLine.append("/Popup ");
+ appendObjectReference(rNote.m_aPopUpAnnotation.m_nObject, aLine);
+
+ // contents of the note (type text string)
+ aLine.append("/Contents ");
+ appendUnicodeTextStringEncrypt(rNote.m_aContents.Contents, rNote.m_nObject, aLine);
+ aLine.append("\n");
+
+ // optional title
+ if (!rNote.m_aContents.Title.isEmpty())
+ {
+ aLine.append("/T ");
+ appendUnicodeTextStringEncrypt(rNote.m_aContents.Title, rNote.m_nObject, aLine);
+ aLine.append("\n");
+ }
+ aLine.append(">>\n");
+ aLine.append("endobj\n\n");
+}
+
+void PDFWriterImpl::emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp)
+{
+ appendObjectID(rPopUp.m_nObject, aLine);
+ aLine.append("<</Type /Annot /Subtype /Popup ");
+ aLine.append("/Parent ");
+ appendObjectReference(rPopUp.m_nParentObject, aLine);
+ aLine.append(">>\n");
+ aLine.append("endobj\n\n");
+}
+
bool PDFWriterImpl::emitNoteAnnotations()
{
// emit note annotations
int nAnnots = m_aNotes.size();
for( int i = 0; i < nAnnots; i++ )
{
- const PDFNoteEntry& rNote = m_aNotes[i];
- if( ! updateObject( rNote.m_nObject ) )
- return false;
+ const PDFNoteEntry& rNote = m_aNotes[i];
+ const PDFPopupAnnotation& rPopUp = rNote.m_aPopUpAnnotation;
- OStringBuffer aLine( 1024 );
- aLine.append( rNote.m_nObject );
- aLine.append( " 0 obj\n" );
-// i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
-// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
- aLine.append( "<</Type/Annot" );
- if( m_bIsPDF_A1 || m_bIsPDF_A2 || m_bIsPDF_A3 )
- aLine.append( "/F 4" );
- aLine.append( "/Subtype/Text/Rect[" );
+ {
+ if (!updateObject(rNote.m_nObject))
+ return false;
- appendFixedInt( rNote.m_aRect.Left(), aLine );
- aLine.append( ' ' );
- appendFixedInt( rNote.m_aRect.Top(), aLine );
- aLine.append( ' ' );
- appendFixedInt( rNote.m_aRect.Right(), aLine );
- aLine.append( ' ' );
- appendFixedInt( rNote.m_aRect.Bottom(), aLine );
- aLine.append( "]" );
+ OStringBuffer aLine(1024);
- // contents of the note (type text string)
- aLine.append( "/Contents\n" );
- appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
- aLine.append( "\n" );
+ emitTextAnnotationLine(aLine, rNote);
- // optional title
- if( !rNote.m_aContents.Title.isEmpty() )
- {
- aLine.append( "/T" );
- appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
- aLine.append( "\n" );
+ if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+ return false;
}
- aLine.append( ">>\nendobj\n\n" );
- CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ {
+
+ if (!updateObject(rPopUp.m_nObject))
+ return false;
+
+ OStringBuffer aLine(1024);
+
+ emitPopupAnnotationLine(aLine, rPopUp);
+
+ if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+ return false;
+ }
}
return true;
}
@@ -9658,6 +9719,8 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN
m_aNotes.emplace_back();
auto & rNoteEntry = m_aNotes.back();
rNoteEntry.m_nObject = createObject();
+ rNoteEntry.m_aPopUpAnnotation.m_nObject = createObject();
+ rNoteEntry.m_aPopUpAnnotation.m_nParentObject = rNoteEntry.m_nObject;
rNoteEntry.m_aContents = rNote;
rNoteEntry.m_aRect = rRect;
// convert to default user space now, since the mapmode may change
@@ -9665,6 +9728,7 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN
// insert note to page's annotation list
m_aPages[nPageNr].m_aAnnotations.push_back(rNoteEntry.m_nObject);
+ m_aPages[nPageNr].m_aAnnotations.push_back(rNoteEntry.m_aPopUpAnnotation.m_nObject);
}
sal_Int32 PDFWriterImpl::createLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
index eb53db7d5877..b5d86a2d2486 100644
--- a/vcl/source/gdi/pdfwriter_impl.hxx
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -403,10 +403,18 @@ struct PDFEmbeddedFile
}
};
+struct PDFPopupAnnotation : public PDFAnnotation
+{
+ /// ID of the parent object.
+ sal_Int32 m_nParentObject;
+};
+
struct PDFNoteEntry : public PDFAnnotation
{
PDFNote m_aContents;
+ PDFPopupAnnotation m_aPopUpAnnotation;
+
PDFNoteEntry()
{}
};
@@ -873,10 +881,14 @@ i12626
bool appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer );
// write all links
bool emitLinkAnnotations();
- /// Write all screen annotations.
+ // Write all screen annotations.
bool emitScreenAnnotations();
+
+ void emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote);
+ static void emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp);
// write all notes
bool emitNoteAnnotations();
+
// write the appearance streams of a widget
bool emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict );
// clean up radio button "On" values
More information about the Libreoffice-commits
mailing list