sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 01/02: Consolidation of ScaledColorSpace / ScaledColorModel.
Date Sun, 23 Feb 2020 16:47:16 GMT
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 0b64c9b5b179dc7564d1ae4023a93a1320c601b8
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sun Feb 23 17:04:53 2020 +0100

    Consolidation of ScaledColorSpace / ScaledColorModel.
---
 .../internal/coverage/j2d/ColorModelFactory.java   |  37 ++------
 .../internal/coverage/j2d/ScaledColorModel.java    | 102 +++++++--------------
 .../internal/coverage/j2d/ScaledColorSpace.java    |  79 ++++++----------
 3 files changed, 70 insertions(+), 148 deletions(-)

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 90d0296..2bc73d4 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
@@ -227,14 +227,7 @@ public final class ColorModelFactory {
          * fallback on a generic (but very slow!) color model.
          */
         if (type != DataBuffer.TYPE_BYTE && type != DataBuffer.TYPE_USHORT) {
-            final ColorSpace colors = createColorSpace(numBands, visibleBand, minimum, maximum);
-            final ComponentColorModel cm;
-            if (colors instanceof ScaledColorSpace) {
-                cm = new ScaledColorModel((ScaledColorSpace) colors, minimum, maximum, type);
-            } else {
-                cm = new ComponentColorModel(colors, false, false, Transparency.OPAQUE, type);
-            }
-            return unique(cm);
+            return createGrayScale(type, numBands, visibleBand, minimum, maximum);
         }
         /*
          * If there is no category, constructs a gray scale palette.
@@ -406,34 +399,22 @@ public final class ColorModelFactory {
      * @param  visibleBand    the band to use for computing colors.
      * @param  minimum        the minimal sample value expected.
      * @param  maximum        the maximal sample value expected.
-     * @return the color space for the given range of values.
+     * @return the color model for the given range of values.
      *
      * @see RasterFactory#createGrayScaleImage(int, int, int, int, int, double, double)
      */
     public static ColorModel createGrayScale(final int dataType, final int numComponents,
             final int visibleBand, final double minimum, final double maximum)
     {
-        final ColorSpace cs = createColorSpace(numComponents, visibleBand, minimum, maximum);
-        return new ComponentColorModel(cs, false, false, Transparency.OPAQUE, dataType);
-    }
-
-    /**
-     * Returns a color space for images storing pixels as real numbers. The color space can
have an arbitrary number of bands,
-     * but in current implementation only one band is used. Current implementation create
a gray scale.
-     *
-     * <p>The use of this color space is very slow. It should be used only when no
standard color space can be used.</p>
-     *
-     * @param  numComponents  the number of components.
-     * @param  visibleBand    the band to use for computing colors.
-     * @param  minimum        the minimal sample value expected.
-     * @param  maximum        the maximal sample value expected.
-     * @return the color space for the given range of values.
-     */
-    public static ColorSpace createColorSpace(final int numComponents, final int visibleBand,
final double minimum, final double maximum) {
+        final ColorModel cm;
         if (numComponents == 1 && minimum == 0 && maximum == 1) {
-            return ColorSpace.getInstance(ColorSpace.CS_GRAY);
+            final ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+            cm = new ComponentColorModel(cs, false, false, Transparency.OPAQUE, dataType);
+        } else {
+            final ScaledColorSpace cs = new ScaledColorSpace(numComponents, visibleBand,
minimum, maximum);
+            cm = new ScaledColorModel(cs, dataType);
         }
-        return new ScaledColorSpace(numComponents, visibleBand, minimum, maximum).unique();
+        return unique(cm);
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorModel.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorModel.java
index e63c920..ab6fc8a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorModel.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorModel.java
@@ -20,7 +20,6 @@ import java.awt.Transparency;
 import java.awt.image.DataBuffer;
 import java.awt.image.ComponentColorModel;
 import java.awt.image.RasterFormatException;
-import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.feature.Resources;
 
 
@@ -29,7 +28,7 @@ import org.apache.sis.internal.feature.Resources;
  * This color model is slightly more efficient than the default {@link ComponentColorModel}
by
  * reducing the amount of object allocations, made possible by the knowledge that we use
only
  * one sample value and returns only one color component (the gray).
- * In addition, this class render the {@link Float#NaN} values as transparent.
+ * In addition, this class renders the {@link Float#NaN} values as transparent.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
@@ -38,65 +37,45 @@ import org.apache.sis.internal.feature.Resources;
  */
 final class ScaledColorModel extends ComponentColorModel {
     /**
-     * Index of the band to display. This is a copy of {@link ScaledColorSpace#visibleBand}.
+     * The mask to apply for getting a single color component.
+     * This is also the maximum (inclusive) color/alpha value.
      */
-    private final int visibleBand;
+    private static final int MASK = 0xFF;
 
     /**
-     * The scaling factor from sample values to RGB normalized values.
-     * This information duplicates {@link ScaledColorSpace#scale} but
-     * for a scale from 0 to 256 instead than 0 to 1.
+     * Size of the range of color values. Since minimum value is zero,
+     * this range is also the maximum (exclusive) color/alpha value.
      */
-    private final double scale;
+    static final int RANGE = 0x100;
 
     /**
-     * The offset to subtract from sample values before to apply the {@linkplain #scale}
factor.
-     * This information duplicates {@link ScaledColorSpace#offset} but for a scale from 0
to 256
-     * instead than 0 to 1.
+     * The object from which to get the coefficients for converting values to colors.
+     * This is a reference to the same object than {@link #getColorSpace()}, but stored
+     * as a {@link ScaledColorSpace} for avoiding the need to perform casts.
      */
-    private final double offset;
+    private final ScaledColorSpace cs;
 
     /**
-     * Creates a new color model.
+     * Creates a new color model for the range of values in the given color space.
      *
-     * @param  colorSpace  the color space to use with this color model.
-     * @param  minimum     the minimal sample value expected, inclusive.
-     * @param  maximum     the maximal sample value expected, exclusive.
-     * @param  type        one of the {@link DataBuffer} constants.
+     * @param  colorSpace   the color space to use with this color model.
+     * @param  type         one of the {@link DataBuffer} constants.
      */
-    ScaledColorModel(final ScaledColorSpace colorSpace, final double minimum, final double
maximum, final int type) {
+    ScaledColorModel(final ScaledColorSpace colorSpace, final int type) {
         super(colorSpace, false, false, Transparency.BITMASK, type);
-        visibleBand = colorSpace.visibleBand;
-        scale  = 0x100 / (maximum - minimum);
-        offset = minimum;
+        cs = colorSpace;
     }
 
     /**
-     * Returns the red component of the given value.
      * Defined for consistency but should not be used.
      */
-    @Override
-    public int getRed(final Object inData) {
-        return getRGB(inData) & 0xFF;
-    }
-
-    /**
-     * Returns the green component of the given value.
-     * Defined for consistency but should not be used.
-     */
-    @Override
-    public int getGreen(final Object inData) {
-        return (getRGB(inData) >>> Byte.SIZE) & 0xFF;
-    }
-
-    /**
-     * Returns the green component of the given value.
-     * Defined for consistency but should not be used.
-     */
-    @Override
-    public int getBlue(final Object inData) {
-        return (getRGB(inData) >>> 2*Byte.SIZE) & 0xFF;
-    }
+    @Override public int getRed  (int    value) {return (getRGB(value) >>> 2*Byte.SIZE)
& MASK;}
+    @Override public int getRed  (Object value) {return (getRGB(value) >>> 2*Byte.SIZE)
& MASK;}
+    @Override public int getGreen(int    value) {return (getRGB(value) >>>   Byte.SIZE)
& MASK;}
+    @Override public int getGreen(Object value) {return (getRGB(value) >>>   Byte.SIZE)
& MASK;}
+    @Override public int getBlue (int    value) {return  getRGB(value)                  &
MASK;}
+    @Override public int getBlue (Object value) {return  getRGB(value)                  &
MASK;}
+    @Override public int getAlpha(int    value) {return                                 
 MASK;}
 
     /**
      * Returns the alpha value for the given sample values.
@@ -104,10 +83,11 @@ final class ScaledColorModel extends ComponentColorModel {
      */
     @Override
     public int getAlpha(final Object inData) {
+        final int visibleBand = cs.visibleBand;
         switch (transferType) {
-            case DataBuffer.TYPE_FLOAT:  return Float .isNaN(((float[])  inData)[visibleBand])
? 0 : 0xFF;
-            case DataBuffer.TYPE_DOUBLE: return Double.isNaN(((double[]) inData)[visibleBand])
? 0 : 0xFF;
-            default: return 0xFF;
+            case DataBuffer.TYPE_FLOAT:  return Float .isNaN(((float[])  inData)[visibleBand])
? 0 : MASK;
+            case DataBuffer.TYPE_DOUBLE: return Double.isNaN(((double[]) inData)[visibleBand])
? 0 : MASK;
+            default: return MASK;
         }
     }
 
@@ -116,6 +96,7 @@ final class ScaledColorModel extends ComponentColorModel {
      */
     @Override
     public int getRGB(final Object inData) {
+        final int visibleBand = cs.visibleBand;
         final double value;
         switch (transferType) {
             case DataBuffer.TYPE_BYTE:   value = Byte .toUnsignedInt(((byte[])   inData)[visibleBand]);
break;
@@ -129,31 +110,16 @@ final class ScaledColorModel extends ComponentColorModel {
         if (Double.isNaN(value)) {
             return 0;                                           // Transparent pixel.
         }
-        final int c = Math.max(0, Math.min(0xFF, (int) ((value - offset) * scale)));
-        return c | (c << Byte.SIZE) | (c << 2*Byte.SIZE) | 0xFF000000;
-    }
-
-    /**
-     * Returns a hash code value for this color model.
-     */
-    @Override
-    public int hashCode() {
-        return Long.hashCode(Double.doubleToLongBits(scale)
-                      + 31 * Double.doubleToLongBits(offset))
-                      +  7 * getNumComponents() + visibleBand;
+        final int c = Math.max(0, Math.min(MASK, (int) ((value - cs.offset) * cs.scale)));
+        return c | (c << Byte.SIZE) | (c << 2*Byte.SIZE) | (MASK << 3*Byte.SIZE);
     }
 
     /**
-     * Compares this color model with the given object for equality.
+     * Returns the color/alpha components of the pixel.
      */
     @Override
-    public boolean equals(final Object other) {
-        if (other instanceof ScaledColorModel && super.equals(other)) {
-            final ScaledColorModel that = (ScaledColorModel) other;
-            return visibleBand == that.visibleBand
-                    && Numerics.equals(scale,  that.scale)
-                    && Numerics.equals(offset, that.offset);
-        }
-        return false;
+    public int getRGB(final int value) {
+        final int c = Math.max(0, Math.min(MASK, (int) ((value - cs.offset) * cs.scale)));
+        return c | (c << Byte.SIZE) | (c << 2*Byte.SIZE) | (MASK << 3*Byte.SIZE);
     }
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorSpace.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorSpace.java
index 9722fb4..13ccfa3 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorSpace.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ScaledColorSpace.java
@@ -19,13 +19,11 @@ package org.apache.sis.internal.coverage.j2d;
 import java.awt.color.ColorSpace;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.Debug;
-import org.apache.sis.util.collection.WeakHashSet;
 
 
 /**
- * Color space for images storing pixels as real numbers. The color space can have an
- * arbitrary number of bands, but in current implementation only one band is used.
- * Current implementation creates a gray scale.
+ * Color space for images storing pixels as real numbers. This color space can have an arbitrary
number of bands,
+ * but only one band is shown. Current implementation produces grayscale image only, but
it may change in future.
  *
  * <p>The use of this color space is very slow.
  * It should be used only when no standard color space can be used.</p>
@@ -34,7 +32,7 @@ import org.apache.sis.util.collection.WeakHashSet;
  * @version 1.1
  *
  * @see ScaledColorModel
- * @see ColorModelFactory#createColorSpace(int, int, double, double)
+ * @see ColorModelFactory#createGrayScale(int, int, int, double, double)
  *
  * @since 1.0
  * @module
@@ -43,41 +41,28 @@ final class ScaledColorSpace extends ColorSpace {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 438226855772441165L;
+    private static final long serialVersionUID = -6635165959083590494L;
 
     /**
-     * Shared instances of {@link ScaledColorSpace}s.
+     * The scaling factor from sample values to RGB values. The target RGB values will be
in range 0
+     * to 255 inclusive. Note that the target range is different than the range of {@link
ColorSpace}
+     * normalized values; methods in this class has to divide values by {@value ScaledColorModel#RANGE}.
      */
-    private static final WeakHashSet<ScaledColorSpace> POOL = new WeakHashSet<>(ScaledColorSpace.class);
-
-    /**
-     * Minimal normalized RGB value.
-     */
-    private static final float MIN_VALUE = 0f;
-
-    /**
-     * Maximal normalized RGB value.
-     */
-    private static final float MAX_VALUE = 1f;
-
-    /**
-     * The scaling factor from sample values to RGB normalized values.
-     */
-    private final float scale;
+    final double scale;
 
     /**
      * The offset to subtract from sample values before to apply the {@linkplain #scale}
factor.
      */
-    private final float offset;
+    final double offset;
 
     /**
-     * Index of the band to display.
+     * Index of the band to display, from 0 inclusive to {@link #getNumComponents()} exclusive.
      */
     final int visibleBand;
 
     /**
      * Creates a color model for the given range of values.
-     * Callers should invoke {@link #unique()} on the newly created instance.
+     * The given range does not need to be exact; values outside that range will be clamped.
      *
      * @param  numComponents  the number of components.
      * @param  visibleBand    the band to use for computing colors.
@@ -87,9 +72,8 @@ final class ScaledColorSpace extends ColorSpace {
     ScaledColorSpace(final int numComponents, final int visibleBand, final double minimum,
final double maximum) {
         super(TYPE_GRAY, numComponents);
         this.visibleBand = visibleBand;
-        final double scale  = (MAX_VALUE - MIN_VALUE) / (maximum - minimum);
-        this.scale  = (float) scale;
-        this.offset = (float) (minimum - MIN_VALUE / scale);
+        scale  = ScaledColorModel.RANGE / (maximum - minimum);
+        offset = minimum;
     }
 
     /**
@@ -100,12 +84,8 @@ final class ScaledColorSpace extends ColorSpace {
      */
     @Override
     public float[] toRGB(final float[] samples) {
-        float value = (samples[visibleBand] - offset) * scale;
-        if (!(value >= MIN_VALUE)) {                            // Use '!' for catching
NaN.
-            value = MIN_VALUE;
-        } else if (value > MAX_VALUE) {
-            value = MAX_VALUE;
-        }
+        float value = Math.min(1, (float) ((samples[visibleBand] - offset) * (1d/ScaledColorModel.RANGE
* scale)));
+        if (!(value >= 0)) value = 0;                   // Use '!' for replacing NaN.
         return new float[] {value, value, value};
     }
 
@@ -118,7 +98,8 @@ final class ScaledColorSpace extends ColorSpace {
     @Override
     public float[] fromRGB(final float[] color) {
         final float[] values = new float[getNumComponents()];
-        values[visibleBand] = (color[0] + color[1] + color[2]) / (3 * scale) + offset;
+        values[visibleBand] = (float) ((color[0] + color[1] + color[2])
+                            / (3d/ScaledColorModel.RANGE * scale) + offset);
         return values;
     }
 
@@ -145,7 +126,8 @@ final class ScaledColorSpace extends ColorSpace {
     @Override
     public float[] fromCIEXYZ(final float[] color) {
         final float[] values = new float[getNumComponents()];
-        values[visibleBand] = (color[0] / 0.9642f + color[1] + color[2] / 0.8249f) / (3 *
scale) + offset;
+        values[visibleBand] = (float) ((color[0] / 0.9642f + color[1] + color[2] / 0.8249f)
+                            / (3d/ScaledColorModel.RANGE * scale) + offset);
         return values;
     }
 
@@ -157,7 +139,7 @@ final class ScaledColorSpace extends ColorSpace {
      */
     @Override
     public float getMinValue(final int component) {
-        return MIN_VALUE / scale + offset;
+        return (float) offset;
     }
 
     /**
@@ -168,7 +150,7 @@ final class ScaledColorSpace extends ColorSpace {
      */
     @Override
     public float getMaxValue(final int component) {
-        return MAX_VALUE / scale + offset;
+        return (float) (ScaledColorModel.RANGE / scale + offset);
     }
 
     /**
@@ -197,32 +179,25 @@ final class ScaledColorSpace extends ColorSpace {
     }
 
     /**
-     * Returns a unique instance of this color space. May be {@code this}.
-     */
-    final ScaledColorSpace unique() {
-        return POOL.unique(this);
-    }
-
-    /**
      * Returns a hash code value for this color space.
-     * Defined for implementation of {@link #unique()}.
      */
     @Override
     public int hashCode() {
-        return Float.floatToIntBits(scale) + 31 * Float.floatToIntBits(offset) + 7 * getNumComponents()
+ visibleBand;
+        return Long.hashCode(Double.doubleToLongBits(scale)
+                      + 31 * Double.doubleToLongBits(offset))
+                      +  7 * getNumComponents() + visibleBand;
     }
 
     /**
      * Compares this color space with the given object for equality.
-     * Defined for implementation of {@link #unique()}.
      */
     @Override
     public boolean equals(final Object obj) {
         if (obj instanceof ScaledColorSpace) {
             final ScaledColorSpace that = (ScaledColorSpace) obj;
-            return Numerics.equals(scale,  that.scale)  &&
-                   Numerics.equals(offset, that.offset) &&
-                   visibleBand         ==  that.visibleBand &&
+            return Numerics.equals(scale,  that.scale)             &&
+                   Numerics.equals(offset, that.offset)            &&
+                   visibleBand         ==  that.visibleBand        &&
                    getNumComponents()  ==  that.getNumComponents() &&
                    getType()           ==  that.getType();
         }


Mime
View raw message