Index: pom.xml
===================================================================
--- pom.xml	(revision 1633893)
+++ pom.xml	(working copy)
@@ -95,6 +95,29 @@
         </configuration>
       </plugin>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>2.3</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <createDependencyReducedPom>false</createDependencyReducedPom>
+              <minimizeJar>true</minimizeJar>
+              <relocations>
+                <relocation>
+                  <pattern>org.apache.commons.compress</pattern>
+                  <shadedPattern>org.apache.commons.compress.SHADED</shadedPattern>
+                </relocation>
+              </relocations>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
           <archive>
@@ -207,6 +230,12 @@
       <version>2.4</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <!-- maven-shade-plugin takes it out later: -->
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-compress</artifactId>
+      <version>1.10-SNAPSHOT</version>
+    </dependency>
   </dependencies>
 
   <reporting>
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]);
+            }
+        }
+    }
 
 }
