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/12/08 14:52:45 UTC

[sis] 04/04: Fix a problem of incompatible (SampleModel, ColorModel) pair when `Visualization` determined that it can not apply interpolations.

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 <ma...@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;
+        }
     }
 
     /**