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 5c39a4340e635a95fecb86fc271027ade5303223 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Dec 8 15:29:16 2021 +0100 Fix a problem of incompatible (SampleModel, ColorModel) pair when `Visualization` determined that it can not apply interpolations. --- .../java/org/apache/sis/image/Interpolation.java | 26 ++++++++++++++++++++++ .../java/org/apache/sis/image/ResampledImage.java | 12 +--------- .../java/org/apache/sis/image/Visualization.java | 20 +++++------------ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java b/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java index 9943dc0..63ef0bd 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java @@ -17,6 +17,8 @@ package org.apache.sis.image; import java.awt.Dimension; +import java.awt.image.RenderedImage; +import java.awt.image.IndexColorModel; import java.nio.DoubleBuffer; @@ -106,6 +108,25 @@ public abstract class Interpolation { public abstract void interpolate(DoubleBuffer source, int numBands, double xfrac, double yfrac, double[] writeTo, int writeToOffset); /** + * Returns {@link #NEAREST} if interpolations on the given image should be restricted to nearest-neighbor. + * If the given image uses an index color model, interpolating the indexed values does not produce the + * expected colors. Safest approach is to disable completely interpolations in that case. + * + * <div class="note"><b>Note:</b> + * we could interpolate if we knew that all index values, without exception (i.e. no index for missing values), + * are related to measurements by a linear function. In practice it rarely happens, because there is usually + * at least one index value reserved for missing values. Scientific data in SIS are usually stored as floating + * point type (with missing values mapped to NaN), which can not be associated to {@link IndexColorModel}. + * For now we do not try to perform a more sophisticated detection of which interpolations are allowed, + * but a future SIS version may revisit this policy if needed.</div> + * + * @return {@link #NEAREST} if interpolations should be restricted to nearest-neighbor, or {@code this} otherwise. + */ + Interpolation toCompatible(final RenderedImage source) { + return (source.getColorModel() instanceof IndexColorModel) ? NEAREST : this; + } + + /** * A nearest-neighbor interpolation using 1×1 pixel. */ public static final Interpolation NEAREST = new Interpolation() { @@ -128,6 +149,11 @@ public abstract class Interpolation { source.get(writeTo, writeToOffset, numBands); source.reset(); } + + /** This interpolation never need to be disabled. */ + @Override Interpolation toCompatible(final RenderedImage source) { + return this; + } }; /** 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 9f8ded6..ec3107e 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 @@ -24,7 +24,6 @@ import java.awt.Dimension; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; -import java.awt.image.IndexColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; @@ -245,17 +244,8 @@ public class ResampledImage extends ComputedImage { /* * If the image uses an index color model, interpolating the indexed values does not produce * the expected colors. Safest approach is to disable completely interpolations in that case. - * - * Note: we could interpolate if we knew that all index values, without exception (i.e. no index for - * missing values), are related to measurements by a linear function. It practice it rarely happens, - * because there is usually at least one index value reserved for missing values. Scientific data in - * SIS are usually stored as floating point type (with missing values mapped to NaN), which can not - * be associated to `IndexColorModel`. For now we don't try to perform a more sophisticated detection - * of which interpolations are allowed, but a future SIS version may revisit this policy if needed. */ - if (source.getColorModel() instanceof IndexColorModel) { - interpolation = Interpolation.NEAREST; - } + interpolation = interpolation.toCompatible(source); /* * If the interpolation requires more than 2×2 pixels, we will need to shift the transform * to source image. For example if the interpolation requires 4×4 pixels, the interpolation diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/Visualization.java b/core/sis-feature/src/main/java/org/apache/sis/image/Visualization.java index 110aed7..393f65f 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/Visualization.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/Visualization.java @@ -30,7 +30,6 @@ import java.awt.image.SampleModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.awt.image.RenderedImage; -import java.awt.image.DataBuffer; import java.nio.DoubleBuffer; import javax.measure.Quantity; import org.apache.sis.coverage.Category; @@ -250,18 +249,6 @@ final class Visualization extends ResampledImage { colorizer.initialize(statistics.minimum(), statistics.maximum()); } /* - * At this point we finished to configure the colorizer; we are ready to build the `ColorModel`. - * If the source image uses unsigned integer types and there is no resampling operation, we can - * update the color model without changing sample values. This is much cheaper and as accurate. - */ - final int dataType = source.getSampleModel().getDataType(); - if (dataType == DataBuffer.TYPE_BYTE || dataType == DataBuffer.TYPE_USHORT) { - if (toSource != null && !toSource.isIdentity()) { - source = processor.resample(source, bounds, toSource); - } - return RecoloredImage.create(source, colorizer.createColorModel(dataType, NUM_BANDS, VISIBLE_BAND)); - } - /* * If we reach this point, sample values need to be converted to integers in [0 … 255] range. * Skip any previous `RecoloredImage` since we are replacing the `ColorModel` by a new one. */ @@ -284,7 +271,7 @@ final class Visualization extends ResampledImage { layout = ImageLayout.fixedSize(source); interpolation = Interpolation.NEAREST; } else { - interpolation = combine(interpolation, converters); + interpolation = combine(interpolation.toCompatible(source), converters); converters = null; } /* @@ -365,6 +352,11 @@ final class Visualization extends ResampledImage { throw new BackingStoreException(e); // Will be unwrapped by computeTile(…). } } + + /** This interpolation never need to be disabled. */ + @Override Interpolation toCompatible(final RenderedImage source) { + return this; + } } /**