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