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 2020/06/27 12:54:49 UTC
[sis] branch geoapi-4.0 updated: Add a PlanarImage.MASK_KEY
property providing a mask over missing values.
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 acea035 Add a PlanarImage.MASK_KEY property providing a mask over missing values.
acea035 is described below
commit acea0356c352c92edf29e5971040a8f0b66b3e23
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Jun 27 14:47:39 2020 +0200
Add a PlanarImage.MASK_KEY property providing a mask over missing values.
---
.../java/org/apache/sis/image/ComputedImage.java | 8 ++
.../main/java/org/apache/sis/image/MaskImage.java | 109 +++++++++++++++++++
.../java/org/apache/sis/image/PlanarImage.java | 17 +++
.../sis/image/PositionalConsistencyImage.java | 108 ++++++-------------
.../java/org/apache/sis/image/ResampledImage.java | 49 ++++++---
.../org/apache/sis/image/SourceAlignedImage.java | 115 +++++++++++++++++++++
.../internal/coverage/j2d/ColorModelFactory.java | 2 +-
.../coverage/j2d/MultiBandsIndexColorModel.java | 15 ++-
8 files changed, 328 insertions(+), 95 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java
index f95b244..d64193b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java
@@ -245,6 +245,14 @@ public abstract class ComputedImage extends PlanarImage implements Disposable {
}
/**
+ * Returns the source at index 0 without any check. This method is invoked by subclasses who know that a
+ * single source exist. This method should not be in public API because of the absence of verification.
+ */
+ final RenderedImage getSource() {
+ return sources[0];
+ }
+
+ /**
* Returns the immediate sources of image data for this image (may be {@code null}).
* This method returns all sources specified at construction time.
*
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/MaskImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/MaskImage.java
new file mode 100644
index 0000000..17e0366
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/MaskImage.java
@@ -0,0 +1,109 @@
+/*
+ * 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.image;
+
+import java.util.Set;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
+import org.apache.sis.internal.coverage.j2d.ImageUtilities;
+import org.apache.sis.internal.jdk9.JDK9;
+
+
+/**
+ * Mask of missing values.
+ * This is the implementation of {@link ResampledImage#MASK_KEY} property value.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ * @module
+ */
+final class MaskImage extends SourceAlignedImage {
+ /**
+ * Properties inherited from the source image. Must be consistent with the <cite>switch case</cite>
+ * statement delegating to the source image in {@link #getProperty(String)}.
+ *
+ * @see #getPropertyNames()
+ */
+ private static final Set<String> INHERITED_PROPERTIES = JDK9.setOf(
+ GRID_GEOMETRY_KEY, POSITIONAL_ACCURACY_KEY, ResampledImage.POSITIONAL_CONSISTENCY_KEY);
+
+ /**
+ * Creates a new instance for the given image.
+ */
+ MaskImage(final ResampledImage image) {
+ super(image, ColorModelFactory.createIndexColorModel(new int[] {0, -1},
+ image.getSampleModel().getNumBands(), ImageUtilities.getVisibleBand(image), 0));
+ }
+
+ /**
+ * Gets a property from this image.
+ */
+ @Override
+ public Object getProperty(final String key) {
+ return INHERITED_PROPERTIES.contains(key) ? getSource().getProperty(key) : super.getProperty(key);
+ }
+
+ /**
+ * Returns the names of all recognized properties.
+ *
+ * @return names of all recognized properties, or {@code null} if none.
+ */
+ @Override
+ public String[] getPropertyNames() {
+ return getPropertyNames(INHERITED_PROPERTIES, null);
+ }
+
+ /**
+ * Invoked when a tile need to be computed or updated.
+ *
+ * @param tileX the column index of the tile to compute.
+ * @param tileY the row index of the tile to compute.
+ * @param tile if the tile already exists but needs to be updated, the tile to update. Otherwise {@code null}.
+ * @return computed tile for the given indices.
+ * @throws TransformException if an error occurred while computing pixel coordinates.
+ */
+ @Override
+ protected Raster computeTile(final int tileX, final int tileY, WritableRaster tile) throws TransformException {
+ final Raster source = getSource().getTile(tileX, tileY);
+ if (tile == null) {
+ tile = createTile(tileX, tileY);
+ }
+ final int tileMinX = tile.getMinX();
+ final int tileMinY = tile.getMinY();
+ final int tileMaxX = Math.addExact(tileMinX, tile.getWidth());
+ final int tileMaxY = Math.addExact(tileMinY, tile.getHeight());
+ final int[] pixel = new int[tile.getNumBands()];
+ float[] values = null;
+ /*
+ * Following algorithm is inefficient; it would be much faster to read or write directly in the arrays.
+ * But it may not be worth to optimize it for now.
+ */
+ for (int y=tileMinY; y<tileMaxY; y++) {
+ for (int x=tileMinX; x<tileMaxX; x++) {
+ values = source.getPixel(x, y, values);
+ for (int i=0; i<pixel.length; i++) {
+ pixel[i] = Float.isNaN(values[i]) ? 1 : 0;
+ }
+ tile.setPixel(x, y, pixel);
+ }
+ }
+ return tile;
+ }
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
index 5ea8970..2646114 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
@@ -172,6 +172,20 @@ public abstract class PlanarImage implements RenderedImage {
public static final String STATISTICS_KEY = "org.apache.sis.Statistics";
/**
+ * Key of property providing a mask for missing values. Values should be instances of {@link RenderedImage}
+ * with binary sample values and a color model of {@link java.awt.Transparency#BITMASK} type.
+ * The binary values 0 and 1 are alpha values: 0 for fully transparent pixels and 1 for fully opaque pixels.
+ * For every pixel (<var>x</var>,<var>y</var>) in this image, the pixel at the same coordinates in the mask
+ * is either fully transparent (sample value 0) if the sample value in this image is valid, or fully opaque
+ * (sample value 1) if the sample value in this image is invalid ({@link Float#NaN}).
+ *
+ * <p>Note that it is usually not necessary to use masks explicitly in Apache SIS because missing values
+ * are represented by {@link Float#NaN}. This property is provided for algorithms that can not work with
+ * NaN values.</p>
+ */
+ public static final String MASK_KEY = "org.apache.sis.Mask";
+
+ /**
* Creates a new rendered image.
*/
protected PlanarImage() {
@@ -216,6 +230,9 @@ public abstract class PlanarImage implements RenderedImage {
* <td>{@value #STATISTICS_KEY}</td>
* <td>Minimum, maximum and mean values for each band.</td>
* </tr><tr>
+ * <td>{@value #MASK_KEY}</td>
+ * <td>Image with transparent pixels at locations of valid values and opaque pixels elsewhere.</td>
+ * </tr><tr>
* <td>{@value ResampledImage#POSITIONAL_CONSISTENCY_KEY}</td>
* <td>Estimation of positional error for each pixel as a consistency check.</td>
* </tr><tr>
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/PositionalConsistencyImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/PositionalConsistencyImage.java
index 24ffd5d..77f2596 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/PositionalConsistencyImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/PositionalConsistencyImage.java
@@ -16,16 +16,14 @@
*/
package org.apache.sis.image;
-import java.awt.image.ColorModel;
+import java.util.Set;
import java.awt.image.DataBuffer;
-import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
-import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
-import org.apache.sis.util.Workaround;
+import org.apache.sis.internal.jdk9.JDK9;
/**
@@ -37,17 +35,23 @@ import org.apache.sis.util.Workaround;
* @since 1.1
* @module
*/
-final class PositionalConsistencyImage extends ComputedImage {
+final class PositionalConsistencyImage extends SourceAlignedImage {
/**
- * The color model for this image.
- * Arbitrarily configured for an error range from 0 to 1.
+ * Properties inherited from the source image. Must be consistent with the <cite>switch case</cite>
+ * statement delegating to the source image in {@link #getProperty(String)}.
+ *
+ * @see #getPropertyNames()
*/
- private final ColorModel colorModel;
+ private static final Set<String> INHERITED_PROPERTIES = JDK9.setOf(
+ GRID_GEOMETRY_KEY, POSITIONAL_ACCURACY_KEY, MASK_KEY);
/**
- * Domain of pixel coordinates in this image.
+ * Properties added by this image, no matter if present in source image or not. Must be consistent with
+ * the <cite>switch case</cite> statement doing its own calculation in {@link #getProperty(String)}.
+ *
+ * @see #getPropertyNames()
*/
- private final int minX, minY, width, height;
+ private static final String[] ADDED_PROPERTIES = {SAMPLE_RESOLUTIONS_KEY};
/**
* A copy of {@link ResampledImage#toSourceSupport} with the support translation removed.
@@ -67,48 +71,28 @@ final class PositionalConsistencyImage extends ComputedImage {
* Creates a new instance for the given image.
*/
PositionalConsistencyImage(final ResampledImage image, final MathTransform toSource) throws TransformException {
- super(createSampleModel(image.getSampleModel()), image);
+ super(image, ColorModelFactory.createGrayScale(DataBuffer.TYPE_FLOAT, 1, 0, 0, 1));
this.toSource = toSource;
this.toTarget = image.toSource.inverse();
- this.minX = image.getMinX();
- this.minY = image.getMinY();
- this.width = image.getWidth();
- this.height = image.getHeight();
- colorModel = ColorModelFactory.createGrayScale(DataBuffer.TYPE_FLOAT, 1, 0, 0, 1);
- }
-
- /**
- * Creates the sample model. This is a workaround for RFE #4093999
- * ("Relax constraint on placement of this()/super() call in constructors").
- */
- @Workaround(library="JDK", version="1.8")
- private static SampleModel createSampleModel(final SampleModel origin) {
- final int width = origin.getWidth();
- return new PixelInterleavedSampleModel(DataBuffer.TYPE_FLOAT, width, origin.getHeight(), 1, width, new int[1]);
- }
-
- /**
- * Returns an arbitrary color model for this image.
- */
- @Override
- public ColorModel getColorModel() {
- return colorModel;
}
/**
- * Gets a property from this image. Current default implementation supports the following keys
- * (more properties may be added to this list in future Apache SIS versions):
- *
- * <ul>
- * <li>{@value #SAMPLE_RESOLUTIONS_KEY}</li>
- * </ul>
+ * Gets a property from this image.
*/
@Override
public Object getProperty(final String key) {
- if (SAMPLE_RESOLUTIONS_KEY.equals(key)) {
- return new double[] {ResamplingGrid.TOLERANCE / 8};
- } else {
- return super.getProperty(key);
+ switch (key) {
+ case SAMPLE_RESOLUTIONS_KEY: {
+ return new double[] {ResamplingGrid.TOLERANCE / 8};
+ }
+ case POSITIONAL_ACCURACY_KEY:
+ case GRID_GEOMETRY_KEY:
+ case MASK_KEY: {
+ return getSource().getProperty(key);
+ }
+ default: {
+ return super.getProperty(key);
+ }
}
}
@@ -119,41 +103,7 @@ final class PositionalConsistencyImage extends ComputedImage {
*/
@Override
public String[] getPropertyNames() {
- return new String[] {
- SAMPLE_RESOLUTIONS_KEY
- };
- }
-
- /**
- * Returns the minimum <var>x</var> coordinate (inclusive) of this image.
- */
- @Override
- public final int getMinX() {
- return minX;
- }
-
- /**
- * Returns the minimum <var>y</var> coordinate (inclusive) of this image.
- */
- @Override
- public final int getMinY() {
- return minY;
- }
-
- /**
- * Returns the number of columns in this image.
- */
- @Override
- public final int getWidth() {
- return width;
- }
-
- /**
- * Returns the number of rows in this image.
- */
- @Override
- public final int getHeight() {
- return height;
+ return getPropertyNames(INHERITED_PROPERTIES, ADDED_PROPERTIES);
}
/**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
index 28e91a6..bb31faa 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
@@ -154,6 +154,14 @@ public class ResampledImage extends ComputedImage {
private Reference<ComputedImage> positionalConsistency;
/**
+ * {@link #MASK_KEY} value, computed when first requested.
+ *
+ * @see #getMask()
+ * @see #getProperty(String)
+ */
+ private Reference<ComputedImage> mask;
+
+ /**
* Creates a new image which will resample the given image. The resampling operation is defined
* by a non-linear transform from <em>this</em> image to the specified <em>source</em> image.
* That transform should map {@linkplain org.opengis.referencing.datum.PixelInCell#CELL_CENTER pixel centers}.
@@ -357,6 +365,21 @@ public class ResampledImage extends ComputedImage {
}
/**
+ * Computes the {@value #MASK_KEY} value. This method is invoked by {@link #getProperty(String)} when the
+ * {@link #MASK_KEY} property value is requested. The result is saved by weak reference since recomputing
+ * this image is rarely requested, and if needed can be recomputed easily.
+ */
+ private synchronized RenderedImage getMask() {
+ ComputedImage image = (mask != null) ? mask.get() : null;
+ if (image == null) {
+ mask = null; // Cleared first in case an error occurs below.
+ image = new MaskImage(this);
+ mask = image.reference();
+ }
+ return image;
+ }
+
+ /**
* Verifies whether image layout information are consistent. This method performs all verifications
* {@linkplain ComputedImage#verify() documented in parent class}, then verifies that source coordinates
* required by this image (computed by converting {@linkplain #getBounds() this image bounds} using the
@@ -393,13 +416,6 @@ public class ResampledImage extends ComputedImage {
}
/**
- * Returns the unique source of this resampled image.
- */
- private RenderedImage getSource() {
- return getSource(0);
- }
-
- /**
* Returns the same color model than the source image.
*
* @return the color model, or {@code null} if unspecified.
@@ -414,8 +430,10 @@ public class ResampledImage extends ComputedImage {
* (more properties may be added to this list in future Apache SIS versions):
*
* <ul>
+ * <li>{@value #POSITIONAL_ACCURACY_KEY}</li>
* <li>{@value #POSITIONAL_CONSISTENCY_KEY}</li>
* <li>{@value #SAMPLE_RESOLUTIONS_KEY} (forwarded to the source image)</li>
+ * <li>{@value #MASK_KEY} if the image uses floating point numbers.</li>
* </ul>
*
* <div class="note"><b>Note:</b>
@@ -438,10 +456,12 @@ public class ResampledImage extends ComputedImage {
} catch (TransformException | IllegalArgumentException e) {
throw (ImagingOpException) new ImagingOpException(e.getMessage()).initCause(e);
}
- default: {
- return super.getProperty(key);
+ case MASK_KEY: {
+ if (ImageUtilities.isIntegerType(sampleModel.getDataType())) break;
+ return getMask();
}
}
+ return super.getProperty(key);
}
/**
@@ -457,14 +477,19 @@ public class ResampledImage extends ComputedImage {
final String[] names = {
SAMPLE_RESOLUTIONS_KEY,
POSITIONAL_ACCURACY_KEY,
- POSITIONAL_CONSISTENCY_KEY
+ POSITIONAL_CONSISTENCY_KEY,
+ MASK_KEY
};
int n = 0;
for (final String name : names) {
- if (name != POSITIONAL_CONSISTENCY_KEY) {
+ if (name != POSITIONAL_CONSISTENCY_KEY) { // Identity comparisons are okay for this method.
if (name == POSITIONAL_ACCURACY_KEY) {
if (getPositionalAccuracyCount() == 0) {
- continue; // Exclude PositionalAccuracy change.
+ continue; // Exclude PositionalAccuracy change.
+ }
+ } else if (name == MASK_KEY) {
+ if (ImageUtilities.isIntegerType(sampleModel.getDataType())) {
+ continue;
}
} else if (!ArraysExt.contains(inherited, name)) {
continue; // Exclude inherited property not defined by source.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java
new file mode 100644
index 0000000..f8085a5
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java
@@ -0,0 +1,115 @@
+/*
+ * 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.image;
+
+import java.util.Set;
+import java.awt.image.ColorModel;
+import java.awt.image.SampleModel;
+import java.awt.image.RenderedImage;
+import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.Workaround;
+
+
+/**
+ * An image computed from a single source and sharing the same coordinate system.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ * @module
+ */
+abstract class SourceAlignedImage extends ComputedImage {
+ /**
+ * The color model for this image.
+ */
+ private final ColorModel colorModel;
+
+ /**
+ * Creates a new image with the given source and a sample model derived from the color model.
+ * The new image will have the same tile size than the given image.
+ *
+ * @param source source of this image. Shall not be null.
+ * @param colorModel the color model of the new image.
+ */
+ SourceAlignedImage(final RenderedImage source, final ColorModel colorModel) {
+ super(createSampleModel(colorModel, source.getSampleModel()), source);
+ this.colorModel = colorModel;
+ }
+
+ /**
+ * Creates the sample model. This is a workaround for RFE #4093999
+ * ("Relax constraint on placement of this()/super() call in constructors").
+ */
+ @Workaround(library="JDK", version="1.8")
+ private static SampleModel createSampleModel(final ColorModel colorModel, final SampleModel original) {
+ final SampleModel sm = colorModel.createCompatibleSampleModel(original.getWidth(), original.getHeight());
+ return original.equals(sm) ? original : sm;
+ }
+
+ /**
+ * Returns an arbitrary color model for this image.
+ */
+ @Override
+ public final ColorModel getColorModel() {
+ return colorModel;
+ }
+
+ /**
+ * Returns the names of properties as a merge between source properties (after filtering) and properties added
+ * by the subclass. This is a helper method for {@link #getPropertyNames()} implementations in subclasses.
+ *
+ * @param inherit properties to inherit from the source.
+ * @param append properties to append, or {@code null} if none.
+ * @return properties recognized by this image, or {@code null} if none.
+ */
+ final String[] getPropertyNames(final Set<String> inherit, final String[] append) {
+ /*
+ * This method modifies directly the array returned by `getPropertyNames()` on the assumption that the array
+ * is already a copy. This assumption is okay when the source is known to be an Apache SIS implementation.
+ */
+ String[] names = getSource().getPropertyNames();
+ if (names == null) {
+ return (append != null) ? append.clone() : null;
+ }
+ int n = 0;
+ for (final String name : names) {
+ if (inherit.contains(name)) {
+ names[n++] = name;
+ }
+ }
+ if (append == null) {
+ return ArraysExt.resize(names, n);
+ }
+ names = ArraysExt.resize(names, n + append.length);
+ System.arraycopy(names, n, append, 0, append.length);
+ return names;
+ }
+
+ /**
+ * Delegates to source image.
+ */
+ @Override public final int getMinX() {return getSource().getMinX();}
+ @Override public final int getMinY() {return getSource().getMinY();}
+ @Override public final int getWidth() {return getSource().getWidth();}
+ @Override public final int getHeight() {return getSource().getHeight();}
+ @Override public final int getMinTileX() {return getSource().getMinTileX();}
+ @Override public final int getMinTileY() {return getSource().getMinTileY();}
+ @Override public final int getNumXTiles() {return getSource().getNumXTiles();}
+ @Override public final int getNumYTiles() {return getSource().getNumYTiles();}
+ @Override public final int getTileGridXOffset() {return getSource().getTileGridXOffset();}
+ @Override public final int getTileGridYOffset() {return getSource().getTileGridYOffset();}
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ColorModelFactory.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ColorModelFactory.java
index 73cd32e..19d4fd8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ColorModelFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ColorModelFactory.java
@@ -357,7 +357,7 @@ public final class ColorModelFactory {
}
/**
- * Returns a tolerant index color model for the specified ARGB code.
+ * Returns a tolerant index color model for the specified ARGB codes.
* This color model accepts image with the specified number of bands.
*
* <p>This methods caches previously created instances using weak references,
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/MultiBandsIndexColorModel.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/MultiBandsIndexColorModel.java
index 988be37..5aca711 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/MultiBandsIndexColorModel.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/MultiBandsIndexColorModel.java
@@ -24,6 +24,7 @@ import java.awt.image.WritableRaster;
import java.awt.image.IndexColorModel;
import java.awt.image.BandedSampleModel;
import java.awt.image.ComponentSampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
/**
@@ -198,7 +199,7 @@ final class MultiBandsIndexColorModel extends IndexColorModel {
*/
@Override
public WritableRaster createCompatibleWritableRaster(final int width, final int height) {
- return Raster.createBandedRaster(transferType, width, height, numBands, null);
+ return Raster.createWritableRaster(createCompatibleSampleModel(width, height), null);
}
/**
@@ -207,7 +208,15 @@ final class MultiBandsIndexColorModel extends IndexColorModel {
*/
@Override
public SampleModel createCompatibleSampleModel(final int width, final int height) {
- return RasterFactory.unique(new BandedSampleModel(transferType, width, height, numBands));
+ final SampleModel sm;
+ if (pixel_bits <= DataBuffer.getDataTypeSize(transferType) / numBands) {
+ final int[] bitMasks = new int[numBands];
+ Arrays.fill(bitMasks, pixel_bits);
+ sm = new SinglePixelPackedSampleModel(transferType, width, height, width, bitMasks);
+ } else {
+ sm = new BandedSampleModel(transferType, width, height, numBands);
+ }
+ return RasterFactory.unique(sm);
}
/**
@@ -228,7 +237,7 @@ final class MultiBandsIndexColorModel extends IndexColorModel {
*/
@Override
public boolean isCompatibleSampleModel(final SampleModel sm) {
- return (sm instanceof ComponentSampleModel) &&
+ return (sm instanceof ComponentSampleModel || sm instanceof SinglePixelPackedSampleModel) &&
sm.getTransferType() == transferType &&
sm.getNumBands() == numBands &&
(1 << sm.getSampleSize(visibleBand)) >= getMapSize();