From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- src/main/java/org/pdfbox/filter/FlateFilter.java | 303 +++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/main/java/org/pdfbox/filter/FlateFilter.java (limited to 'src/main/java/org/pdfbox/filter/FlateFilter.java') diff --git a/src/main/java/org/pdfbox/filter/FlateFilter.java b/src/main/java/org/pdfbox/filter/FlateFilter.java new file mode 100644 index 0000000..c239686 --- /dev/null +++ b/src/main/java/org/pdfbox/filter/FlateFilter.java @@ -0,0 +1,303 @@ +/** + * Copyright (c) 2003-2005, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ +package org.pdfbox.filter; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +import org.pdfbox.cos.COSDictionary; + +/** + * This is the used for the FlateDecode filter. + * + * @author Ben Litchfield (ben@benlitchfield.com) + * @author Marcel Kammer + * @version $Revision: 1.9 $ + */ +public class FlateFilter implements Filter +{ + private static final int BUFFER_SIZE = 2048; + + /** + * This will decode some compressed data. + * + * @param compressedData + * The compressed byte stream. + * @param result + * The place to write the uncompressed byte stream. + * @param options + * The options to use to encode the data. + * + * @throws IOException + * If there is an error decompressing the stream. + */ + + public void decode(InputStream compressedData, OutputStream result, COSDictionary options) throws IOException + { + COSDictionary dict = (COSDictionary) options.getDictionaryObject("DecodeParms"); + int predictor = -1; + int colors = -1; + int bitsPerPixel = -1; + int columns = -1; + InflaterInputStream decompressor = null; + ByteArrayInputStream bais = null; + ByteArrayOutputStream baos = null; + if (dict!=null) + { + predictor = dict.getInt("Predictor"); + colors = dict.getInt("Colors"); + bitsPerPixel = options.getInt("BitsPerComponent"); + columns = dict.getInt("Columns"); + } + + try + { + // Decompress data to temporary ByteArrayOutputStream + decompressor = new InflaterInputStream(compressedData); + byte[] buffer = new byte[BUFFER_SIZE]; + int amountRead; + + // Decode data using given predictor + if (predictor==-1 || predictor == 1 && predictor == 10) + { + // decoding not needed + while ((amountRead = decompressor.read(buffer, 0, BUFFER_SIZE)) != -1) + { + result.write(buffer, 0, amountRead); + } + } + else + { + if (colors==-1 || bitsPerPixel==-1 || columns==-1) + { + throw new IOException("Could not read all parameters to decode image"); + } + + baos = new ByteArrayOutputStream(); + while ((amountRead = decompressor.read(buffer, 0, BUFFER_SIZE)) != -1) + { + baos.write(buffer, 0, amountRead); + } + baos.flush(); + + // Copy data to ByteArrayInputStream for reading + bais = new ByteArrayInputStream(baos.toByteArray()); + baos.close(); + baos = null; + + byte[] decodedData = decodePredictor(predictor, colors, bitsPerPixel, columns, bais); + bais.close(); + bais = new ByteArrayInputStream(decodedData); + + // write decoded data to result + while ((amountRead = bais.read(buffer)) != -1) + { + result.write(buffer, 0, amountRead); + } + bais.close(); + bais = null; + } + + + result.flush(); + } + finally + { + if (decompressor != null) + { + decompressor.close(); + } + if (bais != null) + { + bais.close(); + } + if (baos != null) + { + baos.close(); + } + } + } + + private byte[] decodePredictor(int predictor, int colors, int bitsPerComponent, int columns, InputStream data) + throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[2048]; + + if (predictor == 1 || predictor == 10) + { + // No prediction or PNG NONE + int i = 0; + while ((i = data.read(buffer)) != -1) + { + baos.write(buffer, 0, i); + } + } + else + { + // calculate sizes + int bpp = (colors * bitsPerComponent + 7) / 8; + int rowlength = (columns * colors * bitsPerComponent + 7) / 8 + bpp; + byte[] actline = new byte[rowlength]; + byte[] lastline = new byte[rowlength];// Initialize lastline with + // Zeros according to + // PNG-specification + boolean done = false; + int linepredictor = predictor; + + while (!done) + { + if (predictor == 15) + { + linepredictor = data.read();// read per line predictor + if (linepredictor == -1) + { + done = true;// reached EOF + break; + } + else + { + linepredictor += 10; // add 10 to tread value 1 as 11 + } + // (instead of PRED NONE) and 2 + // as 12 (instead of PRED TIFF) + } + + // read line + int i = 0; + int offset = bpp; + while (offset < rowlength && ((i = data.read(actline, offset, rowlength - offset)) != -1)) + { + offset += i; + } + + // Do prediction as specified in PNG-Specification 1.2 + switch (linepredictor) + { + case 2:// PRED TIFF SUB + /** + * @todo decode tiff + */ + throw new IOException("TIFF-Predictor not supported"); + case 11:// PRED SUB + for (int p = bpp; p < rowlength; p++) + { + int sub = actline[p] & 0xff; + int left = actline[p - bpp] & 0xff; + actline[p] = (byte) (sub + left); + } + break; + case 12:// PRED UP + for (int p = bpp; p < rowlength; p++) + { + int up = actline[p] & 0xff; + int prior = lastline[p] & 0xff; + actline[p] = (byte) (up + prior); + } + break; + case 13:// PRED AVG + for (int p = bpp; p < rowlength; p++) + { + int avg = actline[p] & 0xff; + int left = actline[p - bpp] & 0xff; + int up = lastline[p] & 0xff; + actline[p] = (byte) (avg + ((left + up) / 2)); + } + break; + case 14:// PRED PAETH + for (int p = bpp; p < rowlength; p++) + { + int paeth = actline[p] & 0xff; + int a = actline[p - bpp] & 0xff;// left + int b = lastline[p] & 0xff;// upper + int c = lastline[p - bpp] & 0xff;// upperleft + int value = a + b - c; + int absa = Math.abs(value - a); + int absb = Math.abs(value - b); + int absc = Math.abs(value - c); + + if (absa <= absb && absa <= absc) + { + actline[p] = (byte) (paeth + absa); + } + else if (absb <= absc) + { + actline[p] += (byte) (paeth + absb); + } + else + { + actline[p] += (byte) (paeth + absc); + } + } + break; + default: + break; + } + + lastline = actline; + baos.write(actline, bpp, actline.length - bpp); + } + } + + return baos.toByteArray(); + } + + /** + * This will encode some data. + * + * @param rawData + * The raw data to encode. + * @param result + * The place to write to encoded results to. + * @param options + * The options to use to encode the data. + * + * @throws IOException + * If there is an error compressing the stream. + */ + public void encode(InputStream rawData, OutputStream result, COSDictionary options) throws IOException + { + DeflaterOutputStream out = new DeflaterOutputStream(result); + byte[] buffer = new byte[BUFFER_SIZE]; + int amountRead = 0; + while ((amountRead = rawData.read(buffer, 0, BUFFER_SIZE)) != -1) + { + out.write(buffer, 0, amountRead); + } + out.close(); + result.flush(); + } +} \ No newline at end of file -- cgit v1.2.3