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