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 OString sPdfConformance = (mnPDF_A == 1) ? "A" : "B";
52
53 aXmlWriter.startElement("rdf:Description");
54 aXmlWriter.attribute("rdf:about", OString(""));
55 aXmlWriter.attribute("xmlns:pdfaid", OString("http://www.aiim.org/pdfa/ns/id/"));
56
57 aXmlWriter.startElement("pdfaid:part");
58 aXmlWriter.content(sPdfVersion);
59 aXmlWriter.endElement();
60
61 aXmlWriter.startElement("pdfaid:conformance");
62 aXmlWriter.content(sPdfConformance);
63 aXmlWriter.endElement();
64
65 aXmlWriter.endElement();
66 }
67
68 // Dublin Core properties
69 if (!msTitle.isEmpty() || !msAuthor.isEmpty() || !msSubject.isEmpty())
70 {
71 aXmlWriter.startElement("rdf:Description");
72 aXmlWriter.attribute("rdf:about", OString(""));
73 aXmlWriter.attribute("xmlns:dc", OString("http://purl.org/dc/elements/1.1/"));
74 if (!msTitle.isEmpty())
75 {
76 // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
77 aXmlWriter.startElement("dc:title");
78 aXmlWriter.startElement("rdf:Alt");
79 aXmlWriter.startElement("rdf:li");
80 aXmlWriter.attribute("xml:lang", OString("x-default"));
81 aXmlWriter.content(msTitle);
82 aXmlWriter.endElement();
83 aXmlWriter.endElement();
84 aXmlWriter.endElement();
85 }
86 if (!msAuthor.isEmpty())
87 {
88 aXmlWriter.startElement("dc:creator");
89 aXmlWriter.startElement("rdf:Seq");
90 aXmlWriter.startElement("rdf:li");
91 aXmlWriter.content(msAuthor);
92 aXmlWriter.endElement();
93 aXmlWriter.endElement();
94 aXmlWriter.endElement();
95 }
96 if (!msSubject.isEmpty())
97 {
98 aXmlWriter.startElement("dc:description");
99 aXmlWriter.startElement("rdf:Alt");
100 aXmlWriter.startElement("rdf:li");
101 aXmlWriter.attribute("xml:lang", OString("x-default"));
102 aXmlWriter.content(msSubject);
103 aXmlWriter.endElement();
104 aXmlWriter.endElement();
105 aXmlWriter.endElement();
106 }
107 aXmlWriter.endElement();
108 }
109
110 // PDF/UA
111 if (mbPDF_UA)
112 {
113 OString sPdfUaVersion = OString::number(1);
114 aXmlWriter.startElement("rdf:Description");
115 aXmlWriter.attribute("rdf:about", OString(""));
116 aXmlWriter.attribute("xmlns:pdfuaid", OString("http://www.aiim.org/pdfua/ns/id/"));
117
118 aXmlWriter.startElement("pdfuaid:part");
119 aXmlWriter.content(sPdfUaVersion);
120 aXmlWriter.endElement();
121
122 aXmlWriter.endElement();
123 }
124
125 // PDF properties
126 if (!msProducer.isEmpty() || !msKeywords.isEmpty())
127 {
128 aXmlWriter.startElement("rdf:Description");
129 aXmlWriter.attribute("rdf:about", OString(""));
130 aXmlWriter.attribute("xmlns:pdf", OString("http://ns.adobe.com/pdf/1.3/"));
131 if (!msProducer.isEmpty())
132 {
133 aXmlWriter.startElement("pdf:Producer");
134 aXmlWriter.content(msProducer);
135 aXmlWriter.endElement();
136 }
137 if (!msKeywords.isEmpty())
138 {
139 aXmlWriter.startElement("pdf:Keywords");
140 aXmlWriter.content(msKeywords);
141 aXmlWriter.endElement();
142 }
143 aXmlWriter.endElement();
144 }
145
146 // XMP Basic schema
147 aXmlWriter.startElement("rdf:Description");
148 aXmlWriter.attribute("rdf:about", OString(""));
149 aXmlWriter.attribute("xmlns:xmp", OString("http://ns.adobe.com/xap/1.0/"));
150 if (!m_sCreatorTool.isEmpty())
151 {
152 aXmlWriter.startElement("xmp:CreatorTool");
153 aXmlWriter.content(m_sCreatorTool);
154 aXmlWriter.endElement();
155 }
156 aXmlWriter.startElement("xmp:CreateDate");
157 aXmlWriter.content(m_sCreateDate);
158 aXmlWriter.endElement();
159 aXmlWriter.endElement();
160
161 aXmlWriter.endElement();
162 aXmlWriter.endElement();
163 aXmlWriter.endDocument();
164 }
165
166 // add padding (needed so the metadata can be changed in-place"
167 for (sal_Int32 nSpaces = 1; nSpaces <= 21; nSpaces++)
168 mpMemoryStream->WriteOString(constPadding);
169
170 mpMemoryStream->WriteOString("<?xpacket end=\"w\"?>\n");
171 mbWritten = true;
172}
173
175{
176 if (!mbWritten)
177 write();
178 return mpMemoryStream->GetSize();
179}
180
182{
183 if (!mbWritten)
184 write();
185 return mpMemoryStream->GetData();
186}
187
188} // end vcl::pdf
189
190/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void content(const OString &sValue)
bool startDocument(sal_Int32 nIndent=2, bool bWriteXmlHeader=true)
void attribute(const OString &sTagName, const OString &aValue)
void startElement(const OString &sName)
std::unique_ptr< SvMemoryStream > mpMemoryStream
Definition: XmpMetadata.hxx:24
const void * getData()