LibreOffice Module vcl (master) 1
XmpMetadata.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <pdf/XmpMetadata.hxx>
12#include <tools/XmlWriter.hxx>
13
14namespace vcl::pdf
15{
16namespace
17{
18constexpr const char* constPadding = " "
19 " "
20 " "
21 " "
22 " "
23 "\n";
24}
25
27 : mbWritten(false)
28 , mnPDF_A(0)
29 , mbPDF_UA(false)
30{
31}
32
34{
35 mpMemoryStream = std::make_unique<SvMemoryStream>(4096 /*Initial*/, 64 /*Resize*/);
36
37 // Header
38 mpMemoryStream->WriteOString(
39 OStringLiteral(u8"<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"));
40
41 {
42 tools::XmlWriter aXmlWriter(mpMemoryStream.get());
43 aXmlWriter.startDocument(2, false);
44 aXmlWriter.startElement("x", "xmpmeta", "adobe:ns:meta/");
45 aXmlWriter.startElement("rdf", "RDF", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
46
47 // PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
48 if (mnPDF_A > 0)
49 {
50 OString sPdfVersion = OString::number(mnPDF_A);
51
52 aXmlWriter.startElement("rdf:Description");
53 aXmlWriter.attribute("rdf:about", OString(""));
54 aXmlWriter.attribute("xmlns:pdfaid", OString("http://www.aiim.org/pdfa/ns/id/"));
55
56 aXmlWriter.startElement("pdfaid:part");
57 aXmlWriter.content(sPdfVersion);
58 aXmlWriter.endElement();
59
60 aXmlWriter.startElement("pdfaid:conformance");
61 aXmlWriter.content("B");
62 aXmlWriter.endElement();
63
64 aXmlWriter.endElement();
65 }
66
67 // Dublin Core properties
68 if (!msTitle.isEmpty() || !msAuthor.isEmpty() || !msSubject.isEmpty())
69 {
70 aXmlWriter.startElement("rdf:Description");
71 aXmlWriter.attribute("rdf:about", OString(""));
72 aXmlWriter.attribute("xmlns:dc", OString("http://purl.org/dc/elements/1.1/"));
73 if (!msTitle.isEmpty())
74 {
75 // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
76 aXmlWriter.startElement("dc:title");
77 aXmlWriter.startElement("rdf:Alt");
78 aXmlWriter.startElement("rdf:li");
79 aXmlWriter.attribute("xml:lang", OString("x-default"));
80 aXmlWriter.content(msTitle);
81 aXmlWriter.endElement();
82 aXmlWriter.endElement();
83 aXmlWriter.endElement();
84 }
85 if (!msAuthor.isEmpty())
86 {
87 aXmlWriter.startElement("dc:creator");
88 aXmlWriter.startElement("rdf:Seq");
89 aXmlWriter.startElement("rdf:li");
90 aXmlWriter.content(msAuthor);
91 aXmlWriter.endElement();
92 aXmlWriter.endElement();
93 aXmlWriter.endElement();
94 }
95 if (!msSubject.isEmpty())
96 {
97 aXmlWriter.startElement("dc:description");
98 aXmlWriter.startElement("rdf:Alt");
99 aXmlWriter.startElement("rdf:li");
100 aXmlWriter.attribute("xml:lang", OString("x-default"));
101 aXmlWriter.content(msSubject);
102 aXmlWriter.endElement();
103 aXmlWriter.endElement();
104 aXmlWriter.endElement();
105 }
106 aXmlWriter.endElement();
107 }
108
109 // PDF/UA
110 if (mbPDF_UA && mnPDF_A == 0) // veraPDF says this is not allowed in PDF/A-[123][ab]
111 {
112 OString sPdfUaVersion = OString::number(1);
113 aXmlWriter.startElement("rdf:Description");
114 aXmlWriter.attribute("rdf:about", OString(""));
115 aXmlWriter.attribute("xmlns:pdfuaid", OString("http://www.aiim.org/pdfua/ns/id/"));
116
117 aXmlWriter.startElement("pdfuaid:part");
118 aXmlWriter.content(sPdfUaVersion);
119 aXmlWriter.endElement();
120
121 aXmlWriter.endElement();
122 }
123
124 // PDF properties
125 if (!msProducer.isEmpty() || !msKeywords.isEmpty())
126 {
127 aXmlWriter.startElement("rdf:Description");
128 aXmlWriter.attribute("rdf:about", OString(""));
129 aXmlWriter.attribute("xmlns:pdf", OString("http://ns.adobe.com/pdf/1.3/"));
130 if (!msProducer.isEmpty())
131 {
132 aXmlWriter.startElement("pdf:Producer");
133 aXmlWriter.content(msProducer);
134 aXmlWriter.endElement();
135 }
136 if (!msKeywords.isEmpty())
137 {
138 aXmlWriter.startElement("pdf:Keywords");
139 aXmlWriter.content(msKeywords);
140 aXmlWriter.endElement();
141 }
142 aXmlWriter.endElement();
143 }
144
145 // XMP Basic schema
146 aXmlWriter.startElement("rdf:Description");
147 aXmlWriter.attribute("rdf:about", OString(""));
148 aXmlWriter.attribute("xmlns:xmp", OString("http://ns.adobe.com/xap/1.0/"));
149 if (!m_sCreatorTool.isEmpty())
150 {
151 aXmlWriter.startElement("xmp:CreatorTool");
152 aXmlWriter.content(m_sCreatorTool);
153 aXmlWriter.endElement();
154 }
155 aXmlWriter.startElement("xmp:CreateDate");
156 aXmlWriter.content(m_sCreateDate);
157 aXmlWriter.endElement();
158 aXmlWriter.endElement();
159
160 aXmlWriter.endElement();
161 aXmlWriter.endElement();
162 aXmlWriter.endDocument();
163 }
164
165 // add padding (needed so the metadata can be changed in-place"
166 for (sal_Int32 nSpaces = 1; nSpaces <= 21; nSpaces++)
167 mpMemoryStream->WriteOString(constPadding);
168
169 mpMemoryStream->WriteOString("<?xpacket end=\"w\"?>\n");
170 mbWritten = true;
171}
172
174{
175 if (!mbWritten)
176 write();
177 return mpMemoryStream->GetSize();
178}
179
181{
182 if (!mbWritten)
183 write();
184 return mpMemoryStream->GetData();
185}
186
187} // end vcl::pdf
188
189/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void content(const OString &sValue)
bool startDocument(sal_Int32 nIndent=2, bool bWriteXmlHeader=true)
void attribute(const char *sTagName, const OString &aValue)
void startElement(const char *sName)
std::unique_ptr< SvMemoryStream > mpMemoryStream
Definition: XmpMetadata.hxx:24
const void * getData()