You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2021/08/01 12:14:39 UTC

[sis] branch geoapi-4.0 updated (83ec78c -> 6580779)

This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a change to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git.


    from 83ec78c  Reduce by one the number of exceptions created when the fallback is used or when an error occurs.
     new e1b3d89  Move the `Compression` enumeration close to `Inflater`. It would allow sharing compression algorithms with other image formats in the future if needed.
     new 7bbdb81  Rename `Uncompressed` as `CopyFromBytes` because this class can be used even for compressed data.
     new 6580779  Ensure that the chunk size are not greater than buffer capacity.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../{storage => internal}/geotiff/Compression.java | 13 +++--
 .../{Uncompressed.java => CopyFromBytes.java}      | 30 +++++-----
 .../org/apache/sis/internal/geotiff/Inflater.java  | 59 ++++++++++++++++++--
 .../sis/storage/geotiff/CompressedSubset.java      | 28 ++++++++--
 .../org/apache/sis/storage/geotiff/DataCube.java   | 20 +++----
 .../sis/storage/geotiff/ImageFileDirectory.java    |  1 +
 .../geotiff/CompressionTest.java                   |  6 +-
 .../apache/sis/internal/geotiff/InflaterTest.java  | 64 ++++++++++++++++++++++
 .../apache/sis/test/suite/GeoTiffTestSuite.java    |  3 +-
 9 files changed, 176 insertions(+), 48 deletions(-)
 rename storage/sis-geotiff/src/main/java/org/apache/sis/{storage => internal}/geotiff/Compression.java (93%)
 rename storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/{Uncompressed.java => CopyFromBytes.java} (91%)
 rename storage/sis-geotiff/src/test/java/org/apache/sis/{storage => internal}/geotiff/CompressionTest.java (92%)
 create mode 100644 storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/InflaterTest.java

[sis] 02/03: Rename `Uncompressed` as `CopyFromBytes` because this class can be used even for compressed data.

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 7bbdb81aca1f02f98c7e1743a2d58a67fe2cc01c
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Jul 31 20:33:32 2021 +0200

    Rename `Uncompressed` as `CopyFromBytes` because this class can be used even for compressed data.
---
 .../{Uncompressed.java => CopyFromBytes.java}      | 28 ++++++++++++----------
 .../org/apache/sis/internal/geotiff/Inflater.java  |  8 +++++--
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
similarity index 92%
rename from storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java
rename to storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
index faa815d..4fe7a12 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
@@ -30,17 +30,19 @@ import org.apache.sis.util.Classes;
 
 
 /**
- * A pseudo-inflater which copy values unchanged.
- * This implementation is useful for handling more complex subsampling
- * than what {@link org.apache.sis.internal.storage.io.HyperRectangleReader} can handle.
- * It is also useful for testing purpose.
+ * A pseudo-inflater which copies values from a buffer of bytes to the destination image buffer.
+ * When reading uncompressed TIFF images, the source buffer is the direct buffer used for I/O operations.
+ * When reading compressed TIFF images, the source buffer is a temporary buffer where data segments are
+ * uncompressed before to be copied to the destination image. This is useful when handling subsampling
+ * on-the-fly at decompression time would be too difficult: implementers can decompress everything in
+ * a temporary buffer and let this {@code CopyFromBytes} class do the subsampling.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
  * @since   1.1
  * @module
  */
-abstract class Uncompressed extends Inflater {
+abstract class CopyFromBytes extends Inflater {
     /**
      * Stream position where to perform the next reading.
      */
@@ -60,7 +62,7 @@ abstract class Uncompressed extends Inflater {
     /**
      * For constructors in inner classes.
      */
-    private Uncompressed(final ChannelDataInput input, final long start, final int elementsPerRow,
+    private CopyFromBytes(final ChannelDataInput input, final long start, final int elementsPerRow,
                          final int samplesPerElement, final int[] skipAfterElements, final int sampleSize)
     {
         super(input, elementsPerRow, samplesPerElement, skipAfterElements);
@@ -80,7 +82,7 @@ abstract class Uncompressed extends Inflater {
      * @return the inflater for the given targe type.
      * @throws IllegalArgumentException if the buffer type is not recognized.
      */
-    public static Uncompressed create(final ChannelDataInput input, final long start,
+    public static CopyFromBytes create(final ChannelDataInput input, final long start,
             final int count, final int size, final int[] skips, final Buffer target)
     {
         if (target instanceof   ByteBuffer) return new Bytes  (input, start, count, size, skips,   (ByteBuffer) target);
@@ -152,7 +154,7 @@ abstract class Uncompressed extends Inflater {
     /**
      * Inflater for sample values stored as bytes.
      */
-    private static final class Bytes extends Uncompressed {
+    private static final class Bytes extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final ByteBuffer target;
 
@@ -192,7 +194,7 @@ abstract class Uncompressed extends Inflater {
      * Inflater for sample values stored as short integers.
      * This is a copy of {@link Bytes} implementation with only the type changed.
      */
-    private static final class Shorts extends Uncompressed {
+    private static final class Shorts extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final ShortBuffer target;
 
@@ -226,7 +228,7 @@ abstract class Uncompressed extends Inflater {
      * Inflater for sample values stored as 32 bits integers.
      * This is a copy of {@link Bytes} implementation with only the type changed.
      */
-    private static final class Ints extends Uncompressed {
+    private static final class Ints extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final IntBuffer target;
 
@@ -260,7 +262,7 @@ abstract class Uncompressed extends Inflater {
      * Inflater for sample values stored as long integers.
      * This is a copy of {@link Bytes} implementation with only the type changed.
      */
-    private static final class Longs extends Uncompressed {
+    private static final class Longs extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final LongBuffer target;
 
@@ -294,7 +296,7 @@ abstract class Uncompressed extends Inflater {
      * Inflater for sample values stored as single-precision floating point numbers.
      * This is a copy of {@link Bytes} implementation with only the type changed.
      */
-    private static final class Floats extends Uncompressed {
+    private static final class Floats extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final FloatBuffer target;
 
@@ -328,7 +330,7 @@ abstract class Uncompressed extends Inflater {
      * Inflater for sample values stored as double-precision floating point numbers.
      * This is a copy of {@link Bytes} implementation with only the type changed.
      */
-    private static final class Doubles extends Uncompressed {
+    private static final class Doubles extends CopyFromBytes {
         /** Where to copy the values that we will read. */
         private final DoubleBuffer target;
 
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
index 60ca503..6848964 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
@@ -108,8 +108,12 @@ public abstract class Inflater {
             final int elementsPerRow, final int samplesPerElement, final int[] skipAfterElements, final Buffer target)
     {
         switch (compression) {
-            case NONE: return Uncompressed.create(input, start, elementsPerRow, samplesPerElement, skipAfterElements, target);
-            default: return null;
+            case NONE: {
+                return CopyFromBytes.create(input, start, elementsPerRow, samplesPerElement, skipAfterElements, target);
+            }
+            default: {
+                return null;
+            }
         }
     }
 

[sis] 03/03: Ensure that the chunk size are not greater than buffer capacity.

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 65807794bed50185192a57480deed421e5bb0a6c
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Jul 31 21:45:45 2021 +0200

    Ensure that the chunk size are not greater than buffer capacity.
---
 .../apache/sis/internal/geotiff/CopyFromBytes.java |  2 +-
 .../org/apache/sis/internal/geotiff/Inflater.java  | 32 +++++++++--
 .../apache/sis/internal/geotiff/InflaterTest.java  | 64 ++++++++++++++++++++++
 .../apache/sis/test/suite/GeoTiffTestSuite.java    |  1 +
 4 files changed, 92 insertions(+), 7 deletions(-)

diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
index 4fe7a12..6287cb1 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/CopyFromBytes.java
@@ -65,7 +65,7 @@ abstract class CopyFromBytes extends Inflater {
     private CopyFromBytes(final ChannelDataInput input, final long start, final int elementsPerRow,
                          final int samplesPerElement, final int[] skipAfterElements, final int sampleSize)
     {
-        super(input, elementsPerRow, samplesPerElement, skipAfterElements);
+        super(input, elementsPerRow, samplesPerElement, skipAfterElements, input.buffer.capacity() / sampleSize);
         this.streamPosition = start;
         this.sampleSize = sampleSize;
     }
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
index 6848964..1f9d588 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
@@ -18,6 +18,9 @@ package org.apache.sis.internal.geotiff;
 
 import java.nio.Buffer;
 import java.io.IOException;
+import java.util.Arrays;
+import org.apache.sis.math.MathFunctions;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 
 import static org.apache.sis.util.ArgumentChecks.ensureStrictlyPositive;
@@ -72,11 +75,11 @@ public abstract class Inflater {
      * @param  elementsPerRow     number of elements (usually pixels) per row. Must be strictly positive.
      * @param  samplesPerElement  number of sample values per element (usually pixel). Must be strictly positive.
      * @param  skipAfterElements  number of sample values to skip between elements (pixels). May be empty or null.
+     * @param  maxChunkSize       maximal value (in number of elements) for the {@link #samplesPerChunk} field.
      */
-    protected Inflater(final ChannelDataInput input, final int elementsPerRow, final int samplesPerElement, final int[] skipAfterElements) {
-        ensureNonNull("input", input);
-        ensureStrictlyPositive("elementsPerRow",    elementsPerRow);
-        ensureStrictlyPositive("samplesPerElement", samplesPerElement);
+    protected Inflater(final ChannelDataInput input, final int elementsPerRow, final int samplesPerElement,
+                       final int[] skipAfterElements, final int maxChunkSize)
+    {
         this.input = input;
         skipAfterChunks = skipAfterElements;
         if (skipAfterElements != null) {
@@ -86,8 +89,22 @@ public abstract class Inflater {
             chunksPerRow    = elementsPerRow;
             samplesPerChunk = samplesPerElement;
         } else {
-            chunksPerRow    = 1;
-            samplesPerChunk = Math.multiplyExact(samplesPerElement, elementsPerRow);
+            int n = 1;
+            int s = Math.multiplyExact(samplesPerElement, elementsPerRow);
+            if (s > maxChunkSize) {
+                /*
+                 * We want the smallest divisor n ≥ s/maxChunkSize. Note that `i` is guaranteed
+                 * to be inside the array index range because the last array element is `s` and
+                 * the value that we search can not be greater.
+                 */
+                final int[] divisors = MathFunctions.divisors(s);
+                int i = Arrays.binarySearch(divisors, Numerics.ceilDiv(s, maxChunkSize));
+                if (i < 0) i = ~i;      // No need for array bound check.
+                n = divisors[i];
+                s /= n;
+            }
+            chunksPerRow    = n;
+            samplesPerChunk = s;
         }
     }
 
@@ -107,6 +124,9 @@ public abstract class Inflater {
     public static Inflater create(final Compression compression, final ChannelDataInput input, final long start,
             final int elementsPerRow, final int samplesPerElement, final int[] skipAfterElements, final Buffer target)
     {
+        ensureNonNull("input", input);
+        ensureStrictlyPositive("elementsPerRow",    elementsPerRow);
+        ensureStrictlyPositive("samplesPerElement", samplesPerElement);
         switch (compression) {
             case NONE: {
                 return CopyFromBytes.create(input, start, elementsPerRow, samplesPerElement, skipAfterElements, target);
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/InflaterTest.java b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/InflaterTest.java
new file mode 100644
index 0000000..0df80ca
--- /dev/null
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/InflaterTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.sis.internal.geotiff;
+
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests the {@link Inflater} class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since   0.8
+ * @module
+ */
+public final strictfp class InflaterTest extends TestCase {
+    /**
+     * Verifies that the inflater constructor makes sure to have a chunk size
+     * not greater than maximal buffer capacity.
+     */
+    @Test
+    public void testChunkSizeLimit() {
+        // With chunk size below size limit.
+        Mock inflater = new Mock(131, 5, null, 1000);
+        assertEquals(  1, inflater.chunksPerRow);
+        assertEquals(655, inflater.samplesPerChunk);
+        assertNull  (     inflater.skipAfterChunks);
+
+        // With chunk size above size limit.
+        inflater = new Mock(131, 5, null, 400);
+        assertEquals(  5, inflater.chunksPerRow);
+        assertEquals(131, inflater.samplesPerChunk);
+        assertNull  (     inflater.skipAfterChunks);
+    }
+
+    /**
+     * A dummy inflater implementation doing nothing.
+     */
+    private static final class Mock extends Inflater {
+        Mock(int elementsPerRow, int samplesPerElement, int[] skipAfterElements, int maxChunkSize) {
+            super(null, elementsPerRow, samplesPerElement, skipAfterElements, maxChunkSize);
+        }
+
+        @Override public void uncompressRow() {}
+        @Override public void skip(long n) {}
+    }
+}
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java b/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
index 2b92a07..9bc5e14 100644
--- a/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
@@ -31,6 +31,7 @@ import org.junit.BeforeClass;
  */
 @Suite.SuiteClasses({
     org.apache.sis.internal.geotiff.CompressionTest.class,
+    org.apache.sis.internal.geotiff.InflaterTest.class,
     org.apache.sis.storage.geotiff.TypeTest.class,
     org.apache.sis.storage.geotiff.GeoKeysTest.class,
     org.apache.sis.storage.geotiff.CRSBuilderTest.class,

[sis] 01/03: Move the `Compression` enumeration close to `Inflater`. It would allow sharing compression algorithms with other image formats in the future if needed.

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit e1b3d89d1ff703fc8695e4c6fb83ca813fc26021
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Jul 31 16:43:42 2021 +0200

    Move the `Compression` enumeration close to `Inflater`.
    It would allow sharing compression algorithms with other image formats in the future if needed.
---
 .../{storage => internal}/geotiff/Compression.java | 13 ++++++----
 .../org/apache/sis/internal/geotiff/Inflater.java  | 23 ++++++++++++++++++
 .../apache/sis/internal/geotiff/Uncompressed.java  |  2 +-
 .../sis/storage/geotiff/CompressedSubset.java      | 28 +++++++++++++++++-----
 .../org/apache/sis/storage/geotiff/DataCube.java   | 20 ++++++----------
 .../sis/storage/geotiff/ImageFileDirectory.java    |  1 +
 .../geotiff/CompressionTest.java                   |  6 ++---
 .../apache/sis/test/suite/GeoTiffTestSuite.java    |  2 +-
 8 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Compression.java
similarity index 93%
rename from storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
rename to storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Compression.java
index 74359c1..5217f96 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Compression.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Compression.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.geotiff;
+package org.apache.sis.internal.geotiff;
 
 
 /**
@@ -30,11 +30,11 @@ package org.apache.sis.storage.geotiff;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.1
  * @since   0.8
  * @module
  */
-enum Compression {
+public enum Compression {
     /**
      * No compression, but pack data into bytes as tightly as possible, leaving no unused bits except
      * potentially at the end of rows. The component values are stored as an array of type byte.
@@ -122,14 +122,17 @@ enum Compression {
     /**
      * Creates a new compression enumeration.
      */
-    Compression(final int code) {
+    private Compression(final int code) {
         this.code = code;
     }
 
     /**
      * Returns the compression method for the given GeoTIFF code, or {@code null} if none.
+     *
+     * @param  code  the TIFF code for which to get a compression enumeration value.
+     * @return enumeration value for the given code, or {@code null} if none.
      */
-    static Compression valueOf(final long code) {
+    public static Compression valueOf(final long code) {
         if ((code & ~0xFFFF) == 0) {                // Should be a short according TIFF specification.
             switch ((int) code) {
                 case 1:     return NONE;
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
index 9cd502f..60ca503 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Inflater.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.geotiff;
 
+import java.nio.Buffer;
 import java.io.IOException;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 
@@ -91,6 +92,28 @@ public abstract class Inflater {
     }
 
     /**
+     * Creates a new instance for the given compression.
+     * If the given method is unrecognized, then this method returns {@code null}.
+     *
+     * @param  compression        the compression method.
+     * @param  input              the source of data to decompress.
+     * @param  start              stream position where to start reading.
+     * @param  elementsPerRow     number of elements (usually pixels) per row. Must be strictly positive.
+     * @param  samplesPerElement  number of sample values per element (usually pixel). Must be strictly positive.
+     * @param  skipAfterElements  number of sample values to skip between elements (pixels). May be empty or null.
+     * @param  target             where to store sample values.
+     * @return the inflater for the given targe type, or {@code null} if the compression method is unknown.
+     */
+    public static Inflater create(final Compression compression, final ChannelDataInput input, final long start,
+            final int elementsPerRow, final int samplesPerElement, final int[] skipAfterElements, final Buffer target)
+    {
+        switch (compression) {
+            case NONE: return Uncompressed.create(input, start, elementsPerRow, samplesPerElement, skipAfterElements, target);
+            default: return null;
+        }
+    }
+
+    /**
      * Reads a row of sample values and stores them in the target buffer.
      * This is not a complete row; caller may invoke {@link #skip(long)}
      * for ignoring leading and trailing sample values.
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java
index 2486a90..faa815d 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Uncompressed.java
@@ -40,7 +40,7 @@ import org.apache.sis.util.Classes;
  * @since   1.1
  * @module
  */
-public abstract class Uncompressed extends Inflater {
+abstract class Uncompressed extends Inflater {
     /**
      * Stream position where to perform the next reading.
      */
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
index f49ed60..07d1a04 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
@@ -22,12 +22,14 @@ import java.io.IOException;
 import java.nio.Buffer;
 import org.apache.sis.internal.storage.TiledGridResource;
 import org.apache.sis.internal.coverage.j2d.RasterFactory;
-import org.apache.sis.internal.geotiff.Uncompressed;
+import org.apache.sis.internal.geotiff.Compression;
 import org.apache.sis.internal.geotiff.Inflater;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.image.DataType;
 
 import static java.lang.Math.toIntExact;
+import org.apache.sis.internal.geotiff.Resources;
 import static org.apache.sis.internal.jdk9.JDK9.multiplyFull;
 
 
@@ -41,6 +43,11 @@ import static org.apache.sis.internal.jdk9.JDK9.multiplyFull;
  */
 final class CompressedSubset extends DataSubset {
     /**
+     * The compression method.
+     */
+    private final Compression compression;
+
+    /**
      * Number of sample values to skip for moving to the next row of a tile in the GeoTIFF file.
      * This is not necessarily the same scanline stride than for the tiles created by this class.
      */
@@ -96,13 +103,17 @@ final class CompressedSubset extends DataSubset {
      * by {@link ImageFileDirectory#validateMandatoryTags()} before this call.
      * This constructor should be invoked inside a synchronized block.
      *
-     * @param  source   the resource which contain this {@code DataSubset}.
-     * @param  subset   description of the {@code owner} subset to cover.
-     * @param  rasters  potentially shared cache of rasters read by this {@code DataSubset}.
+     * @param  source       the resource which contain this {@code DataSubset}.
+     * @param  subset       description of the {@code owner} subset to cover.
+     * @param  rasters      potentially shared cache of rasters read by this {@code DataSubset}.
+     * @param  compression  the compression method.
      * @throws ArithmeticException if the number of tiles overflows 32 bits integer arithmetic.
      */
-    CompressedSubset(final DataCube source, final TiledGridResource.Subset subset) throws DataStoreException {
+    CompressedSubset(final DataCube source, final TiledGridResource.Subset subset, final Compression compression)
+            throws DataStoreException
+    {
         super(source, subset);
+        this.compression = compression;
         scanlineStride = multiplyFull(getTileSize(0), sourcePixelStride);
         final int between = sourcePixelStride * (getSubsampling(0) - 1);
         int afterLastBand = sourcePixelStride * (getTileSize(0) - 1);
@@ -202,7 +213,12 @@ final class CompressedSubset extends DataSubset {
         final Buffer[] banks = new Buffer[numBanks];
         for (int b=0; b<numBanks; b++) {
             final Buffer   bank = RasterFactory.createBuffer(type, capacity);
-            final Inflater algo = Uncompressed.create(reader().input, offsets[b], elementsPerRow, samplesPerElement, skipAfterElements, bank);
+            final Inflater algo = Inflater.create(compression, reader().input, offsets[b],
+                                    elementsPerRow, samplesPerElement, skipAfterElements, bank);
+            if (algo == null) {
+                throw new DataStoreContentException(reader().resources().getString(
+                        Resources.Keys.UnsupportedCompressionMethod_1, compression));
+            }
             for (long y = lower[1]; --y >= 0;) {
                 algo.skip(scanlineStride);
                 // TODO: after we finished to implement decompression algorithms,
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
index 1ecb856..d211a05 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
@@ -25,6 +25,7 @@ import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.internal.geotiff.Resources;
+import org.apache.sis.internal.geotiff.Compression;
 import org.apache.sis.internal.storage.TiledGridResource;
 import org.apache.sis.internal.storage.ResourceOnFileSystem;
 import org.apache.sis.util.resources.Errors;
@@ -140,19 +141,12 @@ abstract class DataCube extends TiledGridResource implements ResourceOnFileSyste
                     throw new DataStoreContentException(reader.resources().getString(
                             Resources.Keys.MissingValue_2, Tags.name(Tags.Compression)));
                 }
-                switch (compression) {
-                    case NONE: {
-                        if (subset.hasBandSubset() || (subset.hasSubsampling(0) && isInterleaved())) {
-                            coverage = new CompressedSubset(this, subset);
-                        } else {
-                            coverage = new DataSubset(this, subset);
-                        }
-                        break;
-                    }
-                    default: {
-                        throw new DataStoreContentException(reader.resources().getString(
-                                Resources.Keys.UnsupportedCompressionMethod_1, compression));
-                    }
+                if (compression != Compression.NONE || subset.hasBandSubset()
+                        || (subset.hasSubsampling(0) && isInterleaved()))
+                {
+                    coverage = new CompressedSubset(this, subset, compression);
+                } else {
+                    coverage = new DataSubset(this, subset);
                 }
                 coverage = preload(coverage);
             }
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index a14997b..c469dea 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -37,6 +37,7 @@ import org.opengis.util.FactoryException;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.geotiff.Resources;
+import org.apache.sis.internal.geotiff.Compression;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/CompressionTest.java
similarity index 92%
rename from storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
rename to storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/CompressionTest.java
index 6d89d73..7d22149 100644
--- a/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/CompressionTest.java
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/geotiff/CompressionTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.geotiff;
+package org.apache.sis.internal.geotiff;
 
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -23,10 +23,10 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests the {@link Compression} base class.
+ * Tests the {@link Compression} enumeration.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.1
  * @since   0.8
  * @module
  */
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java b/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
index 02c55ff..2b92a07 100644
--- a/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
@@ -30,8 +30,8 @@ import org.junit.BeforeClass;
  * @module
  */
 @Suite.SuiteClasses({
+    org.apache.sis.internal.geotiff.CompressionTest.class,
     org.apache.sis.storage.geotiff.TypeTest.class,
-    org.apache.sis.storage.geotiff.CompressionTest.class,
     org.apache.sis.storage.geotiff.GeoKeysTest.class,
     org.apache.sis.storage.geotiff.CRSBuilderTest.class,
     org.apache.sis.storage.geotiff.SelfConsistencyTest.class