| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.pdf; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * This class represents a list of PDF filters to be applied when serializing |
| * the output of a PDF object. |
| */ |
| public class PDFFilterList { |
| |
| /** Key for the default filter */ |
| public static final String DEFAULT_FILTER = "default"; |
| /** Key for the filter used for normal content*/ |
| public static final String CONTENT_FILTER = "content"; |
| /** Key for the filter used for precompressed content */ |
| public static final String PRECOMPRESSED_FILTER = "precompressed"; |
| /** Key for the filter used for images */ |
| public static final String IMAGE_FILTER = "image"; |
| /** Key for the filter used for JPEG images */ |
| public static final String JPEG_FILTER = "jpeg"; |
| /** Key for the filter used for TIFF images */ |
| public static final String TIFF_FILTER = "tiff"; |
| /** Key for the filter used for fonts */ |
| public static final String FONT_FILTER = "font"; |
| /** Key for the filter used for metadata */ |
| public static final String METADATA_FILTER = "metadata"; |
| |
| private List filters = new java.util.ArrayList(); |
| |
| private boolean ignoreASCIIFilters = false; |
| |
| private boolean disableAllFilters = false; |
| |
| /** |
| * Default constructor. |
| * <p> |
| * The flag for ignoring ASCII filters defaults to false. |
| */ |
| public PDFFilterList() { |
| //nop |
| } |
| |
| /** |
| * Use this descriptor if you want to have ASCII filters (such as ASCIIHex |
| * and ASCII85) ignored, for example, when encryption is active. |
| * @param ignoreASCIIFilters true if ASCII filters should be ignored |
| */ |
| public PDFFilterList(boolean ignoreASCIIFilters) { |
| this.ignoreASCIIFilters = ignoreASCIIFilters; |
| } |
| |
| /** |
| * Used to disable all filters. |
| * @param value true if all filters shall be disabled |
| */ |
| public void setDisableAllFilters(boolean value) { |
| this.disableAllFilters = value; |
| } |
| |
| /** |
| * Returns true if all filters are disabled. |
| * @return true if all filters are disabled |
| */ |
| public boolean isDisableAllFilters() { |
| return this.disableAllFilters; |
| } |
| |
| /** |
| * Indicates whether the filter list is already initialized. |
| * @return true if more there are filters present |
| */ |
| public boolean isInitialized() { |
| return this.filters.size() > 0; |
| } |
| |
| /** |
| * Add a filter for compression of the stream. Filters are |
| * applied in the order they are added. This should always be a |
| * new instance of the particular filter of choice. The applied |
| * flag in the filter is marked true after it has been applied to the |
| * data. |
| * @param filter filter to add |
| */ |
| public void addFilter(PDFFilter filter) { |
| if (filter != null) { |
| if (this.ignoreASCIIFilters && filter.isASCIIFilter()) { |
| return; //ignore ASCII filter |
| } |
| filters.add(filter); |
| } |
| } |
| |
| /** |
| * Add a filter for compression of the stream by name. |
| * @param filterType name of the filter to add |
| */ |
| public void addFilter(String filterType) { |
| if (filterType == null) { |
| return; |
| } |
| if (filterType.equals("flate")) { |
| addFilter(new FlateFilter()); |
| } else if (filterType.equals("null")) { |
| addFilter(new NullFilter()); |
| } else if (filterType.equals("ascii-85")) { |
| if (this.ignoreASCIIFilters) { |
| return; //ignore ASCII filter |
| } |
| addFilter(new ASCII85Filter()); |
| } else if (filterType.equals("ascii-hex")) { |
| if (this.ignoreASCIIFilters) { |
| return; //ignore ASCII filter |
| } |
| addFilter(new ASCIIHexFilter()); |
| } else if (filterType.equals("")) { |
| return; |
| } else { |
| throw new IllegalArgumentException( |
| "Unsupported filter type in stream-filter-list: " + filterType); |
| } |
| } |
| |
| /** |
| * Checks the filter list for the filter and adds it in the correct |
| * place if necessary. |
| * @param pdfFilter the filter to check / add |
| */ |
| public void ensureFilterInPlace(PDFFilter pdfFilter) { |
| if (this.filters.size() == 0) { |
| addFilter(pdfFilter); |
| } else { |
| if (!(this.filters.get(0).equals(pdfFilter))) { |
| this.filters.add(0, pdfFilter); |
| } |
| } |
| } |
| |
| /** |
| * Adds the default filters to this stream. |
| * @param filters Map of filters |
| * @param type which filter list to modify |
| */ |
| public void addDefaultFilters(Map filters, String type) { |
| if (METADATA_FILTER.equals(type)) { |
| //XMP metadata should not be embedded in clear-text |
| addFilter(new NullFilter()); |
| return; |
| } |
| List filterset = null; |
| if (filters != null) { |
| filterset = (List)filters.get(type); |
| if (filterset == null) { |
| filterset = (List)filters.get(DEFAULT_FILTER); |
| } |
| } |
| if (filterset == null || filterset.size() == 0) { |
| if (JPEG_FILTER.equals(type)) { |
| //JPEG is already well compressed |
| addFilter(new NullFilter()); |
| } else if (TIFF_FILTER.equals(type)) { |
| //CCITT-encoded images are already well compressed |
| addFilter(new NullFilter()); |
| } else if (PRECOMPRESSED_FILTER.equals(type)) { |
| //precompressed content doesn't need further compression |
| addFilter(new NullFilter()); |
| } else { |
| // built-in default to flate |
| addFilter(new FlateFilter()); |
| } |
| } else { |
| for (int i = 0; i < filterset.size(); i++) { |
| String v = (String)filterset.get(i); |
| addFilter(v); |
| } |
| } |
| } |
| |
| /** |
| * Apply the filters to the data |
| * in the order given and return the /Filter and /DecodeParms |
| * entries for the stream dictionary. If the filters have already |
| * been applied to the data (either externally, or internally) |
| * then the dictionary entries are built and returned. |
| * @return a String representing the filter list |
| */ |
| protected String buildFilterDictEntries() { |
| if (filters != null && filters.size() > 0) { |
| List names = new java.util.ArrayList(); |
| List parms = new java.util.ArrayList(); |
| |
| int nonNullParams = populateNamesAndParms(names, parms); |
| |
| // now build up the filter entries for the dictionary |
| return buildFilterEntries(names) |
| + (nonNullParams > 0 ? buildDecodeParms(parms) : ""); |
| } |
| return ""; |
| |
| } |
| |
| /** |
| * Apply the filters to the data |
| * in the order given and add the /Filter and /DecodeParms |
| * entries to the stream dictionary. If the filters have already |
| * been applied to the data (either externally, or internally) |
| * then the dictionary entries added. |
| * @param dict the PDFDictionary to set the entries on |
| */ |
| protected void putFilterDictEntries(PDFDictionary dict) { |
| if (filters != null && filters.size() > 0) { |
| List names = new java.util.ArrayList(); |
| List parms = new java.util.ArrayList(); |
| |
| populateNamesAndParms(names, parms); |
| |
| // now build up the filter entries for the dictionary |
| putFilterEntries(dict, names); |
| putDecodeParams(dict, parms); |
| } |
| } |
| |
| private int populateNamesAndParms(List names, List parms) { |
| // run the filters |
| int nonNullParams = 0; |
| for (int count = 0; count < filters.size(); count++) { |
| PDFFilter filter = (PDFFilter)filters.get(count); |
| // place the names in our local vector in reverse order |
| if (filter.getName().length() > 0) { |
| names.add(0, filter.getName()); |
| PDFObject param = filter.getDecodeParms(); |
| if (param != null) { |
| parms.add(0, param); |
| nonNullParams++; |
| } else { |
| parms.add(0, null); |
| } |
| } |
| } |
| return nonNullParams; |
| } |
| |
| private String buildFilterEntries(List names) { |
| int filterCount = 0; |
| StringBuffer sb = new StringBuffer(64); |
| for (int i = 0; i < names.size(); i++) { |
| final String name = (String)names.get(i); |
| if (name.length() > 0) { |
| filterCount++; |
| sb.append(name); |
| sb.append(" "); |
| } |
| } |
| if (filterCount > 0) { |
| if (filterCount > 1) { |
| return "/Filter [ " + sb.toString() + "]"; |
| } else { |
| return "/Filter " + sb.toString(); |
| } |
| } else { |
| return ""; |
| } |
| } |
| |
| private void putFilterEntries(PDFDictionary dict, List names) { |
| PDFArray array = new PDFArray(dict); |
| for (int i = 0, c = names.size(); i < c; i++) { |
| final String name = (String)names.get(i); |
| if (name.length() > 0) { |
| array.add(new PDFName(name)); |
| } |
| } |
| if (array.length() > 0) { |
| if (array.length() > 1) { |
| dict.put("Filter", array); |
| } else { |
| dict.put("Filter", array.get(0)); |
| } |
| } |
| } |
| |
| private String buildDecodeParms(List parms) { |
| StringBuffer sb = new StringBuffer(); |
| boolean needParmsEntry = false; |
| sb.append("\n/DecodeParms "); |
| |
| if (parms.size() > 1) { |
| sb.append("[ "); |
| } |
| for (int count = 0; count < parms.size(); count++) { |
| String s = (String)parms.get(count); |
| if (s != null) { |
| sb.append(s); |
| needParmsEntry = true; |
| } else { |
| sb.append("null"); |
| } |
| sb.append(" "); |
| } |
| if (parms.size() > 1) { |
| sb.append("]"); |
| } |
| if (needParmsEntry) { |
| return sb.toString(); |
| } else { |
| return ""; |
| } |
| } |
| |
| private void putDecodeParams(PDFDictionary dict, List parms) { |
| boolean needParmsEntry = false; |
| PDFArray array = new PDFArray(dict); |
| for (int i = 0, c = parms.size(); i < c; i++) { |
| Object obj = parms.get(i); |
| if (obj != null) { |
| array.add(obj); |
| needParmsEntry = true; |
| } else { |
| array.add(null); |
| } |
| } |
| if (array.length() > 0 & needParmsEntry) { |
| if (array.length() > 1) { |
| dict.put("DecodeParms", array); |
| } else { |
| dict.put("DecodeParms", array.get(0)); |
| } |
| } |
| } |
| |
| /** |
| * Applies all registered filters as necessary. The method returns an |
| * OutputStream which will receive the filtered contents. |
| * @param stream raw data output stream |
| * @return OutputStream filtered output stream |
| * @throws IOException In case of an I/O problem |
| */ |
| public OutputStream applyFilters(OutputStream stream) throws IOException { |
| OutputStream out = stream; |
| if (filters != null && !isDisableAllFilters()) { |
| for (int count = filters.size() - 1; count >= 0; count--) { |
| PDFFilter filter = (PDFFilter)filters.get(count); |
| out = filter.applyFilter(out); |
| } |
| } |
| return out; |
| } |
| } |