You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PDFInfo.java 9.2KB

Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. /* $Id$ */
  18. package org.apache.fop.pdf;
  19. import java.io.ByteArrayOutputStream;
  20. import java.io.IOException;
  21. import java.util.Date;
  22. import java.util.LinkedHashMap;
  23. import java.util.Map;
  24. import java.util.TimeZone;
  25. import org.apache.xmlgraphics.util.DateFormatUtil;
  26. /**
  27. * class representing an /Info object
  28. */
  29. public class PDFInfo extends PDFObject {
  30. /** The standard keys in the Document Information Dictionary */
  31. public static enum StandardKey {
  32. TITLE("Title"),
  33. AUTHOR("Author"),
  34. SUBJECT("Subject"),
  35. KEYWORDS("Keywords"),
  36. CREATOR("Creator"),
  37. PRODUCER("Producer"),
  38. CREATION_DATE("CreationDate"),
  39. MOD_DATE("ModDate"),
  40. TRAPPED("Trapped");
  41. private final String name;
  42. private StandardKey(String name) {
  43. this.name = name;
  44. }
  45. /**
  46. * Returns the standard key that corresponds to the given name.
  47. *
  48. * @param name key name
  49. * @return the key whose name exactly matches the given name (case-sensitive)
  50. */
  51. public static StandardKey get(String name) {
  52. for (StandardKey key : values()) {
  53. if (key.name.equals(name)) {
  54. return key;
  55. }
  56. }
  57. return null;
  58. }
  59. /**
  60. * Returns the name of this key.
  61. *
  62. * @return the name as it would appear in the Info dictionary without the leading slash
  63. */
  64. public String getName() {
  65. return name;
  66. }
  67. }
  68. /**
  69. * the application producing the PDF
  70. */
  71. private String producer;
  72. private String title;
  73. private String author;
  74. private String subject;
  75. private String keywords;
  76. private Date creationDate;
  77. private Date modDate;
  78. private Map<PDFName, String> customProperties;
  79. /**
  80. * the name of the application that created the
  81. * original document before converting to PDF
  82. */
  83. private String creator;
  84. /** @return the producer of the document or null if not set */
  85. public String getProducer() {
  86. return this.producer;
  87. }
  88. /**
  89. * set the producer string
  90. *
  91. * @param producer the producer string
  92. */
  93. public void setProducer(String producer) {
  94. this.producer = producer;
  95. }
  96. /** @return the creator of the document or null if not set */
  97. public String getCreator() {
  98. return this.creator;
  99. }
  100. /**
  101. * set the creator string
  102. *
  103. * @param creator the document creator
  104. */
  105. public void setCreator(String creator) {
  106. this.creator = creator;
  107. }
  108. /** @return the title string */
  109. public String getTitle() {
  110. return this.title;
  111. }
  112. /**
  113. * set the title string
  114. *
  115. * @param t the document title
  116. */
  117. public void setTitle(String t) {
  118. this.title = t;
  119. }
  120. /** @return the author of the document or null if not set */
  121. public String getAuthor() {
  122. return this.author;
  123. }
  124. /**
  125. * set the author string
  126. *
  127. * @param a the document author
  128. */
  129. public void setAuthor(String a) {
  130. this.author = a;
  131. }
  132. /** @return the subject of the document or null if not set */
  133. public String getSubject() {
  134. return this.subject;
  135. }
  136. /**
  137. * set the subject string
  138. *
  139. * @param s the document subject
  140. */
  141. public void setSubject(String s) {
  142. this.subject = s;
  143. }
  144. /** @return the keywords for the document or null if not set */
  145. public String getKeywords() {
  146. return this.keywords;
  147. }
  148. /**
  149. * set the keywords string
  150. *
  151. * @param k the keywords for this document
  152. */
  153. public void setKeywords(String k) {
  154. this.keywords = k;
  155. }
  156. /**
  157. * @return last set creation date
  158. */
  159. public Date getCreationDate() {
  160. return creationDate;
  161. }
  162. /**
  163. * @param date Date to store in the PDF as creation date. Use null to force current system date.
  164. */
  165. public void setCreationDate(Date date) {
  166. creationDate = date;
  167. }
  168. /** @return last modification date
  169. */
  170. public Date getModDate() {
  171. return this.modDate;
  172. }
  173. /**
  174. * Sets the date of the last modification.
  175. * @param date the last modification date or null if there are no modifications
  176. */
  177. public void setModDate(Date date) {
  178. this.modDate = date;
  179. }
  180. /**
  181. * {@inheritDoc}
  182. */
  183. public byte[] toPDF() {
  184. PDFProfile profile = getDocumentSafely().getProfile();
  185. ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
  186. try {
  187. bout.write(encode("<<\n"));
  188. if (title != null && title.length() > 0) {
  189. bout.write(encode("/Title "));
  190. bout.write(encodeText(this.title));
  191. bout.write(encode("\n"));
  192. } else {
  193. profile.verifyTitleAbsent();
  194. }
  195. if (author != null) {
  196. bout.write(encode("/Author "));
  197. bout.write(encodeText(this.author));
  198. bout.write(encode("\n"));
  199. }
  200. if (subject != null) {
  201. bout.write(encode("/Subject "));
  202. bout.write(encodeText(this.subject));
  203. bout.write(encode("\n"));
  204. }
  205. if (keywords != null) {
  206. bout.write(encode("/Keywords "));
  207. bout.write(encodeText(this.keywords));
  208. bout.write(encode("\n"));
  209. }
  210. if (creator != null) {
  211. bout.write(encode("/Creator "));
  212. bout.write(encodeText(this.creator));
  213. bout.write(encode("\n"));
  214. }
  215. bout.write(encode("/Producer "));
  216. bout.write(encodeText(this.producer));
  217. bout.write(encode("\n"));
  218. // creation date in form (D:YYYYMMDDHHmmSSOHH'mm')
  219. if (creationDate == null) {
  220. creationDate = new Date();
  221. }
  222. bout.write(encode("/CreationDate "));
  223. bout.write(encodeString(formatDateTime(creationDate)));
  224. bout.write(encode("\n"));
  225. if (profile.isModDateRequired() && this.modDate == null) {
  226. this.modDate = this.creationDate;
  227. }
  228. if (this.modDate != null) {
  229. bout.write(encode("/ModDate "));
  230. bout.write(encodeString(formatDateTime(modDate)));
  231. bout.write(encode("\n"));
  232. }
  233. if (profile.isPDFXActive()) {
  234. bout.write(encode("/GTS_PDFXVersion "));
  235. bout.write(encodeString(profile.getPDFXMode().getName()));
  236. bout.write(encode("\n"));
  237. }
  238. if (profile.isTrappedEntryRequired()) {
  239. bout.write(encode("/Trapped /False\n"));
  240. }
  241. if (customProperties != null) {
  242. for (Map.Entry<PDFName, String> entry : customProperties.entrySet()) {
  243. entry.getKey().output(bout);
  244. bout.write(encode(" "));
  245. bout.write(encodeText(entry.getValue()));
  246. bout.write(encode("\n"));
  247. }
  248. }
  249. bout.write(encode(">>"));
  250. } catch (IOException ioe) {
  251. log.error("Ignored I/O exception", ioe);
  252. }
  253. return bout.toByteArray();
  254. }
  255. /**
  256. * Formats a date/time according to the PDF specification (D:YYYYMMDDHHmmSSOHH'mm').
  257. * @param time date/time value to format
  258. * @param tz the time zone
  259. * @return the requested String representation
  260. */
  261. protected static String formatDateTime(final Date time, TimeZone tz) {
  262. return DateFormatUtil.formatPDFDate(time, tz);
  263. }
  264. /**
  265. * Formats a date/time according to the PDF specification. (D:YYYYMMDDHHmmSSOHH'mm').
  266. * @param time date/time value to format
  267. * @return the requested String representation
  268. */
  269. protected static String formatDateTime(final Date time) {
  270. return formatDateTime(time, TimeZone.getDefault());
  271. }
  272. /**
  273. * Adds a custom property to this Info dictionary.
  274. */
  275. public void put(String key, String value) {
  276. StandardKey standardKey = StandardKey.get(key);
  277. if (standardKey != null) {
  278. throw new IllegalArgumentException(key + " is a reserved keyword");
  279. }
  280. if (customProperties == null) {
  281. customProperties = new LinkedHashMap<PDFName, String>();
  282. }
  283. customProperties.put(new PDFName(key), value);
  284. }
  285. }