sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 01/03: Consolidation of Raster/ColorModel/SampleModel factories.
Date Sat, 04 Jan 2020 17:53:10 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 b372f8748d83d2372892821ee1eaf7535af1c2b3
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Jan 4 14:04:33 2020 +0100

    Consolidation of Raster/ColorModel/SampleModel factories.
---
 .../java/org/apache/sis/image/ComputedImage.java   |  3 +-
 .../java/org/apache/sis/image/PlanarImage.java     | 18 ++---
 .../coverage/j2d/BandedSampleConverter.java        |  2 +-
 .../internal/coverage/j2d/ColorModelFactory.java   | 25 ++++++-
 .../sis/internal/coverage/j2d/ImageFactory.java    | 76 ----------------------
 .../sis/internal/coverage/j2d/ImageUtilities.java  |  2 +
 .../coverage/j2d/MultiBandsIndexColorModel.java    |  2 +-
 .../sis/internal/coverage/j2d/RasterFactory.java   | 70 ++++++++++++++++++--
 .../internal/coverage/j2d/ScaledColorSpace.java    | 45 ++++++++++++-
 .../sis/coverage/grid/GridCoverage2DTest.java      |  4 +-
 10 files changed, 143 insertions(+), 104 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 8f728f2..aa6f19c 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
@@ -100,7 +100,8 @@ public abstract class ComputedImage extends PlanarImage {
          * Invoked when the enclosing image has been garbage-collected. This method removes
all cached tiles
          * that were owned by the enclosing image. This method should not perform other cleaning
work than
          * removing cached tiles because it is not guaranteed to be invoked if {@link TileCache#GLOBAL}
-         * does not contain any tile for the enclosing image.
+         * does not contain any tile for the enclosing image (because there would be nothing
preventing
+         * this weak reference to be garbage collected before {@code dispose()} is invoked).
          */
         @Override
         public void dispose() {
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 494009d..f7a4b5d 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
@@ -18,7 +18,6 @@ package org.apache.sis.image;
 
 import java.awt.Image;
 import java.awt.Rectangle;
-import java.awt.color.ColorSpace;
 import java.awt.image.ColorModel;
 import java.awt.image.IndexColorModel;
 import java.awt.image.SampleModel;
@@ -26,12 +25,12 @@ import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
 import java.awt.image.RenderedImage;
 import java.util.Vector;
-import org.apache.sis.internal.util.Numerics;
-import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Classes;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.coverage.j2d.ImageUtilities;
-import org.apache.sis.internal.coverage.j2d.ScaledColorSpace;
+import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
 
 
 /**
@@ -432,14 +431,7 @@ colors: if (cm != null) {
             if (cm instanceof IndexColorModel) {
                 buffer.append(((IndexColorModel) cm).getMapSize()).append(" indexed colors");
             } else {
-                final ColorSpace cs = cm.getColorSpace();
-                if (cs != null) {
-                    if (cs instanceof ScaledColorSpace) {
-                        ((ScaledColorSpace) cs).formatRange(buffer.append("showing "));
-                    } else if (cs.getType() == ColorSpace.TYPE_GRAY) {
-                        buffer.append("grayscale");
-                    }
-                }
+                ColorModelFactory.formatDescription(cm.getColorSpace(), buffer);
             }
             final String transparency;
             switch (cm.getTransparency()) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
index e5c4a1d..4f87725 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
@@ -89,7 +89,7 @@ public final class BandedSampleConverter extends ComputedImage {
             layout = ImageLayout.DEFAULT;
         }
         final Dimension tile = layout.suggestTileSize(source);
-        return new BandedSampleModel(targetType, tile.width, tile.height, numBands);
+        return RasterFactory.unique(new BandedSampleModel(targetType, tile.width, tile.height,
numBands));
     }
 
     /**
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 c784929..39a332c 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
@@ -36,6 +36,7 @@ import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.util.Debug;
 
 
 /**
@@ -63,7 +64,7 @@ public final class ColorModelFactory {
      *
      * @see #unique(ColorModel)
      */
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings("rawtypes")   // TODO: Remove after we removed ColorModelPatch.
     private static final WeakHashSet<ColorModelPatch> CACHE = new WeakHashSet<>(ColorModelPatch.class);
 
     /**
@@ -396,7 +397,7 @@ public final class ColorModelFactory {
      * @param  maximum        the maximal sample value expected.
      * @return the color space for the given range of values.
      *
-     * @see ImageFactory#createGrayScale(int, int, int, int, int, double, double)
+     * @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)
@@ -421,7 +422,25 @@ public final class ColorModelFactory {
         if (numComponents == 1 && minimum == 0 && maximum == 1) {
             return ColorSpace.getInstance(ColorSpace.CS_GRAY);
         }
-        return new ScaledColorSpace(numComponents, visibleBand, minimum, maximum);
+        return new ScaledColorSpace(numComponents, visibleBand, minimum, maximum).unique();
+    }
+
+    /**
+     * Appends a description of the given color space in the given buffer.
+     * This is used for {@code toString()} method implementations.
+     *
+     * @param  cs      the color space to describe, or {@code null}.
+     * @param  buffer  where to append the description.
+     */
+    @Debug
+    public static void formatDescription(final ColorSpace cs, final StringBuilder buffer)
{
+        if (cs != null) {
+            if (cs instanceof ScaledColorSpace) {
+                ((ScaledColorSpace) cs).formatRange(buffer.append("showing "));
+            } else if (cs.getType() == ColorSpace.TYPE_GRAY) {
+                buffer.append("grayscale");
+            }
+        }
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageFactory.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageFactory.java
deleted file mode 100644
index 8355838..0000000
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageFactory.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.internal.coverage.j2d;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import org.apache.sis.util.Static;
-
-
-/**
- * Convenience methods for creating new images.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
- * @since   1.1
- * @module
- */
-public final class ImageFactory extends Static {
-    /**
-     * Do not allow instantiation of this class.
-     */
-    private ImageFactory() {
-    }
-
-    /**
-     * Creates an opaque image with a gray scale color model. The image can have an arbitrary
-     * number of bands, but in current implementation only one band is used.
-     *
-     * <p><b>Warning:</b> displaying this image is very slow, except in
a few special cases.
-     * It should be used only when no standard color model can be used.</p>
-     *
-     * @param  dataType       the color model type as one of {@code DataBuffer.TYPE_*} constants.
-     * @param  width          the desired image width.
-     * @param  height         the desired image height.
-     * @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 BufferedImage createGrayScale(final int dataType, final int width, final
int height,
-            final int numComponents, final int visibleBand, final double minimum, final double
maximum)
-    {
-        switch (dataType) {
-            case DataBuffer.TYPE_BYTE: {
-                if (numComponents == 1 && minimum <= 0 && maximum >=
0xFF) {
-                    return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
-                }
-                break;
-            }
-            case DataBuffer.TYPE_USHORT: {
-                if (numComponents == 1 && minimum <= 0 && maximum >=
0xFFFF) {
-                    return new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
-                }
-                break;
-            }
-        }
-        final ColorModel cm = ColorModelFactory.createGrayScale(DataBuffer.TYPE_INT, 1, 0,
-10, 10);
-        return new BufferedImage(cm, cm.createCompatibleWritableRaster(width, height), false,
null);
-    }
-}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
index 9648cfc..437b60b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
@@ -37,6 +37,8 @@ import org.apache.sis.util.resources.Vocabulary;
 
 /**
  * Utility methods related to images and their color model or sample model.
+ * Those methods only fetch information, they do not create new rasters or sample/color models
+ * (see {@code *Factory} classes for creating those objects).
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
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 404ffa3..988be37 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
@@ -207,7 +207,7 @@ final class MultiBandsIndexColorModel extends IndexColorModel {
      */
     @Override
     public SampleModel createCompatibleSampleModel(final int width, final int height) {
-        return new BandedSampleModel(transferType, width, height, numBands);
+        return RasterFactory.unique(new BandedSampleModel(transferType, width, height, numBands));
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/RasterFactory.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/RasterFactory.java
index 2cdcea3..527e69a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/RasterFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/RasterFactory.java
@@ -17,8 +17,11 @@
 package org.apache.sis.internal.coverage.j2d;
 
 import java.awt.Point;
+import java.awt.image.ColorModel;
+import java.awt.image.SampleModel;
 import java.awt.image.BandedSampleModel;
 import java.awt.image.ComponentSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.DataBufferByte;
 import java.awt.image.DataBufferDouble;
@@ -26,10 +29,9 @@ import java.awt.image.DataBufferFloat;
 import java.awt.image.DataBufferInt;
 import java.awt.image.DataBufferShort;
 import java.awt.image.DataBufferUShort;
-import java.awt.image.PixelInterleavedSampleModel;
 import java.awt.image.RasterFormatException;
-import java.awt.image.SampleModel;
 import java.awt.image.WritableRaster;
+import java.awt.image.BufferedImage;
 import java.nio.Buffer;
 import java.nio.ReadOnlyBufferException;
 import org.apache.sis.internal.feature.Resources;
@@ -38,24 +40,70 @@ import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Workaround;
+import org.apache.sis.util.collection.WeakHashSet;
 
 
 /**
- * Creates rasters from given properties.
+ * Creates rasters from given properties. Contains also convenience methods for
+ * creating {@link BufferedImage} since that kind of images wraps a single raster.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   1.0
  * @module
  */
 public final class RasterFactory extends Static {
     /**
+     * Shared instances of {@link SampleModel}s.
+     *
+     * @see #unique(SampleModel)
+     */
+    private static final WeakHashSet<SampleModel> POOL = new WeakHashSet<>(SampleModel.class);
+
+    /**
      * Do not allow instantiation of this class.
      */
     private RasterFactory() {
     }
 
     /**
+     * Creates an opaque image with a gray scale color model. The image can have an arbitrary
+     * number of bands, but in current implementation only one band is used.
+     *
+     * <p><b>Warning:</b> displaying this image is very slow, except in
a few special cases.
+     * It should be used only when no standard color model can be used.</p>
+     *
+     * @param  dataType       the color model type as one of {@code DataBuffer.TYPE_*} constants.
+     * @param  width          the desired image width.
+     * @param  height         the desired image height.
+     * @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 BufferedImage createGrayScaleImage(final int dataType, final int width,
final int height,
+            final int numComponents, final int visibleBand, final double minimum, final double
maximum)
+    {
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE: {
+                if (numComponents == 1 && minimum <= 0 && maximum >=
0xFF) {
+                    return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+                }
+                break;
+            }
+            case DataBuffer.TYPE_USHORT: {
+                if (numComponents == 1 && minimum <= 0 && maximum >=
0xFFFF) {
+                    return new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
+                }
+                break;
+            }
+        }
+        final ColorModel cm = ColorModelFactory.createGrayScale(DataBuffer.TYPE_INT, 1, 0,
-10, 10);
+        return new BufferedImage(cm, cm.createCompatibleWritableRaster(width, height), false,
null);
+    }
+
+    /**
      * Wraps the given data buffer in a raster.
      * The sample model type is selected according the number of bands and the pixel stride.
      * The number of bands is determined by {@code bandOffsets.length}, which should be one
of followings:
@@ -152,7 +200,7 @@ public final class RasterFactory extends Static {
                 model = new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride,
bankIndices, bandOffsets);
             }
         }
-        return WritableRaster.createWritableRaster(model, buffer, location);
+        return WritableRaster.createWritableRaster(unique(model), buffer, location);
     }
 
     /**
@@ -224,4 +272,16 @@ public final class RasterFactory extends Static {
             default: return null;
         }
     }
+
+    /**
+     * Returns a unique instance of the given sample model. This method can be invoked after
a new sample
+     * has been created in order to share the same instance for many similar {@code Raster}
instances.
+     *
+     * @param  <T>          the type of the given {@code sampleModel}.
+     * @param  sampleModel  the sample model to make unique.
+     * @return a unique instance of the given sample model. May be {@code sampleModel} itself.
+     */
+    static <T extends SampleModel> T unique(final T sampleModel) {
+        return POOL.unique(sampleModel);
+    }
 }
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 0ee9e58..0e97622 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
@@ -17,7 +17,9 @@
 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;
 
 
 /**
@@ -36,13 +38,18 @@ import org.apache.sis.util.Debug;
  * @since 1.0
  * @module
  */
-public final class ScaledColorSpace extends ColorSpace {
+final class ScaledColorSpace extends ColorSpace {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = 438226855772441165L;
 
     /**
+     * Shared instances of {@link ScaledColorSpace}s.
+     */
+    private static final WeakHashSet<ScaledColorSpace> POOL = new WeakHashSet<>(ScaledColorSpace.class);
+
+    /**
      * Minimal normalized RGB value.
      */
     private static final float MIN_VALUE = 0f;
@@ -69,6 +76,7 @@ public final class ScaledColorSpace extends ColorSpace {
 
     /**
      * Creates a color model for the given range of values.
+     * Callers should invoke {@link #unique()} on the newly created instance.
      *
      * @param  numComponents  the number of components.
      * @param  visibleBand    the band to use for computing colors.
@@ -181,9 +189,42 @@ public final class ScaledColorSpace extends ColorSpace {
      * @param  buffer  where to append the range of values.
      */
     @Debug
-    public final void formatRange(final StringBuilder buffer) {
+    final void formatRange(final StringBuilder buffer) {
         buffer.append('[').append(getMinValue(visibleBand))
             .append(" … ").append(getMaxValue(visibleBand))
             .append(" in band ").append(visibleBand).append(']');
     }
+
+    /**
+     * 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 model.
+     * Defined for implementation of {@link #unique()}.
+     */
+    @Override
+    public int hashCode() {
+        return Float.floatToIntBits(scale) + 31 * Float.floatToIntBits(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 &&
+                   getNumComponents()  ==  that.getNumComponents() &&
+                   getType()           ==  that.getType();
+        }
+        return false;
+    }
 }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
index f89d81f..3841c68 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
@@ -27,7 +27,7 @@ import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.datum.PixelInCell;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.geometry.DirectPosition2D;
-import org.apache.sis.internal.coverage.j2d.ImageFactory;
+import org.apache.sis.internal.coverage.j2d.RasterFactory;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.measure.Units;
 import org.apache.sis.referencing.crs.HardCodedCRS;
@@ -70,7 +70,7 @@ public final strictfp class GridCoverage2DTest extends TestCase {
          * Create an image and set values directly as integers. We do not use one of the
          * BufferedImage.TYPE_* constant because this test uses some negative values.
          */
-        final BufferedImage  image  = ImageFactory.createGrayScale(DataBuffer.TYPE_INT, size,
size, 1, 0, -10, 10);
+        final BufferedImage  image  = RasterFactory.createGrayScaleImage(DataBuffer.TYPE_INT,
size, size, 1, 0, -10, 10);
         final WritableRaster raster = image.getRaster();
         raster.setSample(0, 0, 0,   2);
         raster.setSample(1, 0, 0,   5);


Mime
View raw message