選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

PDFFilterList.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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.Collections;
  22. import java.util.List;
  23. import java.util.Map;
  24. /**
  25. * This class represents a list of PDF filters to be applied when serializing
  26. * the output of a PDF object.
  27. */
  28. public class PDFFilterList {
  29. /** Key for the default filter */
  30. public static final String DEFAULT_FILTER = "default";
  31. /** Key for the filter used for normal content*/
  32. public static final String CONTENT_FILTER = "content";
  33. /** Key for the filter used for precompressed content */
  34. public static final String PRECOMPRESSED_FILTER = "precompressed";
  35. /** Key for the filter used for images */
  36. public static final String IMAGE_FILTER = "image";
  37. /** Key for the filter used for JPEG images */
  38. public static final String JPEG_FILTER = "jpeg";
  39. /** Key for the filter used for TIFF images */
  40. public static final String TIFF_FILTER = "tiff";
  41. /** Key for the filter used for fonts */
  42. public static final String FONT_FILTER = "font";
  43. /** Key for the filter used for metadata */
  44. public static final String METADATA_FILTER = "metadata";
  45. private List<PDFFilter> filters = new java.util.ArrayList<PDFFilter>();
  46. private boolean ignoreASCIIFilters;
  47. private boolean disableAllFilters;
  48. /**
  49. * Default constructor.
  50. * <p>
  51. * The flag for ignoring ASCII filters defaults to false.
  52. */
  53. public PDFFilterList() {
  54. //nop
  55. }
  56. /**
  57. * Use this descriptor if you want to have ASCII filters (such as ASCIIHex
  58. * and ASCII85) ignored, for example, when encryption is active.
  59. * @param ignoreASCIIFilters true if ASCII filters should be ignored
  60. */
  61. public PDFFilterList(boolean ignoreASCIIFilters) {
  62. this.ignoreASCIIFilters = ignoreASCIIFilters;
  63. }
  64. /**
  65. * Used to disable all filters.
  66. * @param value true if all filters shall be disabled
  67. */
  68. public void setDisableAllFilters(boolean value) {
  69. this.disableAllFilters = value;
  70. }
  71. /**
  72. * Returns true if all filters are disabled.
  73. * @return true if all filters are disabled
  74. */
  75. public boolean isDisableAllFilters() {
  76. return this.disableAllFilters;
  77. }
  78. /**
  79. * Indicates whether the filter list is already initialized.
  80. * @return true if more there are filters present
  81. */
  82. public boolean isInitialized() {
  83. return this.filters.size() > 0;
  84. }
  85. /**
  86. * Add a filter for compression of the stream. Filters are
  87. * applied in the order they are added. This should always be a
  88. * new instance of the particular filter of choice. The applied
  89. * flag in the filter is marked true after it has been applied to the
  90. * data.
  91. * @param filter filter to add
  92. */
  93. public void addFilter(PDFFilter filter) {
  94. if (filter != null) {
  95. if (this.ignoreASCIIFilters && filter.isASCIIFilter()) {
  96. return; //ignore ASCII filter
  97. }
  98. filters.add(filter);
  99. }
  100. }
  101. /**
  102. * Add a filter for compression of the stream by name.
  103. * @param filterType name of the filter to add
  104. */
  105. public void addFilter(String filterType) {
  106. if (filterType == null) {
  107. return;
  108. }
  109. if (filterType.equals("flate")) {
  110. addFilter(new FlateFilter());
  111. } else if (filterType.equals("null")) {
  112. addFilter(new NullFilter());
  113. } else if (filterType.equals("ascii-85")) {
  114. if (this.ignoreASCIIFilters) {
  115. return; //ignore ASCII filter
  116. }
  117. addFilter(new ASCII85Filter());
  118. } else if (filterType.equals("ascii-hex")) {
  119. if (this.ignoreASCIIFilters) {
  120. return; //ignore ASCII filter
  121. }
  122. addFilter(new ASCIIHexFilter());
  123. } else if (filterType.equals("")) {
  124. return;
  125. } else {
  126. throw new IllegalArgumentException(
  127. "Unsupported filter type in stream-filter-list: " + filterType);
  128. }
  129. }
  130. /**
  131. * Checks the filter list for the filter and adds it in the correct
  132. * place if necessary.
  133. * @param pdfFilter the filter to check / add
  134. */
  135. public void ensureFilterInPlace(PDFFilter pdfFilter) {
  136. if (this.filters.size() == 0) {
  137. addFilter(pdfFilter);
  138. } else {
  139. if (!(this.filters.get(0).equals(pdfFilter))) {
  140. this.filters.add(0, pdfFilter);
  141. }
  142. }
  143. }
  144. /**
  145. * Adds the default filters to this stream.
  146. * @param filters Map of filters
  147. * @param type which filter list to modify
  148. */
  149. public void addDefaultFilters(Map filters, String type) {
  150. if (METADATA_FILTER.equals(type)) {
  151. //XMP metadata should not be embedded in clear-text
  152. addFilter(new NullFilter());
  153. return;
  154. }
  155. List filterset = null;
  156. if (filters != null) {
  157. filterset = (List)filters.get(type);
  158. if (filterset == null) {
  159. filterset = (List)filters.get(DEFAULT_FILTER);
  160. }
  161. }
  162. if (filterset == null || filterset.size() == 0) {
  163. if (JPEG_FILTER.equals(type)) {
  164. //JPEG is already well compressed
  165. addFilter(new NullFilter());
  166. } else if (TIFF_FILTER.equals(type)) {
  167. //CCITT-encoded images are already well compressed
  168. addFilter(new NullFilter());
  169. } else if (PRECOMPRESSED_FILTER.equals(type)) {
  170. //precompressed content doesn't need further compression
  171. addFilter(new NullFilter());
  172. } else {
  173. // built-in default to flate
  174. addFilter(new FlateFilter());
  175. }
  176. } else {
  177. for (Object aFilterset : filterset) {
  178. String v = (String) aFilterset;
  179. addFilter(v);
  180. }
  181. }
  182. }
  183. List<PDFFilter> getFilters() {
  184. return Collections.unmodifiableList(filters);
  185. }
  186. /**
  187. * Apply the filters to the data
  188. * in the order given and return the /Filter and /DecodeParms
  189. * entries for the stream dictionary. If the filters have already
  190. * been applied to the data (either externally, or internally)
  191. * then the dictionary entries are built and returned.
  192. * @return a String representing the filter list
  193. */
  194. protected String buildFilterDictEntries() {
  195. if (filters.size() > 0) {
  196. List names = new java.util.ArrayList();
  197. List parms = new java.util.ArrayList();
  198. int nonNullParams = populateNamesAndParms(names, parms);
  199. // now build up the filter entries for the dictionary
  200. return buildFilterEntries(names)
  201. + (nonNullParams > 0 ? buildDecodeParms(parms) : "");
  202. }
  203. return "";
  204. }
  205. /**
  206. * Apply the filters to the data
  207. * in the order given and add the /Filter and /DecodeParms
  208. * entries to the stream dictionary. If the filters have already
  209. * been applied to the data (either externally, or internally)
  210. * then the dictionary entries added.
  211. * @param dict the PDFDictionary to set the entries on
  212. */
  213. protected void putFilterDictEntries(PDFDictionary dict) {
  214. if (filters.size() > 0) {
  215. List names = new java.util.ArrayList();
  216. List parms = new java.util.ArrayList();
  217. populateNamesAndParms(names, parms);
  218. // now build up the filter entries for the dictionary
  219. putFilterEntries(dict, names);
  220. putDecodeParams(dict, parms);
  221. }
  222. }
  223. private int populateNamesAndParms(List names, List parms) {
  224. // run the filters
  225. int nonNullParams = 0;
  226. for (PDFFilter filter : filters) {
  227. // place the names in our local vector in reverse order
  228. if (filter.getName().length() > 0) {
  229. names.add(0, filter.getName());
  230. PDFObject param = filter.getDecodeParms();
  231. if (param != null) {
  232. parms.add(0, param);
  233. nonNullParams++;
  234. } else {
  235. parms.add(0, null);
  236. }
  237. }
  238. }
  239. return nonNullParams;
  240. }
  241. private String buildFilterEntries(List names) {
  242. int filterCount = 0;
  243. StringBuffer sb = new StringBuffer(64);
  244. for (Object name1 : names) {
  245. final String name = (String) name1;
  246. if (name.length() > 0) {
  247. filterCount++;
  248. sb.append(name);
  249. sb.append(" ");
  250. }
  251. }
  252. if (filterCount > 0) {
  253. if (filterCount > 1) {
  254. return "/Filter [ " + sb + "]";
  255. } else {
  256. return "/Filter " + sb;
  257. }
  258. } else {
  259. return "";
  260. }
  261. }
  262. private void putFilterEntries(PDFDictionary dict, List names) {
  263. PDFArray array = new PDFArray(dict);
  264. for (Object name1 : names) {
  265. final String name = (String) name1;
  266. if (name.length() > 0) {
  267. array.add(new PDFName(name));
  268. }
  269. }
  270. if (array.length() > 0) {
  271. if (array.length() > 1) {
  272. dict.put("Filter", array);
  273. } else {
  274. dict.put("Filter", array.get(0));
  275. }
  276. }
  277. }
  278. private String buildDecodeParms(List parms) {
  279. StringBuffer sb = new StringBuffer();
  280. boolean needParmsEntry = false;
  281. sb.append("\n/DecodeParms ");
  282. if (parms.size() > 1) {
  283. sb.append("[ ");
  284. }
  285. for (Object parm : parms) {
  286. String s = (String) parm;
  287. if (s != null) {
  288. sb.append(s);
  289. needParmsEntry = true;
  290. } else {
  291. sb.append("null");
  292. }
  293. sb.append(" ");
  294. }
  295. if (parms.size() > 1) {
  296. sb.append("]");
  297. }
  298. if (needParmsEntry) {
  299. return sb.toString();
  300. } else {
  301. return "";
  302. }
  303. }
  304. private void putDecodeParams(PDFDictionary dict, List parms) {
  305. boolean needParmsEntry = false;
  306. PDFArray array = new PDFArray(dict);
  307. for (Object obj : parms) {
  308. if (obj != null) {
  309. array.add(obj);
  310. needParmsEntry = true;
  311. } else {
  312. array.add(null);
  313. }
  314. }
  315. if (array.length() > 0 & needParmsEntry) {
  316. if (array.length() > 1) {
  317. dict.put("DecodeParms", array);
  318. } else {
  319. dict.put("DecodeParms", array.get(0));
  320. }
  321. }
  322. }
  323. /**
  324. * Applies all registered filters as necessary. The method returns an
  325. * OutputStream which will receive the filtered contents.
  326. * @param stream raw data output stream
  327. * @return OutputStream filtered output stream
  328. * @throws IOException In case of an I/O problem
  329. */
  330. public OutputStream applyFilters(OutputStream stream) throws IOException {
  331. OutputStream out = stream;
  332. if (!isDisableAllFilters()) {
  333. for (int count = filters.size() - 1; count >= 0; count--) {
  334. PDFFilter filter = filters.get(count);
  335. out = filter.applyFilter(out);
  336. }
  337. }
  338. return out;
  339. }
  340. }