You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/02/23 21:25:10 UTC

svn commit: r1571082 [1/2] - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/cos/ main/java/org/apache/pdfbox/filter/ main/java/org/apache/pdfbox/pdmodel/common/ main/java/org/apache/pdfbox/pdmodel/graphics/color/ main/java/org/apache/pdfbox/p...

Author: jahewson
Date: Sun Feb 23 20:25:09 2014
New Revision: 1571082

URL: http://svn.apache.org/r1571082
Log:
Added image filter repair mechanism for PDFBOX-1893

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DecodeResult.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterFactory.java
      - copied, changed from r1570339, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWDictionary.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWNode.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/RunLengthDecodeFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFFaxDecoder.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDStream.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSBase.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/filter/TestFilters.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java Sun Feb 23 20:25:09 2014
@@ -16,7 +16,6 @@
  */
 package org.apache.pdfbox.cos;
 
-import org.apache.pdfbox.filter.FilterManager;
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
 
 import org.apache.pdfbox.exceptions.COSVisitorException;
@@ -24,35 +23,19 @@ import org.apache.pdfbox.exceptions.COSV
 /**
  * The base object that all objects in the PDF document will extend.
  *
- * @author <a href="ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.14 $
+ * @author Ben Litchfield
  */
 public abstract class COSBase implements COSObjectable
 {
-    /**
-     * Constructor.
-     */
-  
     private boolean needToBeUpdate;
-    
     private boolean direct;
-  
-    public COSBase()
-    {
-      needToBeUpdate = false;
-    }
 
     /**
-     * This will get the filter manager to use to filter streams.
-     *
-     * @return The filter manager.
+     * Constructor.
      */
-    public FilterManager getFilterManager()
+    public COSBase()
     {
-        /**
-         * @todo move this to PDFdocument or something better
-         */
-        return new FilterManager();
+      needToBeUpdate = false;
     }
 
     /**
@@ -65,8 +48,6 @@ public abstract class COSBase implements
         return this;
     }
 
-
-
     /**
      * visitor pattern double dispatch method.
      *

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java Sun Feb 23 20:25:09 2014
@@ -1435,7 +1435,7 @@ public class COSDictionary extends COSBa
 
     /**
      * Returns an unmodifiable view of this dictionary.
-     * @return
+     * @return an unmodifiable view of this dictionary
      */
     public COSDictionary asUnmodifiableDictionary()
     {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java Sun Feb 23 20:25:09 2014
@@ -26,8 +26,9 @@ import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.filter.DecodeResult;
 import org.apache.pdfbox.filter.Filter;
-import org.apache.pdfbox.filter.FilterManager;
+import org.apache.pdfbox.filter.FilterFactory;
 import org.apache.pdfbox.io.*;
 import org.apache.pdfbox.pdfparser.PDFStreamParser;
 import org.apache.pdfbox.exceptions.COSVisitorException;
@@ -57,6 +58,7 @@ public class COSStream extends COSDictio
      * The stream with no filters, this contains the useful data.
      */
     private RandomAccessFileOutputStream unFilteredStream;
+    private DecodeResult decodeResult;
 
     private RandomAccess clone (RandomAccess file) {
         if (file == null) {
@@ -217,6 +219,29 @@ public class COSStream extends COSDictio
     }
 
     /**
+     * Returns the repaired stream parameters dictionary.
+     *
+     * @return the repaired stream parameters dictionary
+     * @throws IOException when encoding/decoding causes an exception
+     */
+    public DecodeResult getDecodeResult() throws IOException
+    {
+        if (unFilteredStream == null)
+        {
+            doDecode();
+        }
+
+        if (unFilteredStream == null)
+        {
+            throw new IOException("Stream was not read");
+        }
+        else
+        {
+            return decodeResult;
+        }
+    }
+
+    /**
      * visitor pattern double dispatch method.
      *
      * @param visitor The object to notify when visiting this object.
@@ -272,8 +297,7 @@ public class COSStream extends COSDictio
      */
     private void doDecode( COSName filterName, int filterIndex ) throws IOException
     {
-        FilterManager manager = getFilterManager();
-        Filter filter = manager.getFilter( filterName );
+        Filter filter = FilterFactory.INSTANCE.getFilter( filterName );
 
         boolean done = false;
         IOException exception = null;
@@ -305,8 +329,7 @@ public class COSStream extends COSDictio
                         new RandomAccessFileInputStream( file, position, length ), BUFFER_SIZE );
                 	IOUtils.closeQuietly(unFilteredStream);
                     unFilteredStream = new RandomAccessFileOutputStream( file );
-                    filter.decode( input, unFilteredStream, this.asUnmodifiableDictionary(),
-                                   filterIndex );
+                    decodeResult = filter.decode( input, unFilteredStream, this, filterIndex );
                     done = true;
                 }
                 catch( IOException io )
@@ -334,8 +357,7 @@ public class COSStream extends COSDictio
                             new RandomAccessFileInputStream( file, position, length ), BUFFER_SIZE );
                     	IOUtils.closeQuietly(unFilteredStream);
                         unFilteredStream = new RandomAccessFileOutputStream( file );
-                        filter.decode( input, unFilteredStream, this.asUnmodifiableDictionary(),
-                                       filterIndex );
+                        decodeResult = filter.decode( input, unFilteredStream, this, filterIndex);
                         done = true;
                     }
                     catch( IOException io )
@@ -396,8 +418,7 @@ public class COSStream extends COSDictio
      */
     private void doEncode( COSName filterName, int filterIndex ) throws IOException
     {
-        FilterManager manager = getFilterManager();
-        Filter filter = manager.getFilter( filterName );
+        Filter filter = FilterFactory.INSTANCE.getFilter( filterName );
 
         InputStream input = new BufferedInputStream(
             new RandomAccessFileInputStream( file, filteredStream.getPosition(),

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java Sun Feb 23 20:25:09 2014
@@ -24,56 +24,49 @@ import org.apache.pdfbox.io.ASCII85Input
 import org.apache.pdfbox.io.ASCII85OutputStream;
 
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.io.IOUtils;
 
 /**
- * This is the used for the ASCIIHexDecode filter.
- *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.8 $
+ * Decodes data encoded in an ASCII base-85 representation, reproducing the original binary data.
+ * @author Ben Litchfield
  */
-public class ASCII85Filter implements Filter
+final class ASCII85Filter extends Filter
 {
-    /**
-     * {@inheritDoc}
-     */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
         ASCII85InputStream is = null;
         try
         {
-            is = new ASCII85InputStream(compressedData);
+            is = new ASCII85InputStream(encoded);
             byte[] buffer = new byte[1024];
-            int amountRead = 0;
-            while( (amountRead = is.read( buffer, 0, 1024) ) != -1 )
+            int amountRead;
+            while((amountRead = is.read(buffer, 0, 1024))!= -1)
             {
-                result.write(buffer, 0, amountRead);
+                decoded.write(buffer, 0, amountRead);
             }
-            result.flush();
+            decoded.flush();
         }
         finally
         {
-            if( is != null )
-            {
-                is.close();
-            }
+            IOUtils.closeQuietly(is);
         }
+        return new DecodeResult(parameters);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
         throws IOException
     {
-        ASCII85OutputStream os = new ASCII85OutputStream(result);
+        ASCII85OutputStream os = new ASCII85OutputStream(encoded);
         byte[] buffer = new byte[1024];
-        int amountRead = 0;
-        while( (amountRead = rawData.read( buffer, 0, 1024 )) != -1 )
+        int amountRead;
+        while((amountRead = input.read(buffer, 0, 1024))!= -1)
         {
-            os.write( buffer, 0, amountRead );
+            os.write(buffer, 0, amountRead);
         }
         os.close();
-        result.flush();
+        encoded.flush();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java Sun Feb 23 20:25:09 2014
@@ -27,204 +27,98 @@ import org.apache.pdfbox.cos.COSDictiona
 import org.apache.pdfbox.persistence.util.COSHEXTable;
 
 /**
- * This is the used for the ASCIIHexDecode filter.
- *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.9 $
+ * Decodes data encoded in an ASCII hexadecimal form, reproducing the original binary data.
+ * @author Ben Litchfield
  */
-public class ASCIIHexFilter implements Filter
+final class ASCIIHexFilter extends Filter
 {
-
-    /**
-     * Log instance.
-     */
     private static final Log log = LogFactory.getLog(ASCIIHexFilter.class);
-    /**
-     * Whitespace.
-     *   0  0x00  Null (NUL)
-     *   9  0x09  Tab (HT)
-     *  10  0x0A  Line feed (LF)
-     *  12  0x0C  Form feed (FF)
-     *  13  0x0D  Carriage return (CR)
-     *  32  0x20  Space (SP)  
-     */
 
-    private boolean isWhitespace(int c) 
-    {
-        return c == 0 || c == 9 || c == 10 || c == 12 || c == 13 || c == 32;
-    }
-    
-    private boolean isEOD(int c) 
-    {
-        return (c == 62); // '>' - EOD
-    }
-    
-    /**
-      * {@inheritDoc}
-      */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException 
+    private static final int[] REVERSE_HEX = {
+      /*   0 */  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  10 */  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  20 */  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  30 */  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  40 */  -1, -1, -1, -1, -1, -1, -1, -1,  0,  1,
+      /*  50 */   2,  3,  4,  5,  6,  7,  8,  9, -1, -1,
+      /*  60 */  -1, -1, -1, -1, -1, 10, 11, 12, 13, 14,
+      /*  70 */  15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  80 */  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      /*  90 */  -1, -1, -1, -1, -1, -1, -1, 10, 11, 12,
+      /* 100 */  13, 14, 15
+    };
+
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-        int value = 0;
-        int firstByte = 0;
-        int secondByte = 0;
-        while ((firstByte = compressedData.read()) != -1) 
+        int value, firstByte, secondByte;
+        while ((firstByte = encoded.read()) != -1)
         {
             // always after first char
-            while(isWhitespace(firstByte))
+            while (isWhitespace(firstByte))
             {
-                firstByte = compressedData.read();
+                firstByte = encoded.read();
             }
-            if(isEOD(firstByte))
+            if (isEOD(firstByte))
             {
                 break;
             }
        
-            if(REVERSE_HEX[firstByte] == -1)
+            if (REVERSE_HEX[firstByte] == -1)
             {
-                log.error("Invalid Hex Code; int: " + firstByte + " char: " + (char) firstByte);
+                log.error("Invalid hex, int: " + firstByte + " char: " + (char)firstByte);
             }
             value = REVERSE_HEX[firstByte] * 16;
-            secondByte = compressedData.read();
+            secondByte = encoded.read();
        
-            if(isEOD(secondByte)) 
+            if (isEOD(secondByte)) 
             {
                 // second value behaves like 0 in case of EOD
-                result.write( value );
+                decoded.write(value);
                 break;
             }
-            if(secondByte >= 0) 
+            if (secondByte >= 0) 
             {
-                if(REVERSE_HEX[secondByte] == -1)
+                if (REVERSE_HEX[secondByte] == -1)
                 {
-                    log.error("Invalid Hex Code; int: " + secondByte + " char: " + (char) secondByte);
+                    log.error("Invalid hex, int: " + secondByte + " char: " + (char)secondByte);
                 }
                 value += REVERSE_HEX[secondByte];
             }
-            result.write( value );
+            decoded.write(value);
         }
-        result.flush();
+        decoded.flush();
+        return new DecodeResult(parameters);
     }
 
-    private static final int[] REVERSE_HEX =
+    // whitespace
+    //   0  0x00  Null (NUL)
+    //   9  0x09  Tab (HT)
+    //  10  0x0A  Line feed (LF)
+    //  12  0x0C  Form feed (FF)
+    //  13  0x0D  Carriage return (CR)
+    //  32  0x20  Space (SP)
+    private boolean isWhitespace(int c)
     {
-        -1, //0
-        -1, //1
-        -1, //2
-        -1, //3
-        -1, //4
-        -1, //5
-        -1, //6
-        -1, //7
-        -1, //8
-        -1, //9
-        -1, //10
-        -1, //11
-        -1, //12
-        -1, //13
-        -1, //14
-        -1, //15
-        -1, //16
-        -1, //17
-        -1, //18
-        -1, //19
-        -1, //20
-        -1, //21
-        -1, //22
-        -1, //23
-        -1, //24
-        -1, //25
-        -1, //26
-        -1, //27
-        -1, //28
-        -1, //29
-        -1, //30
-        -1, //31
-        -1, //32
-        -1, //33
-        -1, //34
-        -1, //35
-        -1, //36
-        -1, //37
-        -1, //38
-        -1, //39
-        -1, //40
-        -1, //41
-        -1, //42
-        -1, //43
-        -1, //44
-        -1, //45
-        -1, //46
-        -1, //47
-         0, //48
-         1, //49
-         2, //50
-         3, //51
-         4, //52
-         5, //53
-         6, //54
-         7, //55
-         8, //56
-         9, //57
-        -1, //58
-        -1, //59
-        -1, //60
-        -1, //61
-        -1, //62
-        -1, //63
-        -1, //64
-        10, //65
-        11, //66
-        12, //67
-        13, //68
-        14, //69
-        15, //70
-        -1, //71
-        -1, //72
-        -1, //73
-        -1, //74
-        -1, //75
-        -1, //76
-        -1, //77
-        -1, //78
-        -1, //79
-        -1, //80
-        -1, //81
-        -1, //82
-        -1, //83
-        -1, //84
-        -1, //85
-        -1, //86
-        -1, //87
-        -1, //88
-        -1, //89
-        -1, //90
-        -1, //91
-        -1, //92
-        -1, //93
-        -1, //94
-        -1, //95
-        -1, //96
-        10, //97
-        11, //98
-        12, //99
-        13, //100
-        14, //101
-        15, //102
-    };
+        return c == 0 || c == 9 || c == 10 || c == 12 || c == 13 || c == 32;
+    }
+
+    private boolean isEOD(int c)
+    {
+        return (c == 62); // '>' - EOD
+    }
 
-    /**
-     * {@inheritDoc}
-     */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
+    @Override
+    public void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
         throws IOException
     {
-        int byteRead = 0;
-        while( (byteRead = rawData.read()) != -1 )
+        int byteRead;
+        while ((byteRead = input.read()) != -1)
         {
-            int value = (byteRead+256)%256;
-            result.write( COSHEXTable.TABLE[value] );
+            int value = (byteRead + 256) % 256;
+            encoded.write(COSHEXTable.TABLE[value]);
         }
-        result.flush();
+        encoded.flush();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java Sun Feb 23 20:25:09 2014
@@ -39,42 +39,28 @@ import org.apache.pdfbox.io.ccitt.FillOr
  * @author Marcel Kammer
  * @author Paul King
  */
-public final class CCITTFaxFilter implements Filter
+final class CCITTFaxFilter extends Filter
 {
     private static final Log log = LogFactory.getLog(CCITTFaxFilter.class);
 
-    /**
-     * Constructor.
-     */
-    public CCITTFaxFilter()
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-    }
+        DecodeResult result = new DecodeResult(new COSDictionary());
+        result.getParameters().addAll(parameters);
 
-    /**
-     * {@inheritDoc}
-     */
-    public void decode(InputStream compressedData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
-    {
         // get decode parameters
-        COSBase decodeP = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
-        COSDictionary decodeParms = null;
-        if (decodeP instanceof COSDictionary)
-        {
-            decodeParms = (COSDictionary)decodeP;
-        }
-        else if (decodeP instanceof COSArray)
-        {
-            decodeParms =  (COSDictionary)((COSArray)decodeP).getObject(filterIndex);
-        }
+        COSDictionary decodeParms = (COSDictionary)
+                parameters.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
 
         // get compressed data
-        int length = options.getInt(COSName.LENGTH, -1);
-        byte[] compressed = null;
+        int length = parameters.getInt(COSName.LENGTH, -1);
+        byte[] compressed;
         if (length != -1)
         {
             compressed = new byte[length];
-            long written = IOUtils.populateBuffer(compressedData, compressed);
+            long written = IOUtils.populateBuffer(encoded, compressed);
             if (written != compressed.length)
             {
                 log.warn("Buffer for compressed data did not match the length"
@@ -86,13 +72,13 @@ public final class CCITTFaxFilter implem
             // inline images don't provide the length of the stream so that
             // we have to read until the end of the stream to find out the length
             // the streams inline images are stored in are mostly small ones
-            compressed = IOUtils.toByteArray(compressedData);
+            compressed = IOUtils.toByteArray(encoded);
         }
 
         // parse dimensions
         int cols = decodeParms.getInt(COSName.COLUMNS, 1728);
         int rows = decodeParms.getInt(COSName.ROWS, 0);
-        int height = options.getInt(COSName.HEIGHT, COSName.H, 0);
+        int height = parameters.getInt(COSName.HEIGHT, COSName.H, 0);
         if (rows > 0 && height > 0)
         {
             // ensure that rows doesn't contain implausible data, see PDFBOX-771
@@ -141,7 +127,14 @@ public final class CCITTFaxFilter implem
             invertBitmap(decompressed);
         }
 
-        result.write(decompressed);
+        // repair missing color space
+        if (!parameters.containsKey(COSName.COLORSPACE))
+        {
+            result.getParameters().setName(COSName.COLORSPACE, COSName.DEVICEGRAY.getName());
+        }
+
+        decoded.write(decompressed);
+        return new DecodeResult(parameters);
     }
 
     private void invertBitmap(byte[] bufferData)
@@ -152,11 +145,9 @@ public final class CCITTFaxFilter implem
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public void encode(InputStream rawData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
         log.warn("CCITTFaxDecode.encode is not implemented yet, skipping this stream.");
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java Sun Feb 23 20:25:09 2014
@@ -23,46 +23,43 @@ import org.apache.pdfbox.cos.COSDictiona
 import org.apache.pdfbox.cos.COSName;
 
 /**
- *
- * @author adam.nichols
+ * Decrypts data encrypted by a security handler, reproducing the data as it was before encryption.
+ * @author Adam Nichols
  */
-public class CryptFilter implements Filter
+final class CryptFilter extends Filter
 {
-    /**
-     * {@inheritDoc}
-     */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-        COSName encryptionName = (COSName)options.getDictionaryObject(COSName.NAME);
+        COSName encryptionName = (COSName) parameters.getDictionaryObject(COSName.NAME);
         if(encryptionName == null || encryptionName.equals(COSName.IDENTITY)) 
         {
             // currently the only supported implementation is the Identity crypt filter
             Filter identityFilter = new IdentityFilter();
-            identityFilter.decode(compressedData, result, options, filterIndex);
+            identityFilter.decode(encoded, decoded, parameters);
+            return new DecodeResult(parameters);
         }
         else 
         {
-            throw new IOException("Unsupported crypt filter "+encryptionName.getName());
+            throw new IOException("Unsupported crypt filter " + encryptionName.getName());
         }
     }
-    
-    /**
-     * {@inheritDoc}
-     */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException
+
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
-        COSName encryptionName = (COSName)options.getDictionaryObject(COSName.NAME);
+        COSName encryptionName = (COSName) parameters.getDictionaryObject(COSName.NAME);
         if(encryptionName == null || encryptionName.equals(COSName.IDENTITY))
         {
             // currently the only supported implementation is the Identity crypt filter
             Filter identityFilter = new IdentityFilter();
-            identityFilter.encode(rawData, result, options, filterIndex);
+            identityFilter.encode(input, encoded, parameters);
         }
         else
         {
-            throw new IOException("Unsupported crypt filter "+encryptionName.getName());
+            throw new IOException("Unsupported crypt filter " + encryptionName.getName());
         }
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java Sun Feb 23 20:25:09 2014
@@ -40,16 +40,15 @@ import javax.imageio.stream.ImageInputSt
  * Decompresses data encoded using a DCT (discrete cosine transform)
  * technique based on the JPEG standard.
  *
- * This filter is called {@code DCTDecode} in the PDF Reference.
- *
  * @author John Hewson
  */
-public final class DCTFilter implements Filter
+final class DCTFilter extends Filter
 {
     private static final Log LOG = LogFactory.getLog(DCTFilter.class);
 
-    public void decode(InputStream input, OutputStream output,
-                       COSDictionary options, int filterIndex) throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
         // find suitable image reader
         Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
@@ -70,7 +69,7 @@ public final class DCTFilter implements 
         ImageInputStream iis = null;
         try
         {
-            iis = ImageIO.createImageInputStream(input);
+            iis = ImageIO.createImageInputStream(encoded);
             reader.setInput(iis);
 
             // get the raster using horrible JAI workarounds
@@ -122,7 +121,7 @@ public final class DCTFilter implements 
             }
 
             DataBufferByte dataBuffer = (DataBufferByte)raster.getDataBuffer();
-            output.write(dataBuffer.getData());
+            decoded.write(dataBuffer.getData());
         }
         finally
         {
@@ -132,12 +131,7 @@ public final class DCTFilter implements 
             }
             reader.dispose();
         }
-    }
-
-    public void encode(InputStream rawData, OutputStream result,
-                       COSDictionary options, int filterIndex) throws IOException
-    {
-        LOG.warn("DCTFilter#encode is not implemented yet, skipping this stream.");
+        return new DecodeResult(parameters);
     }
 
     // reads the APP14 Adobe transform tag
@@ -222,4 +216,11 @@ public final class DCTFilter implements 
     {
         return (int)((value < 0) ? 0 : ((value > 255) ? 255 : value));
     }
+
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
+    {
+        LOG.warn("DCTFilter#encode is not implemented yet, skipping this stream.");
+    }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DecodeResult.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DecodeResult.java?rev=1571082&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DecodeResult.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/DecodeResult.java Sun Feb 23 20:25:09 2014
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+package org.apache.pdfbox.filter;
+
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.pdmodel.graphics.color.PDJPXColorSpace;
+
+/**
+ * The result of a filter decode operation. Allows information such as color space to be
+ * extracted from image streams, and for stream parameters to be repaired during reading.
+ *
+ * @author John Hewson
+ */
+public final class DecodeResult
+{
+    private COSDictionary parameters;
+    private PDJPXColorSpace colorSpace;
+
+    DecodeResult(COSDictionary parameters)
+    {
+        this.parameters = parameters;
+    }
+
+    DecodeResult(COSDictionary parameters, PDJPXColorSpace colorSpace)
+    {
+        this.parameters = parameters;
+        this.colorSpace = colorSpace;
+    }
+
+    /**
+     * Returns the stream parameters, repaired using the embedded stream data.
+     * @return the repaired stream parameters, or an empty dictionary
+     */
+    public COSDictionary getParameters()
+    {
+        return parameters;
+    }
+
+    /**
+     * Returns the embedded JPX color space, if any.
+     * @return the the embedded JPX color space, or null if there is none.
+     */
+    public PDJPXColorSpace getJPXColorSpace()
+    {
+        return colorSpace;
+    }
+
+    // Sets the JPX color space
+    void setColorSpace(PDJPXColorSpace colorSpace)
+    {
+        this.colorSpace = colorSpace;
+    }
+}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java Sun Feb 23 20:25:09 2014
@@ -20,39 +20,87 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
 
 /**
- * This is the interface that will be used to apply filters to a byte stream.
+ * A filter for stream data.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.7 $
+ * @author Ben Litchfield
+ * @author John Hewson
  */
-public interface Filter
+public abstract class Filter
 {
+    private static final Log log = LogFactory.getLog(Filter.class);
+
+    protected Filter()
+    {
+    }
+
     /**
-     * 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.
-     * @param filterIndex The index to the filter being decoded.
-     *
-     * @throws IOException If there is an error decompressing the stream.
+     * Decodes data, producing the original non-encoded data.
+     * @param encoded the encoded byte stream
+     * @param decoded the stream where decoded data will be written
+     * @param parameters the parameters used for decoding
+     * @return repaired parameters dictionary, or the original parameters dictionary
+     * @throws IOException if the stream cannot be decoded
      */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException;
+    public final DecodeResult decode(InputStream encoded, OutputStream decoded, COSDictionary parameters,
+                            int index) throws IOException
+    {
+        COSDictionary params = new COSDictionary();
+        params.addAll(parameters);
+        params.setItem(COSName.DECODE_PARMS, getDecodeParams(params, index));
+        return decode(encoded, decoded, params.asUnmodifiableDictionary());
+    }
+
+    // implemented in subclasses
+    protected abstract DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                   COSDictionary parameters) throws IOException;
 
     /**
-     * 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.
-     * @param filterIndex The index to the filter being encoded.
-     *
-     * @throws IOException If there is an error compressing the stream.
+     * Encodes data.
+     * @param input the byte stream to encode
+     * @param encoded the stream where encoded data will be written
+     * @param parameters the parameters used for encoding
+     * @throws IOException if the stream cannot be encoded
      */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException;
+    public final void encode(InputStream input, OutputStream encoded, COSDictionary parameters,
+                            int index) throws IOException
+    {
+        encode(input, encoded, parameters.asUnmodifiableDictionary());
+    }
+
+    // implemented in subclasses
+    protected abstract void encode(InputStream input, OutputStream encoded,
+                                   COSDictionary parameters) throws IOException;
+
+    // gets the decode params for a specific filter index, this is used to
+    // normalise the DecodeParams entry so that it is always a dictionary
+    private COSDictionary getDecodeParams(COSDictionary dictionary, int index)
+    {
+        COSBase obj = dictionary.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
+        if (obj instanceof COSDictionary)
+        {
+            return (COSDictionary)obj;
+        }
+        else if (obj instanceof COSArray)
+        {
+            COSArray array = (COSArray)obj;
+            if (index < array.size())
+            {
+                return (COSDictionary)array.getObject(index);
+            }
+        }
+        else if (obj != null)
+        {
+            log.error("Expected DecodeParams to be an Array or Dictionary but found " +
+                      obj.getClass().getName());
+        }
+        return new COSDictionary();
+    }
 }

Copied: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterFactory.java (from r1570339, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java)
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterFactory.java?p2=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterFactory.java&p1=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java&r1=1570339&r2=1571082&rev=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterFactory.java Sun Feb 23 20:25:09 2014
@@ -25,103 +25,81 @@ import java.util.Map;
 import org.apache.pdfbox.cos.COSName;
 
 /**
- * This will contain manage all the different types of filters that are available.
+ * Factory for Filter classes.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.13 $
+ * @author Ben Litchfield
  */
-public class FilterManager
+public final class FilterFactory
 {
-    private Map<COSName, Filter> filters = new HashMap<COSName, Filter>();
-
     /**
-     * Constructor.
+     * Singleton instance.
      */
-    public FilterManager()
-    {
-        Filter flateFilter = new FlateFilter();
-        Filter dctFilter = new DCTFilter();
-        Filter ccittFaxFilter = new CCITTFaxFilter();
-        Filter lzwFilter = new LZWFilter();
-        Filter asciiHexFilter = new ASCIIHexFilter();
-        Filter ascii85Filter = new ASCII85Filter();
-        Filter runLengthFilter = new RunLengthDecodeFilter();
-        Filter cryptFilter = new CryptFilter();
-        Filter jpxFilter = new JPXFilter();
-        Filter jbig2Filter = new JBIG2Filter();
-        
-        addFilter( COSName.FLATE_DECODE, flateFilter );
-        addFilter( COSName.FLATE_DECODE_ABBREVIATION, flateFilter );
-        addFilter( COSName.DCT_DECODE, dctFilter );
-        addFilter( COSName.DCT_DECODE_ABBREVIATION, dctFilter );
-        addFilter( COSName.CCITTFAX_DECODE, ccittFaxFilter );
-        addFilter( COSName.CCITTFAX_DECODE_ABBREVIATION, ccittFaxFilter );
-        addFilter( COSName.LZW_DECODE, lzwFilter );
-        addFilter( COSName.LZW_DECODE_ABBREVIATION, lzwFilter );
-        addFilter( COSName.ASCII_HEX_DECODE, asciiHexFilter );
-        addFilter( COSName.ASCII_HEX_DECODE_ABBREVIATION, asciiHexFilter );
-        addFilter( COSName.ASCII85_DECODE, ascii85Filter );
-        addFilter( COSName.ASCII85_DECODE_ABBREVIATION, ascii85Filter );
-        addFilter( COSName.RUN_LENGTH_DECODE, runLengthFilter );
-        addFilter( COSName.RUN_LENGTH_DECODE_ABBREVIATION, runLengthFilter );
-        addFilter( COSName.CRYPT, cryptFilter );
-        addFilter( COSName.JPX_DECODE, jpxFilter );
-        addFilter( COSName.JBIG2_DECODE, jbig2Filter );
-        
-    }
+    public static FilterFactory INSTANCE = new FilterFactory();
 
-    /**
-     * This will get all of the filters that are available in the system.
-     *
-     * @return All available filters in the system.
-     */
-    public Collection<Filter> getFilters()
+    private Map<COSName, Filter> filters = new HashMap<COSName, Filter>();
+
+    private FilterFactory()
     {
-        return filters.values();
+        Filter flate = new FlateFilter();
+        Filter dct = new DCTFilter();
+        Filter ccittFax = new CCITTFaxFilter();
+        Filter lzw = new LZWFilter();
+        Filter asciiHex = new ASCIIHexFilter();
+        Filter ascii85 = new ASCII85Filter();
+        Filter runLength = new RunLengthDecodeFilter();
+        Filter crypt = new CryptFilter();
+        Filter jpx = new JPXFilter();
+        Filter jbig2 = new JBIG2Filter();
+
+        filters.put(COSName.FLATE_DECODE, flate);
+        filters.put(COSName.FLATE_DECODE_ABBREVIATION, flate);
+        filters.put(COSName.DCT_DECODE, dct);
+        filters.put(COSName.DCT_DECODE_ABBREVIATION, dct);
+        filters.put(COSName.CCITTFAX_DECODE, ccittFax);
+        filters.put(COSName.CCITTFAX_DECODE_ABBREVIATION, ccittFax);
+        filters.put(COSName.LZW_DECODE, lzw);
+        filters.put(COSName.LZW_DECODE_ABBREVIATION, lzw);
+        filters.put(COSName.ASCII_HEX_DECODE, asciiHex);
+        filters.put(COSName.ASCII_HEX_DECODE_ABBREVIATION, asciiHex);
+        filters.put(COSName.ASCII85_DECODE, ascii85);
+        filters.put(COSName.ASCII85_DECODE_ABBREVIATION, ascii85);
+        filters.put(COSName.RUN_LENGTH_DECODE, runLength);
+        filters.put(COSName.RUN_LENGTH_DECODE_ABBREVIATION, runLength);
+        filters.put(COSName.CRYPT, crypt);
+        filters.put(COSName.JPX_DECODE, jpx);
+        filters.put(COSName.JBIG2_DECODE, jbig2);
     }
 
     /**
-     * This will add an available filter.
-     *
-     * @param filterName The name of the filter.
-     * @param filter The filter to use.
+     * Returns a filter instance given its name as a string.
+     * @param filterName the name of the filter to retrieve
+     * @return the filter that matches the name
+     * @throws IOException if the filter name was invalid
      */
-    public void addFilter( COSName filterName, Filter filter )
+    public Filter getFilter(String filterName) throws IOException
     {
-        filters.put( filterName, filter );
+        return getFilter(COSName.getPDFName(filterName));
     }
 
     /**
-     * This will get a filter by name.
-     *
-     * @param filterName The name of the filter to retrieve.
-     *
-     * @return The filter that matches the name.
-     *
-     * @throws IOException If the filter could not be found.
+     * Returns a filter instance given its COSName.
+     * @param filterName the name of the filter to retrieve
+     * @return the filter that matches the name
+     * @throws IOException if the filter name was invalid
      */
-    public Filter getFilter( COSName filterName ) throws IOException
+    public Filter getFilter(COSName filterName) throws IOException
     {
-        Filter filter = (Filter)filters.get( filterName );
-        if( filter == null )
+        Filter filter = filters.get(filterName);
+        if (filter == null)
         {
-            throw new IOException( "Unknown stream filter:" + filterName );
+            throw new IOException("Invalid filter: " + filterName);
         }
-
         return filter;
     }
 
-    /**
-     * This will get a filter by name.
-     *
-     * @param filterName The name of the filter to retrieve.
-     *
-     * @return The filter that matches the name.
-     *
-     * @throws IOException If the filter could not be found.
-     */
-    public Filter getFilter( String filterName ) throws IOException
+    // returns all available filters, for testing
+    Collection<Filter> getAllFilters()
     {
-        return getFilter( COSName.getPDFName( filterName ) );
+        return filters.values();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java Sun Feb 23 20:25:09 2014
@@ -27,117 +27,91 @@ import java.util.zip.Inflater;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 
 /**
- * This is the used for the FlateDecode filter.
+ * Decompresses data encoded using the zlib/deflate compression method,
+ * reproducing the original text or binary data.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @author Ben Litchfield
  * @author Marcel Kammer
- * @version $Revision: 1.12 $
  */
-public class FlateFilter implements Filter
+final class FlateFilter extends Filter
 {
-
-    /**
-     * Log instance.
-     */
     private static final Log LOG = LogFactory.getLog(FlateFilter.class);
-
     private static final int BUFFER_SIZE = 16348;
 
-    /**
-     * {@inheritDoc}
-     */
-    public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex )
-    throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-        COSBase baseObj = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
-        COSDictionary dict = null;
-        if( baseObj instanceof COSDictionary )
-        {
-            dict = (COSDictionary)baseObj;
-        }
-        else if( baseObj instanceof COSArray )
-        {
-            COSArray paramArray = (COSArray)baseObj;
-            if( filterIndex < paramArray.size() )
-            {
-                dict = (COSDictionary)paramArray.getObject( filterIndex );
-            }
-        }
-        else if( baseObj != null )
-        {
-            throw new IOException( "Error: Expected COSArray or COSDictionary and not "
-                    + baseObj.getClass().getName() );
-        }
-
-
         int predictor = -1;
         int colors = -1;
         int bitsPerPixel = -1;
         int columns = -1;
-        ByteArrayInputStream bais = null;
-        ByteArrayOutputStream baos = null;
-        if (dict!=null)
+
+        COSDictionary decodeParams = (COSDictionary)
+                parameters.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
+
+        if (decodeParams != null)
         {
-            predictor = dict.getInt(COSName.PREDICTOR);
-            if(predictor > 1)
+            predictor = decodeParams.getInt(COSName.PREDICTOR);
+            if (predictor > 1)
             {
-                colors = dict.getInt(COSName.COLORS);
-                bitsPerPixel = dict.getInt(COSName.BITS_PER_COMPONENT);
-                columns = dict.getInt(COSName.COLUMNS);
+                colors = decodeParams.getInt(COSName.COLORS);
+                bitsPerPixel = decodeParams.getInt(COSName.BITS_PER_COMPONENT);
+                columns = decodeParams.getInt(COSName.COLUMNS);
             }
         }
 
+        ByteArrayInputStream bais = null;
+        ByteArrayOutputStream baos = null;
         try
         {
-            baos = decompress(compressedData);
-            // Decode data using given predictor
-            if (predictor==-1 || predictor == 1 )
+            baos = decompress(encoded);
+
+            // decode data using given predictor
+            if (predictor == -1 || predictor == 1)
             {
-                result.write(baos.toByteArray()); 
+                decoded.write(baos.toByteArray());
             }
             else
             {
-                /*
-                 * Reverting back to default values
-                 */
-                if( colors == -1 )
+                // reverting back to default values
+                if (colors == -1)
                 {
                     colors = 1;
                 }
-                if( bitsPerPixel == -1 )
+
+                if (bitsPerPixel == -1)
                 {
                     bitsPerPixel = 8;
                 }
-                if( columns == -1 )
+
+                if (columns == -1)
                 {
                     columns = 1;
                 }
 
-                // Copy data to ByteArrayInputStream for reading
+                // copy data to ByteArrayInputStream for reading
                 bais = new ByteArrayInputStream(baos.toByteArray());
 
                 byte[] decodedData = decodePredictor(predictor, colors, bitsPerPixel, columns, bais);
                 bais.close();
                 bais = null;
 
-                result.write(decodedData);
+                decoded.write(decodedData);
             }
-            result.flush();
+            decoded.flush();
         } 
-        catch (DataFormatException exception) 
+        catch (DataFormatException e)
         {
             // if the stream is corrupt a DataFormatException may occur
             LOG.error("FlateFilter: stop reading corrupt stream due to a DataFormatException");
-            // re-throw the exception, caller has to handle it
-            IOException io = new IOException();
-            io.initCause(exception);
-            throw io;
+
+            // re-throw the exception
+            throw new IOException(e);
         }
         finally
         {
@@ -150,29 +124,30 @@ public class FlateFilter implements Filt
                 baos.close();
             }
         }
+        return new DecodeResult(parameters);
     }
 
-    // Use Inflater instead of InflateInputStream to avoid an EOFException due to a probably 
+    // Use Inflater instead of InflateInputStream to avoid an EOFException due to a probably
     // missing Z_STREAM_END, see PDFBOX-1232 for details
     private ByteArrayOutputStream decompress(InputStream in) throws IOException, DataFormatException 
     { 
         ByteArrayOutputStream out = new ByteArrayOutputStream(); 
         byte[] buf = new byte[2048]; 
         int read = in.read(buf); 
-        if(read > 0) 
+        if (read > 0) 
         { 
             Inflater inflater = new Inflater(); 
             inflater.setInput(buf,0,read); 
             byte[] res = new byte[2048]; 
-            while(true) 
+            while (true) 
             { 
                 int resRead = inflater.inflate(res); 
-                if(resRead != 0) 
+                if (resRead != 0) 
                 { 
                     out.write(res,0,resRead); 
                     continue; 
                 } 
-                if(inflater.finished() || inflater.needsDictionary() || in.available() == 0) 
+                if (inflater.finished() || inflater.needsDictionary() || in.available() == 0) 
                 {
                     break;
                 } 
@@ -189,10 +164,10 @@ public class FlateFilter implements Filt
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         byte[] buffer = new byte[2048];
-        if (predictor == 1 )
+        if (predictor == 1)
         {
-            // No prediction
-            int i = 0;
+            // no prediction
+            int i;
             while ((i = data.read(buffer)) != -1)
             {
                 baos.write(buffer, 0, i);
@@ -202,10 +177,9 @@ public class FlateFilter implements Filt
         {
             // calculate sizes
             int bitsPerPixel = colors * bitsPerComponent;
-            int bytesPerPixel = (bitsPerPixel + 7 ) / 8;
+            int bytesPerPixel = (bitsPerPixel + 7) / 8;
             int rowlength = (columns * bitsPerPixel + 7) / 8;
             byte[] actline = new byte[rowlength];
-            // Initialize lastline with Zeros according to PNG-specification
             byte[] lastline = new byte[rowlength];
 
             boolean done = false;
@@ -230,22 +204,19 @@ public class FlateFilter implements Filt
                 }
 
                 // read line
-                int i = 0;
-                int offset = 0;
+                int i, offset = 0;
                 while (offset < rowlength && ((i = data.read(actline, offset, rowlength - offset)) != -1))
                 {
                     offset += i;
                 }
 
-                // Do prediction as specified in PNG-Specification 1.2
+                // do prediction as specified in PNG-Specification 1.2
                 switch (linepredictor)
                 {
                     case 2:// PRED TIFF SUB
-                        /**
-                         * @TODO decode tiff with bitsPerComponent != 8;
-                         * e.g. for 4 bpc each nibble must be subtracted separately
-                         */
-                        if ( bitsPerComponent != 8 )
+                        // TODO decode tiff with bitsPerComponent != 8;
+                        // e.g. for 4 bpc each nibble must be subtracted separately
+                        if (bitsPerComponent != 8)
                         {
                             throw new IOException("TIFF-Predictor with " + bitsPerComponent
                                     + " bits per component not supported");
@@ -283,7 +254,7 @@ public class FlateFilter implements Filt
                             int avg = actline[p] & 0xff;
                             int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff: 0;
                             int up = lastline[p] & 0xff;
-                            actline[p] = (byte) ((avg +  (int)Math.floor( (left + up)/2 ) ) & 0xff);
+                            actline[p] = (byte) ((avg +  (int)Math.floor((left + up)/2)) & 0xff);
                         }
                         break;
                     case 14:// PRED PAETH
@@ -322,24 +293,22 @@ public class FlateFilter implements Filt
         return baos.toByteArray();
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex )
-    throws IOException
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
-        DeflaterOutputStream out = new DeflaterOutputStream(result);
-        int amountRead = 0;
-        int mayRead = rawData.available();
+        DeflaterOutputStream out = new DeflaterOutputStream(encoded);
+        int amountRead;
+        int mayRead = input.available();
         if (mayRead > 0)
         {
             byte[] buffer = new byte[Math.min(mayRead,BUFFER_SIZE)];
-            while ((amountRead = rawData.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1)
+            while ((amountRead = input.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1)
             {
                 out.write(buffer, 0, amountRead);
             }
         }
         out.close();
-        result.flush();
+        encoded.flush();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java Sun Feb 23 20:25:09 2014
@@ -22,43 +22,40 @@ import java.io.OutputStream;
 import org.apache.pdfbox.cos.COSDictionary;
 
 /**
- * The IdentityFilter filter just passes the data through without any modifications.
- * This is defined in section 7.6.5 of the PDF 1.7 spec and also stated in table
- * 26.
+ * The IdentityFilter filter passes the data through without any modifications.
+ * It is defined in section 7.6.5 of the PDF 1.7 spec and also stated in table 26.
  * 
- * @author adam.nichols
+ * @author Adam Nichols
  */
-public class IdentityFilter implements Filter
+final class IdentityFilter extends Filter
 {
     private static final int BUFFER_SIZE = 1024;
     
-    /**
-     * {@inheritDoc}
-     */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters)
         throws IOException
     {
         byte[] buffer = new byte[BUFFER_SIZE];
-        int amountRead = 0;
-        while( (amountRead = compressedData.read( buffer, 0, BUFFER_SIZE )) != -1 )
+        int amountRead;
+        while((amountRead = encoded.read(buffer, 0, BUFFER_SIZE)) != -1)
         {
-            result.write( buffer, 0, amountRead );
+            decoded.write(buffer, 0, amountRead);
         }
-        result.flush();
+        decoded.flush();
+        return new DecodeResult(parameters);
     }
-    
-    /**
-     * {@inheritDoc}
-     */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
+
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
         throws IOException
     {
         byte[] buffer = new byte[BUFFER_SIZE];
-        int amountRead = 0;
-        while( (amountRead = rawData.read( buffer, 0, BUFFER_SIZE )) != -1 )
+        int amountRead;
+        while((amountRead = input.read(buffer, 0, BUFFER_SIZE)) != -1)
         {
-            result.write( buffer, 0, amountRead );
+            encoded.write(buffer, 0, amountRead);
         }
-        result.flush();
+        encoded.flush();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java Sun Feb 23 20:25:09 2014
@@ -39,7 +39,7 @@ import org.apache.pdfbox.cos.COSStream;
 
 /**
  * Decompresses data encoded using the JBIG2 standard, reproducing the original
- * monochrome (1 bit per pixel)  image data (or an approximation of that data).
+ * monochrome (1 bit per pixel) image data (or an approximation of that data).
  *
  * Requires a JBIG2 plugin for Java Image I/O to be installed. A known working
  * plug-in is <a href="http://code.google.com/p/jbig2-imageio/">jbig2-imageio</a>
@@ -47,18 +47,13 @@ import org.apache.pdfbox.cos.COSStream;
  *
  * @author Timo Boehme
  */
-public class JBIG2Filter implements Filter
+final class JBIG2Filter extends Filter
 {
     private static final Log LOG = LogFactory.getLog(JBIG2Filter.class);
 
-    /**
-     * Decode JBIG2 data using Java ImageIO library.
-     *
-     * {@inheritDoc}
-     */
     @Override
-    public void decode(InputStream compressedData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
         // find suitable image reader
         Iterator readers = ImageIO.getImageReadersByFormatName("JBIG2");
@@ -76,8 +71,11 @@ public class JBIG2Filter implements Filt
                     "jbig2-imageio is not installed");
         }
 
-        COSInteger bits = (COSInteger) options.getDictionaryObject(COSName.BITS_PER_COMPONENT);
-        COSDictionary params = (COSDictionary) options.getDictionaryObject(COSName.DECODE_PARMS);
+        DecodeResult result = new DecodeResult(new COSDictionary());
+        result.getParameters().addAll(parameters);
+
+        COSInteger bits = (COSInteger) parameters.getDictionaryObject(COSName.BITS_PER_COMPONENT);
+        COSDictionary params = (COSDictionary) parameters.getDictionaryObject(COSName.DECODE_PARMS);
 
         COSStream globals = null;
         if (params != null)
@@ -91,12 +89,12 @@ public class JBIG2Filter implements Filt
             if (globals != null)
             {
                 iis = ImageIO.createImageInputStream(
-                        new SequenceInputStream(globals.getFilteredStream(), compressedData));
+                        new SequenceInputStream(globals.getFilteredStream(), encoded));
                 reader.setInput(iis);
             }
             else
             {
-                iis = ImageIO.createImageInputStream(compressedData);
+                iis = ImageIO.createImageInputStream(encoded);
                 reader.setInput(iis);
             }
 
@@ -130,7 +128,7 @@ public class JBIG2Filter implements Filt
             DataBuffer dBuf = image.getData().getDataBuffer();
             if (dBuf.getDataType() == DataBuffer.TYPE_BYTE)
             {
-                result.write(((DataBufferByte) dBuf).getData());
+                decoded.write(((DataBufferByte) dBuf).getData());
             }
             else
             {
@@ -145,11 +143,19 @@ public class JBIG2Filter implements Filt
             }
             reader.dispose();
         }
+
+        // repair missing color space
+        if (!parameters.containsKey(COSName.COLORSPACE))
+        {
+            result.getParameters().setName(COSName.COLORSPACE, COSName.DEVICEGRAY.getName());
+        }
+
+        return new DecodeResult(parameters);
     }
 
     @Override
-    public void encode(InputStream rawData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
         throw new UnsupportedOperationException("JBIG2 encoding not implemented");
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java Sun Feb 23 20:25:09 2014
@@ -30,6 +30,7 @@ import javax.imageio.ImageReader;
 import javax.imageio.stream.ImageInputStream;
 
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
 import org.apache.pdfbox.pdmodel.graphics.color.PDJPXColorSpace;
 
@@ -48,17 +49,15 @@ import org.apache.pdfbox.pdmodel.graphic
  * @author John Hewson
  * @author Timo Boehme
  */
-public class JPXFilter implements Filter
+public final class JPXFilter extends Filter
 {
-    /**
-     * Decode JPEG 2000 data using Java ImageIO library.
-     *
-     * {@inheritDoc}
-     */
-    public void decode(InputStream compressedData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-        BufferedImage image = readJPX(compressedData);
+        DecodeResult result = new DecodeResult(new COSDictionary());
+        result.getParameters().addAll(parameters);
+        BufferedImage image = readJPX(encoded, result);
 
         WritableRaster raster = image.getRaster();
         if (raster.getDataBuffer().getDataType() != DataBuffer.TYPE_BYTE)
@@ -66,11 +65,13 @@ public class JPXFilter implements Filter
             throw new IOException("Not implemented: greater than 8-bit depth");
         }
         DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
-        result.write(buffer.getData());
+        decoded.write(buffer.getData());
+
+        return result;
     }
 
     // try to read using JAI Image I/O
-    private static BufferedImage readJPX(InputStream input) throws IOException
+    private static BufferedImage readJPX(InputStream input, DecodeResult result) throws IOException
     {
         // find suitable image reader
         Iterator readers = ImageIO.getImageReadersByFormatName("JPEG2000");
@@ -105,6 +106,28 @@ public class JPXFilter implements Filter
                 throw new IOException("Could not read JPEG 2000 (JPX) image", e);
             }
 
+            COSDictionary parameters = result.getParameters();
+
+            // "If the image stream uses the JPXDecode filter, this entry is optional
+            // and shall be ignored if present"
+            parameters.setInt(COSName.BITS_PER_COMPONENT, image.getColorModel().getComponentSize(0));
+
+            // "Decode shall be ignored, except in the case where the image is treated as a mask"
+            if (!parameters.getBoolean(COSName.IMAGE_MASK, false))
+            {
+                parameters.setItem(COSName.DECODE, null);
+            }
+
+            // override dimensions, see PDFBOX-1735
+            parameters.setInt(COSName.WIDTH, image.getWidth());
+            parameters.setInt(COSName.HEIGHT, image.getHeight());
+
+            // extract embedded color space
+            if (!parameters.containsKey(COSName.COLORSPACE))
+            {
+                result.setColorSpace(new PDJPXColorSpace(image.getColorModel().getColorSpace()));
+            }
+
             return image;
         }
         finally
@@ -117,22 +140,9 @@ public class JPXFilter implements Filter
         }
     }
 
-    /**
-     * Returns the embedded color space from a JPX file.
-     * @param input The JPX input stream
-     */
-    // TODO this method is something of a hack, we'd rather be able to return info from decode(...)
-    public static PDColorSpace getColorSpace(InputStream input) throws IOException
-    {
-        BufferedImage image = readJPX(input);
-        return new PDJPXColorSpace(image.getColorModel().getColorSpace());
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void encode(InputStream rawData, OutputStream result, COSDictionary options,
-                       int filterIndex) throws IOException
+    @Override
+    protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
         throw new UnsupportedOperationException("JPX encoding not implemented");
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWDictionary.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWDictionary.java Sun Feb 23 20:25:09 2014
@@ -22,16 +22,15 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * This is the used for the LZWDecode filter.  This represents the dictionary mappings
+ * This is the used for the LZWDecode filter. This represents the dictionary mappings
  * between codes and their values.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.4 $
+ * @author Ben Litchfield
  */
 final class LZWDictionary
 {
     private Map<Long,byte[]> codeToData = new HashMap<Long,byte[]>();
-    private LZWNode root = new LZWNode( 0 );
+    private LZWNode root = new LZWNode(0);
 
     private byte[] buffer = new byte[8];
     private int bufferNextWrite = 0;
@@ -41,50 +40,35 @@ final class LZWDictionary
     private LZWNode previous = null;
     private LZWNode current = root;
 
-    /**
-     * This will get the value for the code.  It will return null if the code is not
-     * defined.
-     *
-     * @param code The key to the data.
-     *
-     * @return The data that is mapped to the code.
+    /*
+     * This will get the value for the code.  It will return null if the code is not defined.
      */
-    public byte[] getData( long code )
+    public byte[] getData(long code)
     {
-        byte[] result = codeToData.get( code );
+        byte[] result = codeToData.get(code);
         if (result == null && code < 256) 
         {
-            addRootNode( (byte) code );
-            result = codeToData.get( code );
+            addRootNode((byte) code);
+            result = codeToData.get(code);
         }
         return result;
     }
 
-    /**
-     * This will take a visit from a byte[].  This will create new code entries as
-     * necessary.
-     *
-     * @param data The byte to get a visit from.
-     *
-     * @throws IOException If there is an error visiting this data.
+    /*
+     * This will take a visit from a byte[].  This will create new code entries as necessary.
      */
-    public void visit( byte[] data ) throws IOException
+    public void visit(byte[] data) throws IOException
     {
-        for( int i=0; i<data.length; i++ )
+        for(int i=0; i<data.length; i++)
         {
-            visit( data[i] );
+            visit(data[i]);
         }
     }
 
-    /**
-     * This will take a visit from a byte.  This will create new code entries as
-     * necessary.
-     *
-     * @param data The byte to get a visit from.
-     *
-     * @throws IOException If there is an error visiting this data.
+    /*
+     * This will take a visit from a byte.  This will create new code entries as necessary.
      */
-    public void visit( byte data ) throws IOException
+    public void visit(byte data) throws IOException
     {
         if (buffer.length == bufferNextWrite) 
         {
@@ -94,11 +78,11 @@ final class LZWDictionary
         }
         buffer[bufferNextWrite++] = data;
         previous = current;
-        current = current.getNode( data );
+        current = current.getNode(data);
         if (current == null) 
         {
             final long code;
-            if ( previous == root ) 
+            if (previous == root) 
             {
                 code = data & 0xFF;
             } 
@@ -106,28 +90,28 @@ final class LZWDictionary
             {
                 code = nextCode++;
             }
-            current = new LZWNode( code );
-            previous.setNode( data, current );
+            current = new LZWNode(code);
+            previous.setNode(data, current);
             byte[] sav = new byte[bufferNextWrite];
             System.arraycopy(buffer, 0, sav, 0, bufferNextWrite);
-            codeToData.put( code,  sav);
+            codeToData.put(code,  sav);
 
-            /**
-            System.out.print( "Adding " + code + "='" );
-            for( int i=0; i<bufferNextWrite; i++ )
+            /*
+            System.out.print("Adding " + code + "='");
+            for(int i=0; i<bufferNextWrite; i++)
             {
-                String hex = Integer.toHexString( ((buffer[i]&0xFF );
-                if( hex.length() <=1 )
+                String hex = Integer.toHexString(((buffer[i]&0xFF);
+                if(hex.length() <=1)
                 {
                     hex = "0" + hex;
                 }
-                if( i != bufferNextWrite -1 )
+                if(i != bufferNextWrite -1)
                 {
                     hex += " ";
                 }
-                System.out.print( hex.toUpperCase() );
+                System.out.print(hex.toUpperCase());
             }
-            System.out.println( "'" );
+            System.out.println("'");
             **/
             bufferNextWrite = 0;
             current = root;
@@ -136,9 +120,8 @@ final class LZWDictionary
         }
     }
 
-    /**
+    /*
      * This will get the next code that will be created.
-     *
      * @return The next code to be created.
      */
     public long getNextCode()
@@ -146,30 +129,28 @@ final class LZWDictionary
         return nextCode;
     }
 
-    /**
+    /*
      * This will get the size of the code in bits, 9, 10, or 11.
-     *
-     * @return The size of the code in bits.
      */
     public int getCodeSize()
     {
         return codeSize;
     }
 
-    /**
-     * This will determine the code size.
+    /*
+     * This will return the code size.
      */
     private void resetCodeSize()
     {
-        if ( nextCode < 512) 
+        if (nextCode < 512) 
         {
             codeSize = 9;
         } 
-        else if ( nextCode < 1024 ) 
+        else if (nextCode < 1024) 
         {
             codeSize = 10;
         } 
-        else if ( nextCode < 2048 ) 
+        else if (nextCode < 2048) 
         {
             codeSize = 11;
         } 
@@ -179,7 +160,7 @@ final class LZWDictionary
         }
     }
 
-    /**
+    /*
      * This will clear the internal buffer that the dictionary uses.
      */
     public void clear()
@@ -189,16 +170,12 @@ final class LZWDictionary
         previous = null;
     }
 
-    /**
-     * This will folow the path to the data node.
-     *
-     * @param data The path to the node.
-     *
-     * @return The node that resides at that path.
+    /*
+     * This will follow the path to the data node.
      */
-    public LZWNode getNode( byte[] data )
+    public LZWNode getNode(byte[] data)
     {
-        LZWNode result = root.getNode( data );
+        LZWNode result = root.getNode(data);
         if (result == null && data.length == 1) 
         {
             result = addRootNode(data[0]);
@@ -206,12 +183,12 @@ final class LZWDictionary
         return result;
     }
 
-    private LZWNode addRootNode( byte b) 
+    private LZWNode addRootNode(byte b) 
     {
         long code = b & 0xFF;
-        LZWNode result = new LZWNode( code );
-        root.setNode( b, result );
-        codeToData.put( code, new byte[] { b } );
+        LZWNode result = new LZWNode(code);
+        root.setNode(b, result);
+        codeToData.put(code, new byte[] { b });
         return result;
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java Sun Feb 23 20:25:09 2014
@@ -31,133 +31,120 @@ import org.apache.pdfbox.io.NBitOutputSt
 /**
  * This is the used for the LZWDecode filter.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.15 $
+ * @author Ben Litchfield
  */
-public class LZWFilter implements Filter
+final class LZWFilter extends Filter
 {
-
-    /**
-     * The LZW clear table code.
-     */
     public static final long CLEAR_TABLE = 256;
-    /**
-     * The LZW end of data code.
-     */
     public static final long EOD = 257;
 
-    /**
-     * {@inheritDoc}
-     */
-    public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException
+    @Override
+    protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
+                                         COSDictionary parameters) throws IOException
     {
-        //log.debug("decode( )");
-        NBitInputStream in = null;
-        in = new NBitInputStream( compressedData );
-        in.setBitsInChunk( 9 );
+        //log.debug("decode()");
+        NBitInputStream in = new NBitInputStream(encoded);
+        in.setBitsInChunk(9);
         LZWDictionary dic = new LZWDictionary();
         byte firstByte = 0;
-        long nextCommand = 0;
-        while( (nextCommand = in.read() ) != EOD )
+        long nextCommand;
+        while ((nextCommand = in.read()) != EOD)
         {
-            // log.debug( "decode - nextCommand=" + nextCommand + ", bitsInChunk: " + in.getBitsInChunk());
+            // log.debug("decode - nextCommand=" + nextCommand + ", bitsInChunk: " + in.getBitsInChunk());
 
-            if( nextCommand == CLEAR_TABLE )
+            if (nextCommand == CLEAR_TABLE)
             {
-                in.setBitsInChunk( 9 );
+                in.setBitsInChunk(9);
                 dic = new LZWDictionary();
             }
             else
             {
-                byte[] data = dic.getData( nextCommand );
-                if( data == null )
+                byte[] data = dic.getData(nextCommand);
+                if (data == null)
                 {
-                    dic.visit( firstByte );
-                    data = dic.getData( nextCommand );
+                    dic.visit(firstByte);
+                    data = dic.getData(nextCommand);
                     dic.clear();
                 }
-                if( data == null )
+                if (data == null)
                 {
-                    throw new StreamCorruptedException( "Error: data is null" );
+                    throw new StreamCorruptedException("Error: data is null");
                 }
                 dic.visit(data);
 
-                //log.debug( "decode - dic.getNextCode(): " + dic.getNextCode());
+                //log.debug("decode - dic.getNextCode(): " + dic.getNextCode());
 
-                if( dic.getNextCode() >= 2047 )
+                if (dic.getNextCode() >= 2047)
                 {
-                    in.setBitsInChunk( 12 );
+                    in.setBitsInChunk(12);
                 }
-                else if( dic.getNextCode() >= 1023 )
+                else if (dic.getNextCode() >= 1023)
                 {
-                    in.setBitsInChunk( 11 );
+                    in.setBitsInChunk(11);
                 }
-                else if( dic.getNextCode() >= 511 )
+                else if (dic.getNextCode() >= 511)
                 {
-                    in.setBitsInChunk( 10 );
+                    in.setBitsInChunk(10);
                 }
                 else
                 {
-                    in.setBitsInChunk( 9 );
+                    in.setBitsInChunk(9);
                 }
                 /**
-                if( in.getBitsInChunk() != dic.getCodeSize() )
+                if (in.getBitsInChunk() != dic.getCodeSize())
                 {
-                    in.unread( nextCommand );
-                    in.setBitsInChunk( dic.getCodeSize() );
-                    System.out.print( "Switching " + nextCommand + " to " );
+                    in.unread(nextCommand);
+                    in.setBitsInChunk(dic.getCodeSize());
+                    System.out.print("Switching " + nextCommand + " to ");
                     nextCommand = in.read();
-                    System.out.println( "" +  nextCommand );
-                    data = dic.getData( nextCommand );
+                    System.out.println("" +  nextCommand);
+                    data = dic.getData(nextCommand);
                 }**/
                 firstByte = data[0];
-                result.write( data );
+                decoded.write(data);
             }
         }
-        result.flush();
+        decoded.flush();
+        return new DecodeResult(parameters);
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
-    public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) 
-        throws IOException
+    @Override
+    protected final void encode(InputStream rawData, OutputStream encoded, COSDictionary parameters)
+            throws IOException
     {
-        //log.debug("encode( )");
-        PushbackInputStream input = new PushbackInputStream( rawData, 4096 );
+        //log.debug("encode()");
+        PushbackInputStream input = new PushbackInputStream(rawData, 4096);
         LZWDictionary dic = new LZWDictionary();
-        NBitOutputStream out = new NBitOutputStream( result );
-        out.setBitsInChunk( 9 ); //initially nine
-        out.write( CLEAR_TABLE );
+        NBitOutputStream out = new NBitOutputStream(encoded);
+        out.setBitsInChunk(9); //initially nine
+        out.write(CLEAR_TABLE);
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         int byteRead = 0;
-        for( int i=0; (byteRead = input.read()) != -1; i++ )
+        for (int i = 0; (byteRead = input.read()) != -1; i++)
         {
-            //log.debug( "byteRead = '" + (char)byteRead + "' (0x" + Integer.toHexString(byteRead) + "), i=" + i);
-            buffer.write( byteRead );
-            dic.visit( (byte)byteRead );
-            out.setBitsInChunk( dic.getCodeSize() );
+            //log.debug("byteRead = '" + (char)byteRead + "' (0x" + Integer.toHexString(byteRead) + "), i=" + i);
+            buffer.write(byteRead);
+            dic.visit((byte)byteRead);
+            out.setBitsInChunk(dic.getCodeSize());
 
-            //log.debug( "Getting node '" + new String( buffer.toByteArray() ) + "', buffer.size = " + buffer.size() );
-            LZWNode node = dic.getNode( buffer.toByteArray() );
+            //log.debug("Getting node '" + new String(buffer.toByteArray()) + "', buffer.size = " + buffer.size());
+            LZWNode node = dic.getNode(buffer.toByteArray());
             int nextByte = input.read();
-            if( nextByte != -1 )
+            if (nextByte != -1)
             {
-                //log.debug( "nextByte = '" + (char)nextByte + "' (0x" + Integer.toHexString(nextByte) + ")");
-                LZWNode next = node.getNode( (byte)nextByte );
-                if( next == null )
+                //log.debug("nextByte = '" + (char)nextByte + "' (0x" + Integer.toHexString(nextByte) + ")");
+                LZWNode next = node.getNode((byte)nextByte);
+                if (next == null)
                 {
                     //log.debug("encode - No next node, writing node and resetting buffer (" +
                     //          " node.getCode: " + node.getCode() + ")" +
                     //          " bitsInChunk: " + out.getBitsInChunk() +
                     //          ")");
-                    out.write( node.getCode() );
+                    out.write(node.getCode());
                     buffer.reset();
                 }
 
-                input.unread( nextByte );
+                input.unread(nextByte);
             }
             else
             {
@@ -165,47 +152,47 @@ public class LZWFilter implements Filter
                 //          " node.getCode: " + node.getCode() + ")" +
                 //          " bitsInChunk: " + out.getBitsInChunk() +
                 //          ")");
-                out.write( node.getCode() );
+                out.write(node.getCode());
                 buffer.reset();
                 break;
             }
 
-            if( dic.getNextCode() == 4096 )
+            if (dic.getNextCode() == 4096)
             {
                 //log.debug("encode - Clearing dictionary and unreading pending buffer data (" +
                 //          " bitsInChunk: " + out.getBitsInChunk() +
                 //          ")");
-                out.write( CLEAR_TABLE );
+                out.write(CLEAR_TABLE);
                 dic = new LZWDictionary();
-                input.unread( buffer.toByteArray() );
+                input.unread(buffer.toByteArray());
                 buffer.reset();
             }
         }
 
         // Fix the code size based on the fact that we are writing the EOD
         //
-        if( dic.getNextCode() >= 2047 )
+        if (dic.getNextCode() >= 2047)
         {
-            out.setBitsInChunk( 12 );
+            out.setBitsInChunk(12);
         }
-        else if( dic.getNextCode() >= 1023 )
+        else if (dic.getNextCode() >= 1023)
         {
-            out.setBitsInChunk( 11 );
+            out.setBitsInChunk(11);
         }
-        else if( dic.getNextCode() >= 511 )
+        else if (dic.getNextCode() >= 511)
         {
-            out.setBitsInChunk( 10 );
+            out.setBitsInChunk(10);
         }
         else
         {
-            out.setBitsInChunk( 9 );
+            out.setBitsInChunk(9);
         }
 
         //log.debug("encode - Writing EOD (" +
         //          " bitsInChunk: " + out.getBitsInChunk() +
         //          ")");
-        out.write( EOD );
+        out.write(EOD);
         out.close();
-        result.flush();
+        encoded.flush();
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWNode.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWNode.java?rev=1571082&r1=1571081&r2=1571082&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWNode.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWNode.java Sun Feb 23 20:25:09 2014
@@ -22,77 +22,61 @@ import java.util.Map;
 /**
  * This is the used for the LZWDecode filter.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.4 $
+ * @author Ben Litchfield
  */
-class LZWNode
+final class LZWNode
 {
     private final long code;
-    private final Map<Byte,LZWNode> subNodes = new HashMap<Byte,LZWNode>();
+    private final Map<Byte, LZWNode> subNodes = new HashMap<Byte, LZWNode>();
 
-    public LZWNode( long codeValue ) 
+    public LZWNode(long codeValue) 
     {
         code = codeValue;
     }
 
-    /**
+    /*
      * This will get the number of children.
-     *
-     * @return The number of children.
      */
     public int childCount()
     {
         return subNodes.size();
     }
 
-    /**
+    /*
      * This will set the node for a particular byte.
-     *
-     * @param b The byte for that node.
-     * @param node The node to add.
      */
-    public void setNode( byte b, LZWNode node )
+    public void setNode(byte b, LZWNode node)
     {
-        subNodes.put( b, node );
+        subNodes.put(b, node);
     }
 
-    /**
+    /*
      * This will get the node that is a direct sub node of this node.
-     *
-     * @param data The byte code to the node.
-     *
-     * @return The node at that value if it exists.
      */
-    public LZWNode getNode( byte data )
+    public LZWNode getNode(byte data)
     {
-        return subNodes.get( data );
+        return subNodes.get(data);
     }
 
-
-    /**
+    /*
      * This will traverse the tree until it gets to the sub node.
      * This will return null if the node does not exist.
-     *
-     * @param data The path to the node.
-     *
-     * @return The node that resides at the data path.
      */
-    public LZWNode getNode( byte[] data )
+    public LZWNode getNode(byte[] data)
     {
         LZWNode current = this;
-        for( int i=0; i<data.length && current != null; i++ )
+        for (int i = 0; i < data.length && current != null; i++)
         {
-            current = current.getNode( data[i] );
+            current = current.getNode(data[i]);
         }
         return current;
     }
 
-    /** Getter for property code.
-     * @return Value of property code.
+    /*
+     * Returns the property code
      */
     public long getCode()
     {
         return code;
     }
-
 }