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.

PDFFilterList.java 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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.IOException;
  20. import java.io.OutputStream;
  21. import java.util.List;
  22. import java.util.Map;
  23. /**
  24. * This class represents a list of PDF filters to be applied when serializing
  25. * the output of a PDF object.
  26. */
  27. public class PDFFilterList {
  28. /** Key for the default filter */
  29. public static final String DEFAULT_FILTER = "default";
  30. /** Key for the filter used for normal content*/
  31. public static final String CONTENT_FILTER = "content";
  32. /** Key for the filter used for images */
  33. public static final String IMAGE_FILTER = "image";
  34. /** Key for the filter used for JPEG images */
  35. public static final String JPEG_FILTER = "jpeg";
  36. /** Key for the filter used for TIFF images */
  37. public static final String TIFF_FILTER = "tiff";
  38. /** Key for the filter used for fonts */
  39. public static final String FONT_FILTER = "font";
  40. /** Key for the filter used for metadata */
  41. public static final String METADATA_FILTER = "metadata";
  42. private List filters = new java.util.ArrayList();
  43. private boolean ignoreASCIIFilters = false;
  44. /**
  45. * Default constructor.
  46. * <p>
  47. * The flag for ignoring ASCII filters defaults to false.
  48. */
  49. public PDFFilterList() {
  50. //nop
  51. }
  52. /**
  53. * Use this descriptor if you want to have ASCII filters (such as ASCIIHex
  54. * and ASCII85) ignored, for example, when encryption is active.
  55. * @param ignoreASCIIFilters true if ASCII filters should be ignored
  56. */
  57. public PDFFilterList(boolean ignoreASCIIFilters) {
  58. this.ignoreASCIIFilters = ignoreASCIIFilters;
  59. }
  60. /**
  61. * Indicates whether the filter list is already initialized.
  62. * @return true if more there are filters present
  63. */
  64. public boolean isInitialized() {
  65. return this.filters.size() > 0;
  66. }
  67. /**
  68. * Add a filter for compression of the stream. Filters are
  69. * applied in the order they are added. This should always be a
  70. * new instance of the particular filter of choice. The applied
  71. * flag in the filter is marked true after it has been applied to the
  72. * data.
  73. * @param filter filter to add
  74. */
  75. public void addFilter(PDFFilter filter) {
  76. if (filter != null) {
  77. if (this.ignoreASCIIFilters && filter.isASCIIFilter()) {
  78. return; //ignore ASCII filter
  79. }
  80. filters.add(filter);
  81. }
  82. }
  83. /**
  84. * Add a filter for compression of the stream by name.
  85. * @param filterType name of the filter to add
  86. */
  87. public void addFilter(String filterType) {
  88. if (filterType == null) {
  89. return;
  90. }
  91. if (filterType.equals("flate")) {
  92. addFilter(new FlateFilter());
  93. } else if (filterType.equals("null")) {
  94. addFilter(new NullFilter());
  95. } else if (filterType.equals("ascii-85")) {
  96. if (this.ignoreASCIIFilters) {
  97. return; //ignore ASCII filter
  98. }
  99. addFilter(new ASCII85Filter());
  100. } else if (filterType.equals("ascii-hex")) {
  101. if (this.ignoreASCIIFilters) {
  102. return; //ignore ASCII filter
  103. }
  104. addFilter(new ASCIIHexFilter());
  105. } else if (filterType.equals("")) {
  106. return;
  107. } else {
  108. throw new IllegalArgumentException(
  109. "Unsupported filter type in stream-filter-list: " + filterType);
  110. }
  111. }
  112. /**
  113. * Checks the filter list for the filter and adds it in the correct
  114. * place if necessary.
  115. * @param pdfFilter the filter to check / add
  116. */
  117. public void ensureFilterInPlace(PDFFilter pdfFilter) {
  118. if (this.filters.size() == 0) {
  119. addFilter(pdfFilter);
  120. } else {
  121. if (!(this.filters.get(0).equals(pdfFilter))) {
  122. this.filters.add(0, pdfFilter);
  123. }
  124. }
  125. }
  126. /**
  127. * Adds the default filters to this stream.
  128. * @param filters Map of filters
  129. * @param type which filter list to modify
  130. */
  131. public void addDefaultFilters(Map filters, String type) {
  132. List filterset = null;
  133. if (filters != null) {
  134. filterset = (List)filters.get(type);
  135. if (filterset == null) {
  136. filterset = (List)filters.get(DEFAULT_FILTER);
  137. }
  138. }
  139. if (filterset == null || filterset.size() == 0) {
  140. if (METADATA_FILTER.equals(type)) {
  141. //XMP metadata should not be embedded in clear-text
  142. addFilter(new NullFilter());
  143. } else if (JPEG_FILTER.equals(type)) {
  144. //JPEG is already well compressed
  145. addFilter(new NullFilter());
  146. } else if (TIFF_FILTER.equals(type)) {
  147. //CCITT-encoded images are already well compressed
  148. addFilter(new NullFilter());
  149. } else {
  150. // built-in default to flate
  151. addFilter(new FlateFilter());
  152. }
  153. } else {
  154. for (int i = 0; i < filterset.size(); i++) {
  155. String v = (String)filterset.get(i);
  156. addFilter(v);
  157. }
  158. }
  159. }
  160. /**
  161. * Apply the filters to the data
  162. * in the order given and return the /Filter and /DecodeParms
  163. * entries for the stream dictionary. If the filters have already
  164. * been applied to the data (either externally, or internally)
  165. * then the dictionary entries are built and returned.
  166. * @return a String representing the filter list
  167. */
  168. protected String buildFilterDictEntries() {
  169. if (filters != null && filters.size() > 0) {
  170. List names = new java.util.ArrayList();
  171. List parms = new java.util.ArrayList();
  172. // run the filters
  173. int nonNullParams = 0;
  174. for (int count = 0; count < filters.size(); count++) {
  175. PDFFilter filter = (PDFFilter)filters.get(count);
  176. // place the names in our local vector in reverse order
  177. if (filter.getName().length() > 0) {
  178. names.add(0, filter.getName());
  179. if (filter.getDecodeParms() != null) {
  180. parms.add(0, filter.getDecodeParms());
  181. nonNullParams++;
  182. } else {
  183. parms.add(0, null);
  184. }
  185. }
  186. }
  187. // now build up the filter entries for the dictionary
  188. return buildFilterEntries(names)
  189. + (nonNullParams > 0 ? buildDecodeParms(parms) : "");
  190. }
  191. return "";
  192. }
  193. private String buildFilterEntries(List names) {
  194. int filterCount = 0;
  195. StringBuffer sb = new StringBuffer(64);
  196. for (int i = 0; i < names.size(); i++) {
  197. final String name = (String)names.get(i);
  198. if (name.length() > 0) {
  199. filterCount++;
  200. sb.append(name);
  201. sb.append(" ");
  202. }
  203. }
  204. if (filterCount > 0) {
  205. if (filterCount > 1) {
  206. return "/Filter [ " + sb.toString() + "]";
  207. } else {
  208. return "/Filter " + sb.toString();
  209. }
  210. } else {
  211. return "";
  212. }
  213. }
  214. private String buildDecodeParms(List parms) {
  215. StringBuffer sb = new StringBuffer();
  216. boolean needParmsEntry = false;
  217. sb.append("\n/DecodeParms ");
  218. if (parms.size() > 1) {
  219. sb.append("[ ");
  220. }
  221. for (int count = 0; count < parms.size(); count++) {
  222. String s = (String)parms.get(count);
  223. if (s != null) {
  224. sb.append(s);
  225. needParmsEntry = true;
  226. } else {
  227. sb.append("null");
  228. }
  229. sb.append(" ");
  230. }
  231. if (parms.size() > 1) {
  232. sb.append("]");
  233. }
  234. if (needParmsEntry) {
  235. return sb.toString();
  236. } else {
  237. return "";
  238. }
  239. }
  240. /**
  241. * Applies all registered filters as necessary. The method returns an
  242. * OutputStream which will receive the filtered contents.
  243. * @param stream raw data output stream
  244. * @return OutputStream filtered output stream
  245. * @throws IOException In case of an I/O problem
  246. */
  247. public OutputStream applyFilters(OutputStream stream) throws IOException {
  248. OutputStream out = stream;
  249. if (filters != null) {
  250. for (int count = filters.size() - 1; count >= 0; count--) {
  251. PDFFilter filter = (PDFFilter)filters.get(count);
  252. out = filter.applyFilter(out);
  253. }
  254. }
  255. return out;
  256. }
  257. }