summaryrefslogtreecommitdiff
path: root/vcl/source/gdi/pdfwriter_impl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/gdi/pdfwriter_impl.cxx')
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx80
1 files changed, 68 insertions, 12 deletions
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index c5b873565611..9a78d6908a58 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -111,6 +111,18 @@ constexpr sal_Int32 pointToPixel(double pt)
return sal_Int32(pt * fDivisor);
}
+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 ");
+}
+
void appendHex(sal_Int8 nInt, OStringBuffer& rBuffer)
{
static const char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
@@ -1801,6 +1813,43 @@ sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject )
return nObject;
}
+// every structure element already has a unique object id - just use it for ID
+static OString GenerateID(sal_Int32 const nObjectId)
+{
+ return "id" + OString::number(nObjectId);
+}
+
+sal_Int32 PDFWriterImpl::emitStructIDTree(sal_Int32 const nObject)
+{
+ // loosely following PDF 1.7, 10.6.5 Example of Logical Structure, Example 10.15
+ if (nObject < 0)
+ {
+ return nObject;
+ }
+ // the name tree entries must be sorted lexicographically.
+ std::map<OString, sal_Int32> ids;
+ for (auto n : m_StructElemObjsWithID)
+ {
+ ids.emplace(GenerateID(n), n);
+ }
+ OStringBuffer buf;
+ appendObjectID(nObject, buf);
+ buf.append("<</Names [\n");
+ for (auto const& it : ids)
+ {
+ appendLiteralStringEncrypt(it.first, nObject, buf);
+ buf.append(" ");
+ appendObjectReference(it.second, buf);
+ buf.append("\n");
+ }
+ buf.append("] >>\nendobj\n\n");
+
+ CHECK_RETURN( updateObject(nObject) );
+ CHECK_RETURN( writeBuffer(buf.getStr(), buf.getLength()) );
+
+ return nObject;
+}
+
const char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr )
{
static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings;
@@ -2084,6 +2133,7 @@ sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
aLine.append( " 0 obj\n"
"<</Type" );
sal_Int32 nParentTree = -1;
+ sal_Int32 nIDTree = -1;
if( rEle.m_nOwnElement == rEle.m_nParentElement )
{
nParentTree = createObject();
@@ -2105,6 +2155,13 @@ sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
}
aLine.append( ">>\n" );
}
+ if (!m_StructElemObjsWithID.empty())
+ {
+ nIDTree = createObject();
+ aLine.append("/IDTree ");
+ appendObjectReference(nIDTree, aLine);
+ aLine.append("\n");
+ }
}
else
{
@@ -2114,6 +2171,11 @@ sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
aLine.append( rEle.m_aAlias );
else
aLine.append( getStructureTag( rEle.m_eType ) );
+ if (m_StructElemObjsWithID.find(rEle.m_nObject) != m_StructElemObjsWithID.end())
+ {
+ aLine.append("\n/ID ");
+ appendLiteralStringEncrypt(GenerateID(rEle.m_nObject), rEle.m_nObject, aLine);
+ }
aLine.append( "\n"
"/P " );
aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject );
@@ -2207,6 +2269,7 @@ sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
CHECK_RETURN( emitStructParentTree( nParentTree ) );
+ CHECK_RETURN( emitStructIDTree(nIDTree) );
return rEle.m_nObject;
}
@@ -3811,18 +3874,6 @@ void appendAnnotationRect(tools::Rectangle const & rRectangle, OStringBuffer & a
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)
@@ -10672,6 +10723,11 @@ sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType,
rEle.m_nObject = createObject();
// update parent's kids list
m_aStructure[ rEle.m_nParentElement ].m_aKids.emplace_back(rEle.m_nObject);
+ // ISO 14289-1:2014, Clause: 7.9
+ if (rEle.m_eType == PDFWriter::Note)
+ {
+ m_StructElemObjsWithID.insert(rEle.m_nObject);
+ }
}
return nNewId;
}