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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 51fc2ddf3e Fix the writing of GeoTIFF planar image (banded sample 
model).
51fc2ddf3e is described below

commit 51fc2ddf3e4a92614252896adc732df5036c370d
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Oct 31 20:49:14 2023 +0100

    Fix the writing of GeoTIFF planar image (banded sample model).
---
 .../sis/storage/geotiff/writer/TileMatrix.java     | 33 +++-------
 .../apache/sis/io/stream/HyperRectangleWriter.java | 72 ++++++++++++++++++++--
 2 files changed, 74 insertions(+), 31 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java
index b4ee813e6a..1ddf9f6dee 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java
@@ -30,9 +30,6 @@ import java.awt.image.DataBufferInt;
 import java.awt.image.DataBufferFloat;
 import java.awt.image.DataBufferDouble;
 import java.awt.image.SampleModel;
-import java.awt.image.ComponentSampleModel;
-import java.awt.image.MultiPixelPackedSampleModel;
-import java.awt.image.SinglePixelPackedSampleModel;
 import org.apache.sis.image.DataType;
 import org.apache.sis.util.internal.Numerics;
 import org.apache.sis.io.stream.ChannelDataOutput;
@@ -219,6 +216,7 @@ public final class TileMatrix {
      * @throws DataStoreException if the compression method is unsupported.
      * @throws IOException if an error occurred while writing to the given 
output.
      */
+    @SuppressWarnings("null")
     public void writeRasters(final ChannelDataOutput output) throws 
DataStoreException, IOException {
         ChannelDataOutput compress = null;
         PixelChannel      cc       = null;
@@ -227,42 +225,28 @@ public final class TileMatrix {
         HyperRectangleWriter rect  = null;
         final int minTileX = image.getMinTileX();
         final int minTileY = image.getMinTileY();
-        int planeIndex = 0;
-        while (planeIndex < offsets.length) {
+        for (int tileIndex = 0; tileIndex < numTiles; tileIndex++) {
             /*
              * In current implementation, we iterate from left to right then 
top to bottom.
              * But a future version could use Hilbert iterator (for example).
              */
-            final int tileIndex = planeIndex / numPlanes;
             int tileX = tileIndex % numXTiles;
             int tileY = tileIndex / numXTiles;
             tileX += minTileX;
             tileY += minTileY;
             final Raster tile = image.getTile(tileX, tileY);
             if (sm != (sm = tile.getSampleModel())) {
-                rect = null;
                 final var builder = new 
HyperRectangleWriter.Builder().region(new Rectangle(tileWidth, tileHeight));
-                if (sm instanceof ComponentSampleModel) {
-                    final var csm = (ComponentSampleModel) sm;
-                    rect = builder.create(csm);
-                    bankIndices = csm.getBankIndices();
-                } else if (sm instanceof SinglePixelPackedSampleModel) {
-                    final var csm = (SinglePixelPackedSampleModel) sm;
-                    rect = builder.create(csm);
-                    bankIndices = new int[1];
-                } else if (sm instanceof MultiPixelPackedSampleModel) {
-                    final var csm = (MultiPixelPackedSampleModel) sm;
-                    rect = builder.create(csm);
-                    bankIndices = new int[1];
+                rect = builder.create(sm);
+                if (rect == null) {
+                    throw new UnsupportedOperationException();      // TODO: 
reformat using a recycled Raster.
                 }
+                bankIndices = builder.bankIndices();
                 if (compress == null) {
                     compress = createCompressionChannel(output, 
builder.pixelStride(), builder.scanlineStride());
                     if (compress != output) cc = (PixelChannel) 
compress.channel;
                 }
             }
-            if (rect == null) {
-                throw new UnsupportedOperationException();      // TODO: 
reformat using a recycled Raster.
-            }
             final DataBuffer buffer = tile.getDataBuffer();
             final int[] bufferOffsets = buffer.getOffsets();
             for (int j=0; j<numPlanes; j++) {
@@ -281,14 +265,11 @@ public final class TileMatrix {
                 if (cc != null) {
                     cc.finish(compress);
                 }
+                final int planeIndex = tileIndex + j*numTiles;
                 offsets[planeIndex] = position;
                 lengths[planeIndex] = 
Math.toIntExact(Math.subtractExact(output.getStreamPosition(), position));
-                planeIndex++;
             }
         }
         if (cc != null) cc.close();
-        if (planeIndex != offsets.length) {
-            throw new AssertionError();                 // Should never happen.
-        }
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleWriter.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleWriter.java
index 792b90e8ab..2e737fe89e 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleWriter.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleWriter.java
@@ -110,6 +110,15 @@ public final class HyperRectangleWriter {
          */
         private int scanlineStride;
 
+        /**
+         * The indices of all banks to write with {@code HyperRectangleWriter}.
+         * A length greater than one means that the {@link 
HyperRectangleWriter} instance
+         * created by this builder will need to be invoked repetitively for 
each bank.
+         *
+         * @see bankIndices()
+         */
+        private int[] bankIndices;
+
         /**
          * Subregion to write, or {@code null} for writing the whole raster.
          */
@@ -159,20 +168,43 @@ public final class HyperRectangleWriter {
          * This method supports only the writing of either a single band, or 
all bands
          * in the order they appear in the array.
          *
+         * <p>The returned writer will need to be applied repetitively for 
each bank
+         * if {@link #bankIndices()} returns an array with a length greater 
than one.</p>
+         *
          * @param  sm  the sample model of the rasters to write.
          * @return writer, or {@code null} if the given sample model is not 
supported.
          */
         public HyperRectangleWriter create(final ComponentSampleModel sm) {
             pixelStride    = sm.getPixelStride();
             scanlineStride = sm.getScanlineStride();
+            bankIndices    = sm.getBankIndices();
             final int[] d  = sm.getBandOffsets();
             final int subX;
-            if (d.length == pixelStride && ArraysExt.isRange(0, d)) {
-                subX = 1;
-            } else if (d.length == 1) {
-                subX = pixelStride;
+            if (ArraysExt.allEquals(bankIndices, bankIndices[0])) {
+                /*
+                 * PixelInterleavedSampleModel (at least conceptually, no 
matter the actual type).
+                 * The returned `HyperRectangleWriter` instance will write all 
sample values in a
+                 * single call to a `write(…)` method, no matter the actual 
number of bands.
+                 */
+                bankIndices = ArraysExt.resize(bankIndices, 1);
+                if (d.length == pixelStride && ArraysExt.isRange(0, d)) {
+                    subX = 1;
+                } else if (d.length == 1) {
+                    subX = pixelStride;
+                } else {
+                    return null;
+                }
             } else {
-                return null;
+                /*
+                 * BandedSampleModel (at least conceptually, no matter the 
actual type).
+                 * The returned `HyperRectangleWriter` instance will need to 
be used
+                 * repetitively by the caller.
+                 */
+                if (ArraysExt.allEquals(d, 0)) {
+                    subX = 1;
+                } else {
+                    return null;
+                }
             }
             return create(sm, subX);
         }
@@ -185,6 +217,7 @@ public final class HyperRectangleWriter {
          * @return writer, or {@code null} if the given sample model is not 
supported.
          */
         public HyperRectangleWriter create(final SinglePixelPackedSampleModel 
sm) {
+            bankIndices    = new int[1];   // Length is NOT the number of 
bands.
             pixelStride    = 1;
             scanlineStride = sm.getScanlineStride();
             final int[] d  = sm.getBitMasks();
@@ -205,6 +238,7 @@ public final class HyperRectangleWriter {
          * @return writer, or {@code null} if the given sample model is not 
supported.
          */
         public HyperRectangleWriter create(final MultiPixelPackedSampleModel 
sm) {
+            bankIndices    = new int[1];   // Length is NOT the number of 
bands.
             pixelStride    = 1;
             scanlineStride = sm.getScanlineStride();
             final int[] d  = sm.getSampleSize();
@@ -217,6 +251,21 @@ public final class HyperRectangleWriter {
             return null;
         }
 
+        /**
+         * Creates a new writer for raster data described by the given sample 
model.
+         * The returned writer will need to be applied repetitively for each 
bank
+         * if {@link #bankIndices()} returns an array with a length greater 
than one.
+         *
+         * @param  sm  the sample model of the rasters to write.
+         * @return writer, or {@code null} if the given sample model is not 
supported.
+         */
+        public HyperRectangleWriter create(final SampleModel sm) {
+            if (sm instanceof ComponentSampleModel)         return 
create((ComponentSampleModel)         sm);
+            if (sm instanceof SinglePixelPackedSampleModel) return 
create((SinglePixelPackedSampleModel) sm);
+            if (sm instanceof MultiPixelPackedSampleModel)  return 
create((MultiPixelPackedSampleModel)  sm);
+            return null;
+        }
+
         /**
          * {@return the number of elements (not necessarily bytes) between a 
pixel and the next pixel}.
          * This information is valid only after a {@code create(…)} method has 
been invoked.
@@ -232,6 +281,19 @@ public final class HyperRectangleWriter {
         public int scanlineStride() {
             return scanlineStride;
         }
+
+        /**
+         * Returns the indices of all banks to write with {@code 
HyperRectangleWriter}.
+         * This is not necessarily the bank indices of all bands, because the 
writer may be
+         * able to write all bands contiguously in a single call to a {@code 
write(…)} method.
+         * This information is valid only after a {@code create(…)} method has 
been invoked.
+         *
+         * @return indices of all banks to write with {@code 
HyperRectangleWriter}.
+         */
+        @SuppressWarnings("ReturnOfCollectionOrArrayField")
+        public int[] bankIndices() {
+            return bankIndices;
+        }
     }
 
     /**

Reply via email to