You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/05/01 15:17:04 UTC

svn commit: r1591650 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter: FlateFilter.java LZWFilter.java Predictor.java

Author: tilman
Date: Thu May  1 13:17:03 2014
New Revision: 1591650

URL: http://svn.apache.org/r1591650
Log:
PDFBOX-2050: added predictor postprocessing found in Flate filter to LZW filter, moved predictor method into a helper class

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java   (with props)
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java

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=1591650&r1=1591649&r2=1591650&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 Thu May  1 13:17:03 2014
@@ -97,7 +97,7 @@ final class FlateFilter extends Filter
                 // copy data to ByteArrayInputStream for reading
                 bais = new ByteArrayInputStream(baos.toByteArray());
 
-                byte[] decodedData = decodePredictor(predictor, colors, bitsPerPixel, columns, bais);
+                byte[] decodedData = Predictor.decodePredictor(predictor, colors, bitsPerPixel, columns, bais);
                 bais.close();
                 bais = null;
 
@@ -157,142 +157,8 @@ final class FlateFilter extends Filter
         }
         out.close();
         return out;
-    } 
-    
-    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)
-        {
-            // no prediction
-            int i;
-            while ((i = data.read(buffer)) != -1)
-            {
-                baos.write(buffer, 0, i);
-            }
-        }
-        else
-        {
-            // calculate sizes
-            int bitsPerPixel = colors * bitsPerComponent;
-            int bytesPerPixel = (bitsPerPixel + 7) / 8;
-            int rowlength = (columns * bitsPerPixel + 7) / 8;
-            byte[] actline = new byte[rowlength];
-            byte[] lastline = new byte[rowlength];
-
-            boolean done = false;
-            int linepredictor = predictor;
-
-            while (!done && data.available() > 0)
-            {
-                // test for PNG predictor; each value >= 10 (not only 15) indicates usage of PNG predictor
-                if (predictor >= 10)
-                {
-                    // PNG predictor; each row starts with predictor type (0, 1, 2, 3, 4)
-                    linepredictor = data.read();// read per line predictor
-                    if (linepredictor == -1)
-                    {
-                        done = true;// reached EOF
-                        break;
-                    }
-                    else
-                    {
-                        linepredictor += 10; // add 10 to tread value 0 as 10, 1 as 11, ...
-                    }
-                }
-
-                // read line
-                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
-                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)
-                        {
-                            throw new IOException("TIFF-Predictor with " + bitsPerComponent
-                                    + " bits per component not supported");
-                        }
-                        // for 8 bits per component it is the same algorithm as PRED SUB of PNG format
-                        for (int p = 0; p < rowlength; p++)
-                        {
-                            int sub = actline[p] & 0xff;
-                            int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0;
-                            actline[p] = (byte) (sub + left);
-                        }
-                        break;
-                    case 10:// PRED NONE
-                        // do nothing
-                        break;
-                    case 11:// PRED SUB
-                        for (int p = 0; p < rowlength; p++)
-                        {
-                            int sub = actline[p];
-                            int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel]: 0;
-                            actline[p] = (byte) (sub + left);
-                        }
-                        break;
-                    case 12:// PRED UP
-                        for (int p = 0; p < rowlength; p++)
-                        {
-                            int up = actline[p] & 0xff;
-                            int prior = lastline[p] & 0xff;
-                            actline[p] = (byte) ((up + prior) & 0xff);
-                        }
-                        break;
-                    case 13:// PRED AVG
-                        for (int p = 0; p < rowlength; p++)
-                        {
-                            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);
-                        }
-                        break;
-                    case 14:// PRED PAETH
-                        for (int p = 0; p < rowlength; p++)
-                        {
-                            int paeth = actline[p] & 0xff;
-                            int a = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0;// left
-                            int b = lastline[p] & 0xff;// upper
-                            int c = p - bytesPerPixel >= 0 ? lastline[p - bytesPerPixel] & 0xff : 0;// 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 + a) & 0xff);
-                            }
-                            else if (absb <= absc)
-                            {
-                                actline[p] = (byte) ((paeth + b) & 0xff);
-                            }
-                            else
-                            {
-                                actline[p] = (byte) ((paeth + c) & 0xff);
-                            }
-                        }
-                        break;
-                    default:
-                        break;
-                }
-                lastline = actline.clone();
-                baos.write(actline, 0, actline.length);
-            }
-        }
-        return baos.toByteArray();
     }
-
+    
     @Override
     protected final void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
             throws IOException

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=1591650&r1=1591649&r2=1591650&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 Thu May  1 13:17:03 2014
@@ -15,6 +15,8 @@
  */
 package org.apache.pdfbox.filter;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -26,6 +28,7 @@ import javax.imageio.stream.MemoryCacheI
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
 
 /**
  *
@@ -61,6 +64,34 @@ public class LZWFilter extends Filter
     protected final DecodeResult decode(InputStream encoded, OutputStream decoded,
             COSDictionary parameters) throws IOException
     {
+        int predictor = -1;
+
+        COSDictionary decodeParams = (COSDictionary)
+                parameters.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP);
+        if (decodeParams != null)
+        {
+            predictor = decodeParams.getInt(COSName.PREDICTOR);
+        }
+        if (predictor > 1)
+        {
+            int colors = decodeParams.getInt(COSName.COLORS, 1);
+            int bitsPerPixel = decodeParams.getInt(COSName.BITS_PER_COMPONENT, 8);
+            int columns = decodeParams.getInt(COSName.COLUMNS, 1);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            doLZWDecode(encoded, baos);
+            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+            byte[] decodedData = Predictor.decodePredictor(predictor, colors, bitsPerPixel, columns, bais);
+            decoded.write(decodedData);
+        }
+        else
+        {
+            doLZWDecode(encoded, decoded);
+        }
+        return new DecodeResult(parameters);
+    }
+
+    private void doLZWDecode(InputStream encoded, OutputStream decoded) throws IOException
+    {
         ArrayList<byte[]> codeTable = null;
         int chunk = 9;
         MemoryCacheImageInputStream in = new MemoryCacheImageInputStream(encoded);
@@ -111,7 +142,6 @@ public class LZWFilter extends Filter
             LOG.warn("Premature EOF in LZW stream, EOD code missing");
         }
         decoded.flush();
-        return new DecodeResult(parameters);
     }
 
     /**

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java?rev=1591650&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java Thu May  1 13:17:03 2014
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2014 The Apache Software Foundation.
+ *
+ * Licensed 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Helper class to contain predictor decoding used by Flate and LZW filter.
+ * To see the history, look at the FlateFilter class.
+ */
+public class Predictor
+{
+    static 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)
+        {
+            // no prediction
+            int i;
+            while ((i = data.read(buffer)) != -1)
+            {
+                baos.write(buffer, 0, i);
+            }
+        }
+        else
+        {
+            // calculate sizes
+            final int bitsPerPixel = colors * bitsPerComponent;
+            final int bytesPerPixel = (bitsPerPixel + 7) / 8;
+            final int rowlength = (columns * bitsPerPixel + 7) / 8;
+            byte[] actline = new byte[rowlength];
+            byte[] lastline = new byte[rowlength];
+
+            boolean done = false;
+            int linepredictor = predictor;
+
+            while (!done && data.available() > 0)
+            {
+                // test for PNG predictor; each value >= 10 (not only 15) indicates usage of PNG predictor
+                if (predictor >= 10)
+                {
+                    // PNG predictor; each row starts with predictor type (0, 1, 2, 3, 4)
+                    linepredictor = data.read();// read per line predictor
+                    if (linepredictor == -1)
+                    {
+                        done = true;// reached EOF
+                        break;
+                    }
+                    else
+                    {
+                        linepredictor += 10; // add 10 to tread value 0 as 10, 1 as 11, ...
+                    }
+                }
+
+                // read line
+                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
+                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)
+                        {
+                            throw new IOException("TIFF-Predictor with " + bitsPerComponent
+                                    + " bits per component not supported");
+                        }
+                        // for 8 bits per component it is the same algorithm as PRED SUB of PNG format
+                        for (int p = 0; p < rowlength; p++)
+                        {
+                            int sub = actline[p] & 0xff;
+                            int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0;
+                            actline[p] = (byte) (sub + left);
+                        }
+                        break;
+                    case 10:// PRED NONE
+                        // do nothing
+                        break;
+                    case 11:// PRED SUB
+                        for (int p = 0; p < rowlength; p++)
+                        {
+                            int sub = actline[p];
+                            int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] : 0;
+                            actline[p] = (byte) (sub + left);
+                        }
+                        break;
+                    case 12:// PRED UP
+                        for (int p = 0; p < rowlength; p++)
+                        {
+                            int up = actline[p] & 0xff;
+                            int prior = lastline[p] & 0xff;
+                            actline[p] = (byte) ((up + prior) & 0xff);
+                        }
+                        break;
+                    case 13:// PRED AVG
+                        for (int p = 0; p < rowlength; p++)
+                        {
+                            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);
+                        }
+                        break;
+                    case 14:// PRED PAETH
+                        for (int p = 0; p < rowlength; p++)
+                        {
+                            int paeth = actline[p] & 0xff;
+                            int a = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0;// left
+                            int b = lastline[p] & 0xff;// upper
+                            int c = p - bytesPerPixel >= 0 ? lastline[p - bytesPerPixel] & 0xff : 0;// 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 + a) & 0xff);
+                            }
+                            else if (absb <= absc)
+                            {
+                                actline[p] = (byte) ((paeth + b) & 0xff);
+                            }
+                            else
+                            {
+                                actline[p] = (byte) ((paeth + c) & 0xff);
+                            }
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                lastline = actline.clone();
+                baos.write(actline, 0, actline.length);
+            }
+        }
+        return baos.toByteArray();
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java
------------------------------------------------------------------------------
    svn:eol-style = native