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 9de980b207e6647eb7908327524dc0e8a52ba792
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Thu Sep 12 19:15:16 2024 +0200

    Add a `int[] bands` argument to the `TiledGridResource.getSampleModel(…)` 
and `getColorModel(…)` methods.
    It allows some data stores to perform a better work than the default band 
selection mechanism.
    This is useful with the GDAL model of bands.
---
 .../sis/coverage/privy/ColorModelFactory.java      |   2 +-
 .../apache/sis/coverage/privy/RangeArgument.java   |   2 -
 .../org/apache/sis/storage/geotiff/DataCube.java   |   6 +-
 .../sis/storage/geotiff/ImageFileDirectory.java    |  22 ++--
 .../apache/sis/storage/base/TiledGridResource.java | 144 +++++++++++++++++----
 .../org/apache/sis/storage/gdal/TiledResource.java |  61 ++++++---
 .../storage/gimi/internal/MatrixGridRessource.java |  10 +-
 7 files changed, 183 insertions(+), 64 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/ColorModelFactory.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/ColorModelFactory.java
index e1a22790e1..2f9750f88b 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/ColorModelFactory.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/ColorModelFactory.java
@@ -505,7 +505,7 @@ public final class ColorModelFactory {
             cm = new ComponentColorModel(cs, false, true, Transparency.OPAQUE, 
dataType);
             // Note: `ComponentColorModel` does not work well with negative 
values.
         } else {
-            final ScaledColorSpace cs = new ScaledColorSpace(numComponents, 
visibleBand, minimum, maximum);
+            final var cs = new ScaledColorSpace(numComponents, visibleBand, 
minimum, maximum);
             cm = new ScaledColorModel(cs, dataType);
         }
         return unique(cm);
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/RangeArgument.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/RangeArgument.java
index 3fdd7ba79b..4c152d901c 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/RangeArgument.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/privy/RangeArgument.java
@@ -24,8 +24,6 @@ import java.awt.image.RasterFormatException;
 import org.opengis.metadata.spatial.DimensionNameType;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridExtent;
-import org.apache.sis.coverage.privy.ColorModelFactory;
-import org.apache.sis.coverage.privy.SampleModelFactory;
 import org.apache.sis.feature.internal.Resources;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ArraysExt;
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java
index bb7ff44fce..2891c0400f 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java
@@ -121,10 +121,10 @@ abstract class DataCube extends TiledGridResource 
implements ResourceOnFileSyste
 
     /**
      * Returns the number of components per pixel in the image stored in 
GeoTIFF file.
-     * This the same value as the one returned by {@code 
getSampleModel().getNumBands()},
+     * This the same value as the one returned by {@code 
getSampleModel(null).getNumBands()},
      * and is also the size of the collection returned by {@link 
#getSampleDimensions()}.
      *
-     * @see #getSampleModel()
+     * @see #getSampleModel(int[])
      * @see SampleModel#getNumBands()
      */
     abstract int getNumBands();
@@ -201,7 +201,7 @@ abstract class DataCube extends TiledGridResource 
implements ResourceOnFileSyste
      *       a multiple of 8.
      */
     private boolean canReadDirect(final Subset subset) throws 
DataStoreException {
-        final SampleModel model = getSampleModel();
+        final SampleModel model = getSampleModel(null);
         int b = model.getNumBands();
         if (b != 1 && !(model instanceof BandedSampleModel)) {              // 
First condition (see Javadoc).
             if (!subset.isXContiguous()) {                                  // 
Exception to first consition.
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index 723f16516e..582b560f27 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -425,14 +425,14 @@ final class ImageFileDirectory extends DataCube {
      * The image sample model, created when first needed. The raster size is 
the tile size.
      * Sample models with different size and number of bands can be derived 
from this model.
      *
-     * @see #getSampleModel()
+     * @see #getSampleModel(int[])
      */
     private SampleModel sampleModel;
 
     /**
      * The image color model, created when first needed.
      *
-     * @see #getColorModel()
+     * @see #getColorModel(int[])
      */
     private ColorModel colorModel;
 
@@ -1592,12 +1592,15 @@ final class ImageFileDirectory extends DataCube {
      *
      * @see SampleModel#createCompatibleSampleModel(int, int)
      * @see SampleModel#createSubsetSampleModel(int[])
-     * @see #getColorModel()
+     * @see #getColorModel(int[])
      * @see #getTileSize()
      */
     @Override
-    protected SampleModel getSampleModel() throws DataStoreContentException {
+    protected SampleModel getSampleModel(final int[] bands) throws 
DataStoreContentException {
         assert Thread.holdsLock(getSynchronizationLock());
+        if (bands != null) {
+            return null;    // Let `TileGridResource` derive a model itself.
+        }
         if (sampleModel == null) {
             RuntimeException error = null;
             final DataType type = getDataType();
@@ -1637,7 +1640,7 @@ final class ImageFileDirectory extends DataCube {
      * The number of dimensions is always 2 for {@code ImageFileDirectory}.
      *
      * @see #getExtent()
-     * @see #getSampleModel()
+     * @see #getSampleModel(int[])
      */
     @Override
     protected int[] getTileSize() {
@@ -1690,13 +1693,16 @@ final class ImageFileDirectory extends DataCube {
      *
      * @throws DataStoreContentException if the data type is not supported.
      *
-     * @see #getSampleModel()
+     * @see #getSampleModel(int[])
      */
     @Override
-    protected ColorModel getColorModel() throws DataStoreContentException {
+    protected ColorModel getColorModel(final int[] bands) throws 
DataStoreContentException {
         assert Thread.holdsLock(getSynchronizationLock());
+        if (bands != null) {
+            return null;    // Let `TileGridResource` derive a model itself.
+        }
         if (colorModel == null) {
-            final SampleModel sm  = getSampleModel();
+            final SampleModel sm  = getSampleModel(null);
             final int dataType    = sm.getDataType();
             final int visibleBand = 0;      // May be configurable in a future 
version.
             short missing = 0;              // Non-zero if there is a warning 
about missing information.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
index 74128e6099..47cf1469e5 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
@@ -18,6 +18,7 @@ package org.apache.sis.storage.base;
 
 import java.util.List;
 import java.util.Arrays;
+import java.util.Objects;
 import java.awt.image.DataBuffer;
 import java.awt.image.ColorModel;
 import java.awt.image.SampleModel;
@@ -33,12 +34,14 @@ import org.apache.sis.coverage.grid.GridDerivation;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridRoundingMode;
+import org.apache.sis.coverage.privy.ColorModelFactory;
 import org.apache.sis.coverage.privy.RangeArgument;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.AbstractGridCoverageResource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.RasterLoadingStrategy;
 import org.apache.sis.storage.event.StoreListeners;
+import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.collection.WeakValueHashMap;
 import static org.apache.sis.storage.base.TiledGridCoverage.X_DIMENSION;
@@ -52,6 +55,29 @@ import org.opengis.coverage.CannotEvaluateException;
  * Base class of grid coverage resource storing data in tiles.
  * The word "tile" is used for simplicity but can be understood
  * as "chunk" in a <var>n</var>-dimensional generalization.
+ * Subclasses need to implement the following methods:
+ *
+ * <ul>
+ *   <li>{@link #getGridGeometry()}</li>
+ *   <li>{@link #getSampleDimensions()}</li>
+ *   <li>{@link #getTileSize()}</li>
+ *   <li>{@link #getSampleModel(int[])} (optional but recommended)</li>
+ *   <li>{@link #getColorModel(int[])} (optional but recommended)</li>
+ *   <li>{@link #read(GridGeometry, int...)}</li>
+ * </ul>
+ *
+ * The read method can be implemented simply as below:
+ *
+ * {@snippet lang="java" :
+ *     @Override
+ *     public GridCoverage read(GridGeometry domain, int... ranges) throws 
DataStoreException {
+ *         synchronized (getSynchronizationLock()) {
+ *             var subset = new Subset(domain, ranges);
+ *             var result = new MySubclassOfTiledGridCoverage(this, subset);
+ *             return preload(result);
+ *         }
+ *     }
+ *     }
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -141,7 +167,7 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
 
     /**
      * Returns the size of tiles in this resource.
-     * The length of the returned array is the number of dimensions.
+     * The length of the returned array is the number of dimensions, which 
must be 2 or more.
      *
      * @return the size of tiles (in pixels) in this resource.
      * @throws DataStoreException if an error occurred while fetching the tile 
size.
@@ -166,7 +192,7 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
      * @throws DataStoreException if an error occurred while fetching the 
sample model.
      */
     protected int getAtomSize(final int dim) throws DataStoreException {
-        return (dim == 0) ? 
TiledGridCoverage.getPixelsPerElement(getSampleModel()) : 1;
+        return (dim == 0) ? 
TiledGridCoverage.getPixelsPerElement(getSampleModel(null)) : 1;
     }
 
     /**
@@ -176,7 +202,7 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
      *
      * <ul class="verbose">
      *   <li>If {@code false}, then {@link TiledGridCoverage#model} will 
expect the same {@link DataBuffer}
-     *       than the one expected by the {@linkplain #getSampleModel() sample 
model of this resource}.
+     *       than the one expected by the {@linkplain #getSampleModel(int[]) 
sample model of this resource}.
      *       All bands will be loaded but the coverage sample model will 
ignore the bands that were not
      *       enumerated in the {@code range} argument. This strategy is 
convenient when skipping bands
      *       at reading time is difficult.</li>
@@ -197,33 +223,86 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
      * @see RangeArgument#select(SampleModel, boolean)
      */
     protected boolean getDissociableBands() throws DataStoreException {
-        return getSampleModel() instanceof ComponentSampleModel;
+        return getSampleModel(null) instanceof ComponentSampleModel;
     }
 
     /**
-     * Returns the Java2D sample model describing pixel type and layout for 
all bands.
-     * The raster size is the {@linkplain #getTileSize() tile size} as stored 
in the resource.
+     * Returns the Java2D sample model describing pixel type and layout for 
the specified bands.
+     * The raster size shall be the two first dimensions of the {@linkplain 
#getTileSize() tile size}.
+     * This is the size of tiles as stored in the resource, i.e. ignoring 
sub-sampling.
+     *
+     * <p>If the {@code bands} argument is {@code null}, then this method 
<em>shall</em> return the sample model
+     * for all bands and cannot return {@code null}. If the {@code bands} 
argument is non-null, then this method
+     * <em>may</em> compute the sample model for the specified bands, or 
return {@code null} for instructing the
+     * caller to derive the sample model from {@code getSampleModel(null)}.</p>
      *
-     * <h4>Multi-dimensional data cube</h4>
-     * If this resource has more than 2 dimensions, then this model is for the 
two first ones (usually horizontal).
-     * The images for all levels in additional dimensions shall use the same 
sample model.
+     * <h4>Implementation note</h4>
+     * The default implementation creates a sample model compatible with the 
{@linkplain #getColorModel(int[])
+     * color model} if available, or otherwise defaults to a {@link 
BandedSampleModel} which stores samples as
+     * floating point values. This is okay for prototyping, but it is 
recommended to override this method with
+     * a simple model that better matches the data. A simple implementation 
can be as below:
      *
-     * <h4>Performance note</h4>
-     * Implementation should return a cached value, because this method may be 
invoked many times.
+     * {@snippet lang="java" :
+     *     private SampleModel sampleModel;
      *
-     * @return the sample model for tiles at full resolution with all their 
bands.
+     *     @Override
+     *     protected SampleModel getSampleModel(int[] bands) throws 
DataStoreException {
+     *         if (bands != null) {
+     *             return null;
+     *         }
+     *         synchronized (getSynchronizationLock()) {
+     *             if (sampleModel == null) {
+     *                 sampleModel = ...;   // Compute and cache, because 
requested many times.
+     *             }
+     *             return sampleModel;
+     *         }
+     *     }
+     *     }
+     *
+     * @param  bands  indices (not necessarily in increasing order) of desired 
bands, or {@code null} for all bands.
+     * @return the sample model for tiles at full resolution with the 
specified bands.
+     *         Shall be non-null if {@code bands} is null (i.e. the caller is 
requesting the main sample model).
      * @throws DataStoreException if an error occurred during sample model 
construction.
      */
-    protected abstract SampleModel getSampleModel() throws DataStoreException;
+    protected SampleModel getSampleModel(final int[] bands) throws 
DataStoreException {
+        final int[] tileSize = getTileSize();
+        final int width  = tileSize[X_DIMENSION];
+        final int height = tileSize[Y_DIMENSION];
+        final ColorModel colors = getColorModel(bands);
+        if (colors != null) {
+            return colors.createCompatibleSampleModel(width, height);
+        }
+        int numBands = (bands != null) ? bands.length : 
getSampleDimensions().size();
+        return new BandedSampleModel(DataBuffer.TYPE_FLOAT, width, height, 
numBands);
+    }
 
     /**
      * Returns the Java2D color model for rendering images, or {@code null} if 
none.
-     * The color model shall be compatible with the sample model returned by 
{@link #getSampleModel()}.
+     * The color model shall be compatible with the sample model returned by 
{@link #getSampleModel(int[])}.
+     *
+     * <p>The default implementation returns a gray scale color model if there 
is only one band
+     * to show and the range of the {@linkplain #getSampleDimensions() sample 
dimension} is known.
+     * OTherwise, this method returns {@code null}.
+     * This is okay for prototyping, but it is recommended to override.</p>
      *
-     * @return a color model compatible with {@link #getSampleModel()}, or 
{@code null} if none.
+     * @param  bands  indices (not necessarily in increasing order) of desired 
bands, or {@code null} for all bands.
+     * @return a color model compatible with {@link #getSampleModel(int[])}, 
or {@code null} if none.
      * @throws DataStoreException if an error occurred during color model 
construction.
      */
-    protected abstract ColorModel getColorModel() throws DataStoreException;
+    protected ColorModel getColorModel(final int[] bands) throws 
DataStoreException {
+        final List<SampleDimension> sd = getSampleDimensions();
+        if ((bands != null && bands.length == 1) || sd.size() == 1) {
+            NumberRange<?> range = sd.get((bands != null) ? bands[0] : 
0).getSampleRange().orElse(null);
+            if (range != null) {
+                final double min = range.getMinDouble();
+                final double max = range.getMaxDouble();
+                if (Double.isFinite(min) && Double.isFinite(max)) {
+                    return 
ColorModelFactory.createGrayScale(DataBuffer.TYPE_FLOAT, 1, 0, min, max);
+                }
+            }
+        }
+        return null;
+    }
 
     /**
      * Returns the value to use for filling empty spaces in rasters,
@@ -400,30 +479,39 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
              * If user has specified bands in a different order, that change 
of band order will
              * be handled by the `SampleModel`, not in `includedBands` array.
              */
-            @SuppressWarnings("LocalVariableHidesMemberVariable")
-            int[] includedBands = null;
+            @SuppressWarnings("LocalVariableHidesMemberVariable") int[]       
includedBands       = null;
+            @SuppressWarnings("LocalVariableHidesMemberVariable") SampleModel 
modelForBandSubset  = null;
+            @SuppressWarnings("LocalVariableHidesMemberVariable") ColorModel  
colorsForBandSubset = null;
             boolean loadAllBands = rangeIndices.isIdentity();
             if (!loadAllBands) {
                 bands = Arrays.asList(rangeIndices.select(bands));
                 loadAllBands = !getDissociableBands();
                 if (!loadAllBands) {
                     sharedCache = false;
-                    includedBands = new int[rangeIndices.getNumBands()];
-                    for (int i=0; i<includedBands.length; i++) {
-                        includedBands[i] = rangeIndices.getSourceIndex(i);
-                    }
-                    assert ArraysExt.isSorted(includedBands, true);
-                    if (rangeIndices.hasAllBands) {
-                        assert ArraysExt.isRange(0, includedBands);
-                        includedBands = null;
+                    if (!rangeIndices.hasAllBands) {
+                        includedBands = new int[rangeIndices.getNumBands()];
+                        for (int i=0; i<includedBands.length; i++) {
+                            includedBands[i] = rangeIndices.getSourceIndex(i);
+                        }
+                        assert ArraysExt.isSorted(includedBands, true);
                     }
+                    // Same as `includedBands`, but in the order requested by 
the user.
+                    int[] requestedBands = rangeIndices.getSelectedBands();
+                    modelForBandSubset   = getSampleModel(requestedBands);
+                    colorsForBandSubset  = getColorModel (requestedBands);
                 }
             }
+            if (modelForBandSubset == null) {
+                modelForBandSubset = rangeIndices.select(getSampleModel(null), 
loadAllBands);
+            }
+            if (colorsForBandSubset == null) {
+                colorsForBandSubset = rangeIndices.select(getColorModel(null));
+            }
             this.domain              = domain;
             this.ranges              = bands;
             this.includedBands       = includedBands;
-            this.modelForBandSubset  = rangeIndices.select(getSampleModel(), 
loadAllBands);
-            this.colorsForBandSubset = rangeIndices.select(getColorModel());
+            this.modelForBandSubset  = 
Objects.requireNonNull(modelForBandSubset);
+            this.colorsForBandSubset = colorsForBandSubset;
             this.fillValue           = getFillValue();
             /*
              * All `TiledGridCoverage` instances can share the same cache if 
they read all tiles fully.
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
index 5c3a576b84..3025ab2255 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
@@ -18,6 +18,7 @@ package org.apache.sis.storage.gdal;
 
 import java.util.Map;
 import java.util.List;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.Optional;
@@ -104,17 +105,25 @@ final class TiledResource extends TiledGridResource {
     private List<SampleDimension> sampleDimensions;
 
     /**
-     * The color model, created when first requested.
+     * Indices of the {@linkplain #bands} selected for creating {@link 
#colorModel} and {@link #sampleModel}.
+     * A null value means that all bands are used.
+     */
+    private int[] selectedBandIndices;
+
+    /**
+     * The color model for the bands specified by {@link 
#selectedBandIndices}, created when first requested.
+     * This model is recreated when {@link #selectedBandIndices} changed.
      *
-     * @see #getColorModel()
+     * @see #getColorModel(int[])
      */
     private ColorModel colorModel;
 
     /**
-     * The sample model, created when first requested.
-     * Its size is the tile size with no sub-sampling.
+     * The sample model for the bands specified by {@link 
#selectedBandIndices}, created when first requested.
+     * All sample models shall have the size of the tile size with no 
sub-sampling.
+     * This model is recreated when {@link #selectedBandIndices} changed.
      *
-     * @see #getSampleModel()
+     * @see #getSampleModel(int[])
      */
     private SampleModel sampleModel;
 
@@ -334,14 +343,25 @@ final class TiledResource extends TiledGridResource {
 
     /**
      * Creates the color model and sample model.
+     *
+     * @param  bandIndices  indices of the selected bands.
      */
-    private void createColorAndSampleModel() throws DataStoreException {
+    private void createColorAndSampleModel(final int[] bandIndices) throws 
DataStoreException {
+        final Band[] selectedBands;
+        if (bandIndices == null) {
+            selectedBands = bands;
+        } else {
+            selectedBands = new Band[bandIndices.length];
+            for (int i=0; i<bandIndices.length; i++) {
+                selectedBands[i] = bands[bandIndices[i]];
+            }
+        }
         final GDAL gdal = parent.getProvider().GDAL();
         int[] palette = null;
         int paletteIndex = 0;
         int alpha = -1, red = -1, green = -1, blue = -1, gray = -1;
-        for (int i=0; i < bands.length; i++) {
-            final Band band = bands[i];
+        for (int i=0; i < selectedBands.length; i++) {
+            final Band band = selectedBands[i];
             switch (band.getColorInterpretation(gdal)) {
                 case ALPHA:     if (alpha < 0) alpha = i; break;
                 case RED:       if (red   < 0) red   = i; break;
@@ -370,15 +390,15 @@ final class TiledResource extends TiledGridResource {
             // TODO: needs custom color model if too many bands, or if order 
is not (A)RGB.
         } else if (palette != null) {
             visibleBand = paletteIndex;
-            colorModel = ColorModelFactory.createIndexColorModel(bands.length, 
visibleBand, palette, true, -1);
+            colorModel = 
ColorModelFactory.createIndexColorModel(selectedBands.length, visibleBand, 
palette, true, -1);
         } else {
             visibleBand = Math.max(gray, 0);
-            final Band band = bands[visibleBand];
+            final Band band = selectedBands[visibleBand];
             final double min = band.getValue(gdal.getRasterMinimum, 
MemorySegment.NULL);
             final double max = band.getValue(gdal.getRasterMaximum, 
MemorySegment.NULL);
-            colorModel = ColorModelFactory.createGrayScale(dataType.imageType, 
bands.length, visibleBand, min, max);
+            colorModel = ColorModelFactory.createGrayScale(dataType.imageType, 
selectedBands.length, visibleBand, min, max);
         }
-        sampleModel = new BandedSampleModel(dataType.imageType, width, height, 
bands.length);
+        sampleModel = new BandedSampleModel(dataType.imageType, width, height, 
selectedBands.length);
         /*
          * Also compute the fill value here because the current method needs 
the visible band.
          * TODO: we should compute the fill value for all bands instead, and 
move this code to
@@ -386,21 +406,22 @@ final class TiledResource extends TiledGridResource {
          */
         try (final Arena arena = Arena.ofConfined()) {
             final MemorySegment flag = arena.allocate(ValueLayout.JAVA_INT);
-            final double value = 
bands[visibleBand].getValue(gdal.getRasterNoDataValue, flag);
+            final double value = 
selectedBands[visibleBand].getValue(gdal.getRasterNoDataValue, flag);
             if (value != 0 && Band.isTrue(flag)) {
                 fillValue = value;
             }
         }
+        selectedBandIndices = bandIndices;
     }
 
     /**
      * Returns the Java2D color model for rendering images.
      */
     @Override
-    protected ColorModel getColorModel() throws DataStoreException {
+    protected ColorModel getColorModel(final int[] bandIndices) throws 
DataStoreException {
         synchronized (getSynchronizationLock()) {
-            if (colorModel == null) {
-                createColorAndSampleModel();
+            if (colorModel == null || !Arrays.equals(bandIndices, 
selectedBandIndices)) {
+                createColorAndSampleModel(bandIndices);
             }
             return colorModel;
         }
@@ -411,10 +432,10 @@ final class TiledResource extends TiledGridResource {
      * The raster size is the {@linkplain #getTileSize() tile size} as stored 
in the resource.
      */
     @Override
-    protected SampleModel getSampleModel() throws DataStoreException {
+    protected SampleModel getSampleModel(final int[] bandIndices) throws 
DataStoreException {
         synchronized (getSynchronizationLock()) {
-            if (sampleModel == null) {
-                createColorAndSampleModel();
+            if (sampleModel == null || !Arrays.equals(bandIndices, 
selectedBandIndices)) {
+                createColorAndSampleModel(bandIndices);
             }
             return sampleModel;
         }
@@ -429,7 +450,7 @@ final class TiledResource extends TiledGridResource {
     protected Number getFillValue() throws DataStoreException {
         synchronized (getSynchronizationLock()) {
             if (fillValue == null) {
-                createColorAndSampleModel();
+                createColorAndSampleModel(null);
             }
             return fillValue;
         }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/MatrixGridRessource.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/MatrixGridRessource.java
index d65b4b0eaf..be0abc9bca 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/MatrixGridRessource.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/MatrixGridRessource.java
@@ -67,13 +67,19 @@ public abstract class MatrixGridRessource extends 
TiledGridResource {
     }
 
     @Override
-    protected SampleModel getSampleModel() throws DataStoreException {
+    protected SampleModel getSampleModel(int[] bands) throws 
DataStoreException {
+        if (bands != null) {
+            return null;
+        }
         initialize();
         return sampleModel;
     }
 
     @Override
-    protected ColorModel getColorModel() throws DataStoreException {
+    protected ColorModel getColorModel(int[] bands) throws DataStoreException {
+        if (bands != null) {
+            return null;
+        }
         initialize();
         return colorModel;
     }

Reply via email to