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/02/23 16:47:16 UTC
[sis] 01/02: Consolidation of ScaledColorSpace / ScaledColorModel.
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 <ma...@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();
}