KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > pdf > PDFMetadata


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id$ */
19  
20 package org.apache.fop.pdf;
21
22 import java.io.IOException JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.util.Date JavaDoc;
25
26 import javax.xml.transform.TransformerConfigurationException JavaDoc;
27
28 import org.apache.xmlgraphics.xmp.Metadata;
29 import org.apache.xmlgraphics.xmp.XMPSerializer;
30 import org.apache.xmlgraphics.xmp.schemas.DublinCoreAdapter;
31 import org.apache.xmlgraphics.xmp.schemas.DublinCoreSchema;
32 import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
33 import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
34 import org.apache.xmlgraphics.xmp.schemas.pdf.AdobePDFAdapter;
35 import org.apache.xmlgraphics.xmp.schemas.pdf.AdobePDFSchema;
36 import org.apache.xmlgraphics.xmp.schemas.pdf.PDFAAdapter;
37 import org.apache.xmlgraphics.xmp.schemas.pdf.PDFAOldXMPSchema;
38 import org.apache.xmlgraphics.xmp.schemas.pdf.PDFAXMPSchema;
39
40 import org.xml.sax.SAXException JavaDoc;
41
42 /**
43  * Special PDFStream for Metadata.
44  * @since PDF 1.4
45  */

46 public class PDFMetadata extends PDFStream {
47     
48     private Metadata xmpMetadata;
49     private boolean readOnly = true;
50
51     /** @see org.apache.fop.pdf.PDFObject#PDFObject() */
52     public PDFMetadata(Metadata xmp, boolean readOnly) {
53         super();
54         if (xmp == null) {
55             throw new NullPointerException JavaDoc(
56                     "The parameter for the XMP Document must not be null");
57         }
58         this.xmpMetadata = xmp;
59         this.readOnly = readOnly;
60     }
61
62     /** @see org.apache.fop.pdf.AbstractPDFStream#setupFilterList() */
63     protected void setupFilterList() {
64         if (!getFilterList().isInitialized()) {
65             getFilterList().addDefaultFilters(
66                 getDocumentSafely().getFilterMap(),
67                 PDFFilterList.METADATA_FILTER);
68         }
69         super.setupFilterList();
70     }
71
72     /**
73      * @return the XMP metadata
74      */

75     public Metadata getMetadata() {
76         return this.xmpMetadata;
77     }
78     
79     /**
80      * overload the base object method so we don't have to copy
81      * byte arrays around so much
82      * @see org.apache.fop.pdf.PDFObject#output(OutputStream)
83      */

84     protected int output(java.io.OutputStream JavaDoc stream)
85                 throws java.io.IOException JavaDoc {
86         int length = super.output(stream);
87         this.xmpMetadata = null; //Release DOM when it's not used anymore
88
return length;
89     }
90     
91     /** @see org.apache.fop.pdf.AbstractPDFStream#outputRawStreamData(java.io.OutputStream) */
92     protected void outputRawStreamData(OutputStream JavaDoc out) throws IOException JavaDoc {
93         try {
94             XMPSerializer.writeXMPPacket(xmpMetadata, out, this.readOnly);
95         } catch (TransformerConfigurationException JavaDoc tce) {
96             throw new IOException JavaDoc("Error setting up Transformer for XMP stream serialization: "
97                     + tce.getMessage());
98         } catch (SAXException JavaDoc saxe) {
99             throw new IOException JavaDoc("Error while serializing XMP stream: "
100                     + saxe.getMessage());
101         }
102     }
103     
104     /** @see org.apache.fop.pdf.AbstractPDFStream#buildStreamDict(String) */
105     protected String JavaDoc buildStreamDict(String JavaDoc lengthEntry) {
106         final String JavaDoc filterEntry = getFilterList().buildFilterDictEntries();
107         if (getDocumentSafely().getProfile().getPDFAMode().isPDFA1LevelB()
108                 && filterEntry != null && filterEntry.length() > 0) {
109             throw new PDFConformanceException(
110                     "The Filter key is prohibited when PDF/A-1 is active");
111         }
112         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc(128);
113         sb.append(getObjectID());
114         sb.append("<< ");
115         sb.append("/Type /Metadata");
116         sb.append("\n/Subtype /XML");
117         sb.append("\n/Length " + lengthEntry);
118         sb.append("\n" + filterEntry);
119         sb.append("\n>>\n");
120         return sb.toString();
121     }
122
123     /**
124      * Creates an XMP document based on the settings on the PDF Document.
125      * @param pdfDoc the PDF Document
126      * @return the requested XMP metadata
127      */

128     public static Metadata createXMPFromUserAgent(PDFDocument pdfDoc) {
129         Metadata meta = new Metadata();
130         
131         PDFInfo info = pdfDoc.getInfo();
132
133         //Set creation date if not available, yet
134
if (info.getCreationDate() == null) {
135             Date JavaDoc d = new Date JavaDoc();
136             info.setCreationDate(d);
137         }
138         
139         //Important: Acrobat's preflight check for PDF/A-1b wants the creation date in the Info
140
//object and in the XMP metadata to have the same timezone or else it shows a validation
141
//error even if the times are essentially equal.
142

143         //Dublin Core
144
DublinCoreAdapter dc = DublinCoreSchema.getAdapter(meta);
145         if (info.getAuthor() != null) {
146             dc.addCreator(info.getAuthor());
147         }
148         if (info.getTitle() != null) {
149             dc.setTitle(info.getTitle());
150         }
151         if (info.getSubject() != null) {
152             dc.addSubject(info.getSubject());
153         }
154         dc.addDate(info.getCreationDate());
155
156         //PDF/A identification
157
PDFAMode pdfaMode = pdfDoc.getProfile().getPDFAMode();
158         if (pdfaMode.isPDFA1LevelB()) {
159             PDFAAdapter pdfa = PDFAXMPSchema.getAdapter(meta);
160             //Create the identification a second time with the old namespace to keep
161
//Adobe Acrobat happy
162
PDFAAdapter pdfaOld = PDFAOldXMPSchema.getAdapter(meta);
163             pdfa.setPart(1);
164             pdfaOld.setPart(1);
165             if (pdfaMode == PDFAMode.PDFA_1A) {
166                 pdfa.setConformance("A"); //PDF/A-1a
167
pdfaOld.setConformance("A"); //PDF/A-1a
168
} else {
169                 pdfa.setConformance("B"); //PDF/A-1b
170
pdfaOld.setConformance("B"); //PDF/A-1b
171
}
172         }
173         
174         //XMP Basic Schema
175
XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(meta);
176         xmpBasic.setCreateDate(info.getCreationDate());
177         PDFProfile profile = pdfDoc.getProfile();
178         if (profile.isModDateRequired()) {
179             xmpBasic.setModifyDate(info.getCreationDate());
180         }
181         if (info.getCreator() != null) {
182             xmpBasic.setCreatorTool(info.getCreator());
183         }
184
185         AdobePDFAdapter adobePDF = AdobePDFSchema.getAdapter(meta);
186         if (info.getKeywords() != null) {
187             adobePDF.setKeywords(info.getKeywords());
188         }
189         if (info.getProducer() != null) {
190             adobePDF.setProducer(info.getProducer());
191         }
192         adobePDF.setPDFVersion(pdfDoc.getPDFVersionString());
193         
194         
195         return meta;
196     }
197
198     /**
199      * Updates the values in the Info object from the XMP metadata according to the rules defined
200      * in PDF/A-1 (ISO 19005-1:2005)
201      * @param meta the metadata
202      * @param info the Info object
203      */

204     public static void updateInfoFromMetadata(Metadata meta, PDFInfo info) {
205         DublinCoreAdapter dc = DublinCoreSchema.getAdapter(meta);
206         info.setTitle(dc.getTitle());
207         String JavaDoc[] creators = dc.getCreators();
208         if (creators != null && creators.length > 0) {
209             info.setAuthor(creators[0]);
210         } else {
211             info.setAuthor(null);
212         }
213         String JavaDoc[] subjects = dc.getSubjects();
214         //PDF/A-1 defines dc:subject as "Text" but XMP defines it as "bag Text".
215
//We're simply doing the inverse from createXMPFromUserAgent() above.
216
if (subjects != null && subjects.length > 0) {
217             info.setSubject(subjects[0]);
218         } else {
219             info.setSubject(null);
220         }
221         
222         AdobePDFAdapter pdf = AdobePDFSchema.getAdapter(meta);
223         info.setKeywords(pdf.getKeywords());
224         info.setProducer(pdf.getProducer());
225         
226         XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(meta);
227         info.setCreator(xmpBasic.getCreatorTool());
228         Date JavaDoc d;
229         d = xmpBasic.getCreateDate();
230         xmpBasic.setCreateDate(d); //To make Adobe Acrobat happy (bug filed with Adobe)
231
//Adobe Acrobat doesn't like it when the xmp:CreateDate has a different timezone
232
//than Info/CreationDate
233
info.setCreationDate(d);
234         d = xmpBasic.getModifyDate();
235         if (d != null) { //ModifyDate is only required for PDF/X
236
xmpBasic.setModifyDate(d);
237             info.setModDate(d);
238         }
239     }
240 }
241
Popular Tags