001: /*
002: * $Id: XmpWriter.java 2862 2007-07-02 09:15:02Z blowagie $
003: * $Name$
004: *
005: * Copyright 2005 by Bruno Lowagie.
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */
050:
051: package com.lowagie.text.xml.xmp;
052:
053: import com.lowagie.text.pdf.PdfWriter;
054: import java.io.IOException;
055: import java.io.OutputStream;
056: import java.io.OutputStreamWriter;
057: import java.util.Iterator;
058: import java.util.Map;
059:
060: import com.lowagie.text.pdf.PdfDate;
061: import com.lowagie.text.pdf.PdfDictionary;
062: import com.lowagie.text.pdf.PdfName;
063: import com.lowagie.text.pdf.PdfObject;
064: import com.lowagie.text.pdf.PdfString;
065:
066: /**
067: * With this class you can create an Xmp Stream that can be used for adding
068: * Metadata to a PDF Dictionary. Remark that this class doesn't cover the
069: * complete XMP specification.
070: */
071: public class XmpWriter {
072:
073: /** A possible charset for the XMP. */
074: public static final String UTF8 = "UTF-8";
075: /** A possible charset for the XMP. */
076: public static final String UTF16 = "UTF-16";
077: /** A possible charset for the XMP. */
078: public static final String UTF16BE = "UTF-16BE";
079: /** A possible charset for the XMP. */
080: public static final String UTF16LE = "UTF-16LE";
081:
082: /** String used to fill the extra space. */
083: public static final String EXTRASPACE = " \n";
084:
085: /** You can add some extra space in the XMP packet; 1 unit in this variable represents 100 spaces and a newline. */
086: protected int extraSpace;
087:
088: /** The writer to which you can write bytes for the XMP stream. */
089: protected OutputStreamWriter writer;
090:
091: /** The about string that goes into the rdf:Description tags. */
092: protected String about;
093:
094: /** The end attribute. */
095: protected char end = 'w';
096:
097: /**
098: * Creates an XmpWriter.
099: * @param os
100: * @param utfEncoding
101: * @param extraSpace
102: * @throws IOException
103: */
104: public XmpWriter(OutputStream os, String utfEncoding, int extraSpace)
105: throws IOException {
106: this .extraSpace = extraSpace;
107: writer = new OutputStreamWriter(os, utfEncoding);
108: writer
109: .write("<?xpacket begin='\uFEFF' id='W5M0MpCehiHzreSzNTczkc9d' ?>\n");
110: writer.write("<x:xmpmeta xmlns:x='adobe:ns:meta/'>\n");
111: writer
112: .write("<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n");
113: about = "";
114: }
115:
116: /**
117: * Creates an XmpWriter.
118: * @param os
119: * @throws IOException
120: */
121: public XmpWriter(OutputStream os) throws IOException {
122: this (os, UTF8, 20);
123: }
124:
125: /** Sets the XMP to read-only */
126: public void setReadOnly() {
127: end = 'r';
128: }
129:
130: /**
131: * @param about The about to set.
132: */
133: public void setAbout(String about) {
134: this .about = about;
135: }
136:
137: /**
138: * Adds an rdf:Description.
139: * @param xmlns
140: * @param content
141: * @throws IOException
142: */
143: public void addRdfDescription(String xmlns, String content)
144: throws IOException {
145: writer.write("<rdf:Description rdf:about='");
146: writer.write(about);
147: writer.write("' ");
148: writer.write(xmlns);
149: writer.write(">");
150: writer.write(content);
151: writer.write("</rdf:Description>\n");
152: }
153:
154: /**
155: * Adds an rdf:Description.
156: * @param s
157: * @throws IOException
158: */
159: public void addRdfDescription(XmpSchema s) throws IOException {
160: writer.write("<rdf:Description rdf:about='");
161: writer.write(about);
162: writer.write("' ");
163: writer.write(s.getXmlns());
164: writer.write(">");
165: writer.write(s.toString());
166: writer.write("</rdf:Description>\n");
167: }
168:
169: /**
170: * Flushes and closes the XmpWriter.
171: * @throws IOException
172: */
173: public void close() throws IOException {
174: writer.write("</rdf:RDF>");
175: writer.write("</x:xmpmeta>\n");
176: for (int i = 0; i < extraSpace; i++) {
177: writer.write(EXTRASPACE);
178: }
179: writer.write("<?xpacket ends='" + end + "' ?>");
180: writer.flush();
181: writer.close();
182: }
183:
184: /**
185: * @param os
186: * @param info
187: * @throws IOException
188: */
189: public XmpWriter(OutputStream os, PdfDictionary info,
190: int PdfXConformance) throws IOException {
191: this (os);
192: if (info != null) {
193: DublinCoreSchema dc = new DublinCoreSchema();
194: PdfSchema p = new PdfSchema();
195: XmpBasicSchema basic = new XmpBasicSchema();
196: PdfName key;
197: PdfObject obj;
198: for (Iterator it = info.getKeys().iterator(); it.hasNext();) {
199: key = (PdfName) it.next();
200: obj = info.get(key);
201: if (obj == null)
202: continue;
203: if (PdfName.TITLE.equals(key)) {
204: dc.addTitle(((PdfString) obj).toUnicodeString());
205: }
206: if (PdfName.AUTHOR.equals(key)) {
207: dc.addAuthor(((PdfString) obj).toUnicodeString());
208: }
209: if (PdfName.SUBJECT.equals(key)) {
210: dc.addSubject(((PdfString) obj).toUnicodeString());
211: dc.addDescription(((PdfString) obj)
212: .toUnicodeString());
213: }
214: if (PdfName.KEYWORDS.equals(key)) {
215: p.addKeywords(((PdfString) obj).toUnicodeString());
216: }
217: if (PdfName.CREATOR.equals(key)) {
218: basic.addCreatorTool(((PdfString) obj)
219: .toUnicodeString());
220: }
221: if (PdfName.PRODUCER.equals(key)) {
222: p.addProducer(((PdfString) obj).toUnicodeString());
223: }
224: if (PdfName.CREATIONDATE.equals(key)) {
225: basic.addCreateDate(((PdfDate) obj).getW3CDate());
226: }
227: if (PdfName.MODDATE.equals(key)) {
228: basic.addModDate(((PdfDate) obj).getW3CDate());
229: }
230: }
231: if (dc.size() > 0)
232: addRdfDescription(dc);
233: if (p.size() > 0)
234: addRdfDescription(p);
235: if (basic.size() > 0)
236: addRdfDescription(basic);
237: if (PdfXConformance == PdfWriter.PDFA1A
238: || PdfXConformance == PdfWriter.PDFA1B) {
239: PdfA1Schema a1 = new PdfA1Schema();
240: if (PdfXConformance == PdfWriter.PDFA1A)
241: a1.addConformance("A");
242: else
243: a1.addConformance("B");
244: addRdfDescription(a1);
245: }
246: }
247: }
248:
249: /**
250: * @param os
251: * @param info
252: * @throws IOException
253: */
254: public XmpWriter(OutputStream os, Map info) throws IOException {
255: this (os);
256: if (info != null) {
257: DublinCoreSchema dc = new DublinCoreSchema();
258: PdfSchema p = new PdfSchema();
259: XmpBasicSchema basic = new XmpBasicSchema();
260: String key;
261: String value;
262: for (Iterator it = info.entrySet().iterator(); it.hasNext();) {
263: Map.Entry entry = (Map.Entry) it.next();
264: key = (String) entry.getKey();
265: value = (String) entry.getValue();
266: if (value == null)
267: continue;
268: if ("Title".equals(key)) {
269: dc.addTitle(value);
270: }
271: if ("Author".equals(key)) {
272: dc.addAuthor(value);
273: }
274: if ("Subject".equals(key)) {
275: dc.addSubject(value);
276: dc.addDescription(value);
277: }
278: if ("Keywords".equals(key)) {
279: p.addKeywords(value);
280: }
281: if ("Creator".equals(key)) {
282: basic.addCreatorTool(value);
283: }
284: if ("Producer".equals(key)) {
285: p.addProducer(value);
286: }
287: if ("CreationDate".equals(key)) {
288: basic.addCreateDate(PdfDate.getW3CDate(value));
289: }
290: if ("ModDate".equals(key)) {
291: basic.addModDate(PdfDate.getW3CDate(value));
292: }
293: }
294: if (dc.size() > 0)
295: addRdfDescription(dc);
296: if (p.size() > 0)
297: addRdfDescription(p);
298: if (basic.size() > 0)
299: addRdfDescription(basic);
300: }
301: }
302: }
|