1 | /* | |
2 | * $Id: XmpWriter.java 3949 2009-06-03 15:19:04Z blowagie $ | |
3 | * | |
4 | * Copyright 2005 by Bruno Lowagie. | |
5 | * | |
6 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
7 | * (the "License"); you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
9 | * | |
10 | * Software distributed under the License is distributed on an "AS IS" basis, | |
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 | * for the specific language governing rights and limitations under the License. | |
13 | * | |
14 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
15 | * | |
16 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
17 | * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. | |
18 | * All Rights Reserved. | |
19 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
20 | * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. | |
21 | * | |
22 | * Contributor(s): all the names of the contributors are added in the source code | |
23 | * where applicable. | |
24 | * | |
25 | * Alternatively, the contents of this file may be used under the terms of the | |
26 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
27 | * provisions of LGPL are applicable instead of those above. If you wish to | |
28 | * allow use of your version of this file only under the terms of the LGPL | |
29 | * License and not to allow others to use your version of this file under | |
30 | * the MPL, indicate your decision by deleting the provisions above and | |
31 | * replace them with the notice and other provisions required by the LGPL. | |
32 | * If you do not delete the provisions above, a recipient may use your version | |
33 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE | |
34 | * | |
35 | * This library is free software; you can redistribute it and/or modify it | |
36 | * under the terms of the MPL as stated above or under the terms of the GNU | |
37 | * Library General Public License as published by the Free Software Foundation; | |
38 | * either version 2 of the License, or any later version. | |
39 | * | |
40 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
41 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
42 | * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more | |
43 | * details. | |
44 | * | |
45 | * If you didn't download this code from the following link, you should check if | |
46 | * you aren't using an obsolete version: | |
47 | * http://www.lowagie.com/iText/ | |
48 | */ | |
49 | ||
50 | package com.lowagie.text.xml.xmp; | |
51 | ||
52 | import com.lowagie.text.pdf.PdfDate; | |
53 | import com.lowagie.text.pdf.PdfDictionary; | |
54 | import com.lowagie.text.pdf.PdfName; | |
55 | import com.lowagie.text.pdf.PdfObject; | |
56 | import com.lowagie.text.pdf.PdfString; | |
57 | import com.lowagie.text.pdf.PdfWriter; | |
58 | ||
59 | import java.io.IOException; | |
60 | import java.io.OutputStream; | |
61 | import java.io.OutputStreamWriter; | |
62 | import java.util.Map; | |
63 | ||
64 | /** | |
65 | * With this class you can create an Xmp Stream that can be used for adding | |
66 | * Metadata to a PDF Dictionary. Remark that this class doesn't cover the | |
67 | * complete XMP specification. | |
68 | */ | |
69 | public class XmpWriter { | |
70 | ||
71 | /** A possible charset for the XMP. */ | |
72 | public static final String UTF8 = "UTF-8"; | |
73 | /** A possible charset for the XMP. */ | |
74 | public static final String UTF16 = "UTF-16"; | |
75 | /** A possible charset for the XMP. */ | |
76 | public static final String UTF16BE = "UTF-16BE"; | |
77 | /** A possible charset for the XMP. */ | |
78 | public static final String UTF16LE = "UTF-16LE"; | |
79 | | |
80 | /** String used to fill the extra space. */ | |
81 | public static final String EXTRASPACE = " \n"; | |
82 | | |
83 | /** You can add some extra space in the XMP packet; 1 unit in this variable represents 100 spaces and a newline. */ | |
84 | protected int extraSpace; | |
85 | | |
86 | /** The writer to which you can write bytes for the XMP stream. */ | |
87 | protected OutputStreamWriter writer; | |
88 | | |
89 | /** The about string that goes into the rdf:Description tags. */ | |
90 | protected String about; | |
91 | ||
92 | /** | |
93 | * Processing Instruction required at the start of an XMP stream | |
94 | * @since iText 2.1.6 | |
95 | */ | |
96 | public static final String XPACKET_PI_BEGIN = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"; | |
97 | | |
98 | /** | |
99 | * Processing Instruction required at the end of an XMP stream for XMP streams that can be updated | |
100 | * @since iText 2.1.6 | |
101 | */ | |
102 | public static final String XPACKET_PI_END_W = "<?xpacket end=\"w\"?>"; | |
103 | | |
104 | /** | |
105 | * Processing Instruction required at the end of an XMP stream for XMP streams that are read only | |
106 | * @since iText 2.1.6 | |
107 | */ | |
108 | public static final String XPACKET_PI_END_R = "<?xpacket end=\"r\"?>"; | |
109 | | |
110 | /** The end attribute. */ | |
111 | protected char end = 'w'; | |
112 | | |
113 | /** | |
114 | * Creates an XmpWriter. | |
115 | * @param os | |
116 | * @param utfEncoding | |
117 | * @param extraSpace | |
118 | * @throws IOException | |
119 | */ | |
120 | public XmpWriter(OutputStream os, String utfEncoding, int extraSpace) throws IOException { | |
121 | this.extraSpace = extraSpace; | |
122 | writer = new OutputStreamWriter(os, utfEncoding); | |
123 |
1
1. |
writer.write(XPACKET_PI_BEGIN); |
124 |
1
1. |
writer.write("<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n"); |
125 |
1
1. |
writer.write("<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"); |
126 | about = ""; | |
127 | } | |
128 | | |
129 | /** | |
130 | * Creates an XmpWriter. | |
131 | * @param os | |
132 | * @throws IOException | |
133 | */ | |
134 | public XmpWriter(OutputStream os) throws IOException { | |
135 | this(os, UTF8, 20); | |
136 | } | |
137 | ||
138 | ||
139 | /** | |
140 | * @param os | |
141 | * @param info | |
142 | * @throws IOException | |
143 | */ | |
144 | public XmpWriter(OutputStream os, PdfDictionary info, int PdfXConformance) throws IOException { | |
145 | this(os); | |
146 |
1
1. |
if (info != null) { |
147 | DublinCoreSchema dc = new DublinCoreSchema(); | |
148 | PdfSchema p = new PdfSchema(); | |
149 | XmpBasicSchema basic = new XmpBasicSchema(); | |
150 | PdfName key; | |
151 | PdfObject obj; | |
152 | for (PdfName pdfName : info.getKeys()) { | |
153 | key = pdfName; | |
154 | obj = info.get(key); | |
155 |
1
1. |
if (obj == null) |
156 | continue; | |
157 |
1
1. |
if (PdfName.TITLE.equals(key)) { |
158 |
1
1. |
dc.addTitle(((PdfString) obj).toUnicodeString()); |
159 | } | |
160 |
1
1. |
if (PdfName.AUTHOR.equals(key)) { |
161 |
1
1. |
dc.addAuthor(((PdfString) obj).toUnicodeString()); |
162 | } | |
163 |
1
1. |
if (PdfName.SUBJECT.equals(key)) { |
164 |
1
1. |
dc.addSubject(((PdfString) obj).toUnicodeString()); |
165 |
1
1. |
dc.addDescription(((PdfString) obj).toUnicodeString()); |
166 | } | |
167 |
1
1. |
if (PdfName.KEYWORDS.equals(key)) { |
168 |
1
1. |
p.addKeywords(((PdfString) obj).toUnicodeString()); |
169 | } | |
170 |
1
1. |
if (PdfName.CREATOR.equals(key)) { |
171 |
1
1. |
basic.addCreatorTool(((PdfString) obj).toUnicodeString()); |
172 | } | |
173 |
1
1. |
if (PdfName.PRODUCER.equals(key)) { |
174 |
1
1. |
p.addProducer(((PdfString) obj).toUnicodeString()); |
175 | } | |
176 |
1
1. |
if (PdfName.CREATIONDATE.equals(key)) { |
177 |
1
1. |
basic.addCreateDate(((PdfDate) obj).getW3CDate()); |
178 | } | |
179 |
1
1. |
if (PdfName.MODDATE.equals(key)) { |
180 |
1
1. |
basic.addModDate(((PdfDate) obj).getW3CDate()); |
181 | } | |
182 | } | |
183 |
3
1. 2. 3. |
if (dc.size() > 0) addRdfDescription(dc); |
184 |
3
1. 2. 3. |
if (p.size() > 0) addRdfDescription(p); |
185 |
3
1. 2. 3. |
if (basic.size() > 0) addRdfDescription(basic); |
186 |
2
1. 2. |
if (PdfXConformance == PdfWriter.PDFA1A || PdfXConformance == PdfWriter.PDFA1B) { |
187 | PdfA1Schema a1 = new PdfA1Schema(); | |
188 |
1
1. |
if (PdfXConformance == PdfWriter.PDFA1A) |
189 |
1
1. |
a1.addConformance("A"); |
190 | else | |
191 |
1
1. |
a1.addConformance("B"); |
192 |
1
1. |
addRdfDescription(a1); |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | /** | |
198 | * @param os | |
199 | * @param info | |
200 | * @throws IOException | |
201 | */ | |
202 | public XmpWriter(OutputStream os, Map info) throws IOException { | |
203 | this(os); | |
204 |
1
1. |
if (info != null) { |
205 | DublinCoreSchema dc = new DublinCoreSchema(); | |
206 | PdfSchema p = new PdfSchema(); | |
207 | XmpBasicSchema basic = new XmpBasicSchema(); | |
208 | String key; | |
209 | String value; | |
210 | for (Object o : info.entrySet()) { | |
211 | Map.Entry entry = (Map.Entry) o; | |
212 | key = (String) entry.getKey(); | |
213 | value = (String) entry.getValue(); | |
214 |
1
1. |
if (value == null) |
215 | continue; | |
216 |
1
1. |
if ("Title".equals(key)) { |
217 |
1
1. |
dc.addTitle(value); |
218 | } | |
219 |
1
1. |
if ("Author".equals(key)) { |
220 |
1
1. |
dc.addAuthor(value); |
221 | } | |
222 |
1
1. |
if ("Subject".equals(key)) { |
223 |
1
1. |
dc.addSubject(value); |
224 |
1
1. |
dc.addDescription(value); |
225 | } | |
226 |
1
1. |
if ("Keywords".equals(key)) { |
227 |
1
1. |
p.addKeywords(value); |
228 | } | |
229 |
1
1. |
if ("Creator".equals(key)) { |
230 |
1
1. |
basic.addCreatorTool(value); |
231 | } | |
232 |
1
1. |
if ("Producer".equals(key)) { |
233 |
1
1. |
p.addProducer(value); |
234 | } | |
235 |
1
1. |
if ("CreationDate".equals(key)) { |
236 |
1
1. |
basic.addCreateDate(PdfDate.getW3CDate(value)); |
237 | } | |
238 |
1
1. |
if ("ModDate".equals(key)) { |
239 |
1
1. |
basic.addModDate(PdfDate.getW3CDate(value)); |
240 | } | |
241 | } | |
242 |
3
1. 2. 3. |
if (dc.size() > 0) addRdfDescription(dc); |
243 |
3
1. 2. 3. |
if (p.size() > 0) addRdfDescription(p); |
244 |
3
1. 2. 3. |
if (basic.size() > 0) addRdfDescription(basic); |
245 | } | |
246 | } | |
247 | | |
248 | /** Sets the XMP to read-only */ | |
249 | public void setReadOnly() { | |
250 | end = 'r'; | |
251 | } | |
252 | | |
253 | /** | |
254 | * @param about The about to set. | |
255 | */ | |
256 | public void setAbout(String about) { | |
257 | this.about = about; | |
258 | } | |
259 | | |
260 | /** | |
261 | * Adds an rdf:Description. | |
262 | * @param xmlns | |
263 | * @param content | |
264 | * @throws IOException | |
265 | */ | |
266 | public void addRdfDescription(String xmlns, String content) throws IOException { | |
267 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("<rdf:Description rdf:about=\""); |
268 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(about); |
269 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("\" "); |
270 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(xmlns); |
271 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(">"); |
272 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(content); |
273 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("</rdf:Description>\n"); |
274 | } | |
275 | | |
276 | /** | |
277 | * Adds an rdf:Description. | |
278 | * @param s | |
279 | * @throws IOException | |
280 | */ | |
281 | public void addRdfDescription(XmpSchema s) throws IOException { | |
282 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("<rdf:Description rdf:about=\""); |
283 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(about); |
284 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("\" "); |
285 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(s.getXmlns()); |
286 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(">"); |
287 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(s.toString()); |
288 |
1
1. addRdfDescription : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("</rdf:Description>\n"); |
289 | } | |
290 | | |
291 | /** | |
292 | * Flushes and closes the XmpWriter. | |
293 | * @throws IOException | |
294 | */ | |
295 | public void close() throws IOException { | |
296 |
1
1. close : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("</rdf:RDF>"); |
297 |
1
1. close : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write("</x:xmpmeta>\n"); |
298 |
3
1. close : changed conditional boundary → NO_COVERAGE 2. close : Changed increment from 1 to -1 → NO_COVERAGE 3. close : negated conditional → NO_COVERAGE |
for (int i = 0; i < extraSpace; i++) { |
299 |
1
1. close : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(EXTRASPACE); |
300 | } | |
301 |
2
1. close : negated conditional → NO_COVERAGE 2. close : removed call to java/io/OutputStreamWriter::write → NO_COVERAGE |
writer.write(end == 'r' ? XPACKET_PI_END_R : XPACKET_PI_END_W); |
302 |
1
1. close : removed call to java/io/OutputStreamWriter::flush → NO_COVERAGE |
writer.flush(); |
303 |
1
1. close : removed call to java/io/OutputStreamWriter::close → NO_COVERAGE |
writer.close(); |
304 | } | |
305 | } | |
Mutations | ||
123 |
1.1 |
|
124 |
1.1 |
|
125 |
1.1 |
|
146 |
1.1 |
|
155 |
1.1 |
|
157 |
1.1 |
|
158 |
1.1 |
|
160 |
1.1 |
|
161 |
1.1 |
|
163 |
1.1 |
|
164 |
1.1 |
|
165 |
1.1 |
|
167 |
1.1 |
|
168 |
1.1 |
|
170 |
1.1 |
|
171 |
1.1 |
|
173 |
1.1 |
|
174 |
1.1 |
|
176 |
1.1 |
|
177 |
1.1 |
|
179 |
1.1 |
|
180 |
1.1 |
|
183 |
1.1 2.2 3.3 |
|
184 |
1.1 2.2 3.3 |
|
185 |
1.1 2.2 3.3 |
|
186 |
1.1 2.2 |
|
188 |
1.1 |
|
189 |
1.1 |
|
191 |
1.1 |
|
192 |
1.1 |
|
204 |
1.1 |
|
214 |
1.1 |
|
216 |
1.1 |
|
217 |
1.1 |
|
219 |
1.1 |
|
220 |
1.1 |
|
222 |
1.1 |
|
223 |
1.1 |
|
224 |
1.1 |
|
226 |
1.1 |
|
227 |
1.1 |
|
229 |
1.1 |
|
230 |
1.1 |
|
232 |
1.1 |
|
233 |
1.1 |
|
235 |
1.1 |
|
236 |
1.1 |
|
238 |
1.1 |
|
239 |
1.1 |
|
242 |
1.1 2.2 3.3 |
|
243 |
1.1 2.2 3.3 |
|
244 |
1.1 2.2 3.3 |
|
267 |
1.1 |
|
268 |
1.1 |
|
269 |
1.1 |
|
270 |
1.1 |
|
271 |
1.1 |
|
272 |
1.1 |
|
273 |
1.1 |
|
282 |
1.1 |
|
283 |
1.1 |
|
284 |
1.1 |
|
285 |
1.1 |
|
286 |
1.1 |
|
287 |
1.1 |
|
288 |
1.1 |
|
296 |
1.1 |
|
297 |
1.1 |
|
298 |
1.1 2.2 3.3 |
|
299 |
1.1 |
|
301 |
1.1 2.2 |
|
302 |
1.1 |
|
303 |
1.1 |