Index: pom.xml
===================================================================
--- pom.xml (revision 1633893)
+++ pom.xml (working copy)
@@ -95,6 +95,29 @@
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.3
+
+
+ package
+
+ shade
+
+
+ false
+ true
+
+
+ org.apache.commons.compress
+ org.apache.commons.compress.SHADED
+
+
+
+
+
+
+
maven-jar-plugin
@@ -207,6 +230,12 @@
2.4
test
+
+
+ org.apache.commons
+ commons-compress
+ 1.10-SNAPSHOT
+
Index: src/main/java/org/apache/commons/imaging/common/BinaryFunctions.java
===================================================================
--- src/main/java/org/apache/commons/imaging/common/BinaryFunctions.java (revision 1633893)
+++ src/main/java/org/apache/commons/imaging/common/BinaryFunctions.java (working copy)
@@ -313,7 +313,11 @@
}
public static byte[] getStreamBytes(final InputStream is) throws IOException {
- final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ return getStreamBytes(is, 32);
+ }
+
+ public static byte[] getStreamBytes(final InputStream is, int expectedSize) throws IOException {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream(expectedSize);
copyStreamToStream(is, os);
return os.toByteArray();
}
Index: src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java
===================================================================
--- src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java (revision 1633893)
+++ src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java (working copy)
@@ -37,6 +37,7 @@
import org.apache.commons.imaging.ImageParser;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
+import org.apache.commons.imaging.common.BinaryFunctions;
import org.apache.commons.imaging.common.BinaryOutputStream;
import org.apache.commons.imaging.common.IImageMetadata;
import org.apache.commons.imaging.common.ImageBuilder;
@@ -383,9 +384,12 @@
final InputStream bais = new ByteArrayInputStream(bytes);
final int size = imageWidth * imageHeight;
- final MyLzwDecompressor myLzwDecompressor = new MyLzwDecompressor(
- lzwMinimumCodeSize, ByteOrder.LITTLE_ENDIAN);
- imageData = myLzwDecompressor.decompress(bais, size);
+ GifLzwInputStream gifLzwInputStream = new GifLzwInputStream(bais, lzwMinimumCodeSize);
+ try {
+ imageData = BinaryFunctions.getStreamBytes(gifLzwInputStream, size);
+ } finally {
+ IoUtils.closeQuietly(false, gifLzwInputStream);
+ }
} else {
final int LZWMinimumCodeSize = is.read();
if (getDebug()) {
Index: src/main/java/org/apache/commons/imaging/formats/gif/GifLzwInputStream.java
===================================================================
--- src/main/java/org/apache/commons/imaging/formats/gif/GifLzwInputStream.java (revision 0)
+++ src/main/java/org/apache/commons/imaging/formats/gif/GifLzwInputStream.java (working copy)
@@ -0,0 +1,90 @@
+/*
+ * 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.commons.imaging.formats.gif;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import org.apache.commons.compress.compressors.lzw.LZWInputStream;
+
+public class GifLzwInputStream extends LZWInputStream {
+ private static final int MAX_CODE_SIZE = 12;
+ private static final int MAX_TABLE_SIZE = 1 << MAX_CODE_SIZE;
+
+ private final int initialCodeSize;
+ private final int eoiCode;
+
+ public GifLzwInputStream(final InputStream in, final int initialCodeSize) {
+ super(in, ByteOrder.LITTLE_ENDIAN);
+ initializeTables(MAX_CODE_SIZE);
+ this.initialCodeSize = initialCodeSize + 1;
+ codeSize = initialCodeSize + 1;
+ clearCode = 1 << initialCodeSize;
+ eoiCode = clearCode + 1;
+ tableSize = eoiCode + 1;
+ }
+
+ private void clearEntries() {
+ tableSize = eoiCode + 1;
+ }
+
+ @Override
+ protected int addEntry(int previousCode, byte character) throws IOException {
+ final int maxTableSize = 1 << codeSize;
+ int r = addEntry(previousCode, character, maxTableSize);
+ if (tableSize == maxTableSize && codeSize < MAX_CODE_SIZE) {
+ codeSize++;
+ }
+ return r;
+ }
+
+ @Override
+ protected int decompressNextSymbol() throws IOException {
+ //
+ // table entry table entry
+ // _____________ _____
+ // table entry / \ / \
+ // ____________/ \ \
+ // / / \ / \ \
+ // +---+---+---+---+---+---+---+---+---+---+
+ // | . | . | . | . | . | . | . | . | . | . |
+ // +---+---+---+---+---+---+---+---+---+---+
+ // |<--------->|<------------->|<----->|<->|
+ // symbol symbol symbol symbol
+ //
+ final int code = readNextCode();
+ if (code < 0) {
+ return -1;
+ } else if (code == clearCode) {
+ clearEntries();
+ codeSize = initialCodeSize;
+ previousCode = -1;
+ return 0;
+ } else if (code == eoiCode) {
+ return -1;
+ } else {
+ boolean addedUnfinishedEntry = false;
+ int theCode = code;
+ if (theCode >= tableSize) {
+ theCode = tableSize;
+ addRepeatOfPreviousCode();
+ addedUnfinishedEntry = true;
+ }
+ return expandCodeToOutputStack(theCode, addedUnfinishedEntry);
+ }
+ }
+}
Property changes on: src/main/java/org/apache/commons/imaging/formats/gif/GifLzwInputStream.java
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReader.java
===================================================================
--- src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReader.java (revision 1633893)
+++ src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReader.java (working copy)
@@ -16,25 +16,34 @@
*/
package org.apache.commons.imaging.formats.tiff.datareaders;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_1D;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_3;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_4;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_LZW;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_PACKBITS;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_UNCOMPRESSED;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_FLAG_T4_OPTIONS_2D;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_FLAG_T4_OPTIONS_FILL;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_FLAG_T4_OPTIONS_UNCOMPRESSED_MODE;
+import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_FLAG_T6_OPTIONS_UNCOMPRESSED_MODE;
+
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.ByteOrder;
import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.BinaryFunctions;
import org.apache.commons.imaging.common.ImageBuilder;
import org.apache.commons.imaging.common.PackBits;
import org.apache.commons.imaging.common.itu_t4.T4AndT6Compression;
-import org.apache.commons.imaging.common.mylzw.MyLzwDecompressor;
import org.apache.commons.imaging.formats.tiff.TiffDirectory;
import org.apache.commons.imaging.formats.tiff.TiffField;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
+import org.apache.commons.imaging.util.IoUtils;
-import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.*;
-
public abstract class DataReader {
protected final TiffDirectory directory;
protected final PhotometricInterpreter photometricInterpreter;
@@ -180,16 +189,12 @@
}
case TIFF_COMPRESSION_LZW: // LZW
{
- final InputStream is = new ByteArrayInputStream(compressed);
-
- final int lzwMinimumCodeSize = 8;
-
- final MyLzwDecompressor myLzwDecompressor = new MyLzwDecompressor(
- lzwMinimumCodeSize, ByteOrder.BIG_ENDIAN);
-
- myLzwDecompressor.setTiffLZWMode();
-
- return myLzwDecompressor.decompress(is, expectedSize);
+ final TiffLzwInputStream tiffLzwInputStream = new TiffLzwInputStream(new ByteArrayInputStream(compressed));
+ try {
+ return BinaryFunctions.getStreamBytes(tiffLzwInputStream, expectedSize);
+ } finally {
+ IoUtils.closeQuietly(false, tiffLzwInputStream);
+ }
}
case TIFF_COMPRESSION_PACKBITS: // Packbits
Index: src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/TiffLzwInputStream.java
===================================================================
--- src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/TiffLzwInputStream.java (revision 0)
+++ src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/TiffLzwInputStream.java (working copy)
@@ -0,0 +1,90 @@
+/*
+ * 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.commons.imaging.formats.tiff.datareaders;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import org.apache.commons.compress.compressors.lzw.LZWInputStream;
+
+public class TiffLzwInputStream extends LZWInputStream {
+ private static final int MAX_CODE_SIZE = 12;
+ private static final int MAX_TABLE_SIZE = 1 << MAX_CODE_SIZE;
+
+ private final int eoiCode;
+
+ public TiffLzwInputStream(final InputStream in) {
+ super(in, ByteOrder.BIG_ENDIAN);
+ initializeTables(MAX_CODE_SIZE);
+ setClearCode(codeSize);
+ eoiCode = clearCode + 1;
+ tableSize = eoiCode + 1;
+ }
+
+ private void clearEntries() {
+ tableSize = eoiCode + 1;
+ }
+
+ @Override
+ protected int addEntry(int previousCode, byte character) throws IOException {
+ final int maxTableSize = 1 << codeSize;
+ int r = addEntry(previousCode, character, maxTableSize);
+ // early change:
+ if (tableSize == (maxTableSize - 1) && codeSize < MAX_CODE_SIZE) {
+ codeSize++;
+ }
+ return r;
+ }
+
+ @Override
+ protected int decompressNextSymbol() throws IOException {
+ //
+ // table entry table entry
+ // _____________ _____
+ // table entry / \ / \
+ // ____________/ \ \
+ // / / \ / \ \
+ // +---+---+---+---+---+---+---+---+---+---+
+ // | . | . | . | . | . | . | . | . | . | . |
+ // +---+---+---+---+---+---+---+---+---+---+
+ // |<--------->|<------------->|<----->|<->|
+ // symbol symbol symbol symbol
+ //
+ final int code = readNextCode();
+ if (code < 0) {
+ return -1;
+ } else if (code == clearCode) {
+ clearEntries();
+ codeSize = 9;
+ previousCode = -1;
+ return 0;
+ } else if (code == eoiCode) {
+ return -1;
+ } else {
+ boolean addedUnfinishedEntry = false;
+ // Unbelievably, TIFF *really* needs us to treat every out of range code as
+ // the "concatenation of previousCode with its own first character" case!!!
+ int theCode = code;
+ if (code >= tableSize) {
+ theCode = tableSize;
+ addRepeatOfPreviousCode();
+ addedUnfinishedEntry = true;
+ }
+ return expandCodeToOutputStack(theCode, addedUnfinishedEntry);
+ }
+ }
+}
Property changes on: src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/TiffLzwInputStream.java
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: src/test/java/org/apache/commons/imaging/formats/tiff/TiffRoundtripTest.java
===================================================================
--- src/test/java/org/apache/commons/imaging/formats/tiff/TiffRoundtripTest.java (revision 1633893)
+++ src/test/java/org/apache/commons/imaging/formats/tiff/TiffRoundtripTest.java (working copy)
@@ -65,8 +65,21 @@
params);
final BufferedImage image2 = Imaging.getBufferedImage(tempFile);
assertNotNull(image2);
+ compareImages(image, image2);
}
}
}
+
+ private void compareImages(BufferedImage image1, BufferedImage image2) {
+ int[] row1 = new int[image1.getWidth()];
+ int[] row2 = new int[image1.getWidth()];
+ for (int y = 0; y < image1.getHeight(); y++) {
+ image1.getRGB(0, y, image1.getWidth(), 1, row1, 0, image1.getWidth());
+ image2.getRGB(0, y, image1.getWidth(), 1, row2, 0, image1.getWidth());
+ for (int x = 0; x < row1.length; x++) {
+ assertEquals(row1[x], row2[x]);
+ }
+ }
+ }
}