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 2023/04/12 10:35:09 UTC
[sis] branch geoapi-4.0 updated: Chains of operations on images need `BufferedImage` to notify when data are changed.
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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new f83bef1818 Chains of operations on images need `BufferedImage` to notify when data are changed.
f83bef1818 is described below
commit f83bef1818bd74e750c4aca3ba9d347e9a902b94
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Apr 12 12:32:13 2023 +0200
Chains of operations on images need `BufferedImage` to notify when data are changed.
---
.../sis/coverage/grid/GridCoverageBuilder.java | 3 +-
.../apache/sis/coverage/grid/ImageRenderer.java | 3 +-
.../java/org/apache/sis/image/BandSelectImage.java | 3 +-
.../apache/sis/image/WritableComputedImage.java | 8 +-
.../sis/internal/coverage/j2d/ObservableImage.java | 289 +++++++++++++++++++++
.../sis/internal/coverage/j2d/RasterFactory.java | 4 +-
.../internal/coverage/j2d/WritableTiledImage.java | 8 +-
.../sis/internal/coverage/j2d/WriteSupport.java | 100 -------
.../sis/internal/sql/postgis/RasterReader.java | 3 +-
.../sis/internal/storage/esri/RasterStore.java | 4 +-
10 files changed, 309 insertions(+), 116 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
index c6b048c31c..4119687eac 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageBuilder.java
@@ -37,6 +37,7 @@ import org.apache.sis.image.PlanarImage;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.internal.coverage.j2d.ColorModelBuilder;
import org.apache.sis.internal.coverage.j2d.ImageUtilities;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
import org.apache.sis.internal.coverage.j2d.TiledImage;
import org.apache.sis.internal.coverage.j2d.WritableTiledImage;
import org.apache.sis.internal.feature.Resources;
@@ -489,7 +490,7 @@ public class GridCoverageBuilder {
if (raster instanceof WritableRaster) {
final WritableRaster wr = (WritableRaster) raster;
if (colors != null && (wr.getMinX() | wr.getMinY()) == 0) {
- image = new BufferedImage(colors, wr, false, properties);
+ image = new ObservableImage(colors, wr, false, properties);
} else {
image = new WritableTiledImage(properties, colors, wr.getWidth(), wr.getHeight(), 0, 0, wr);
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
index d9b0fef705..a34fe0ffe8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
@@ -43,6 +43,7 @@ import org.apache.sis.coverage.Category;
import org.apache.sis.internal.coverage.j2d.ColorModelBuilder;
import org.apache.sis.internal.coverage.j2d.DeferredProperty;
import org.apache.sis.internal.coverage.j2d.RasterFactory;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
import org.apache.sis.internal.coverage.j2d.TiledImage;
import org.apache.sis.internal.coverage.j2d.WritableTiledImage;
import org.apache.sis.internal.feature.Resources;
@@ -792,7 +793,7 @@ public class ImageRenderer {
* The use of a {@link BufferedImage} subclass is desired because Java2D rendering pipeline has optimizations
* in the form {@code if (image instanceof BufferedImage)}.
*/
- private static final class Untiled extends BufferedImage {
+ private static final class Untiled extends ObservableImage {
/**
* The value associated to the {@value org.apache.sis.image.PlanarImage#GRID_GEOMETRY_KEY} key,
* or {@code null} if not yet computed.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/BandSelectImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/BandSelectImage.java
index a5aeaff2cd..45ad9e2a27 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/BandSelectImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/BandSelectImage.java
@@ -33,6 +33,7 @@ import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.internal.coverage.j2d.ImageUtilities;
import org.apache.sis.internal.coverage.j2d.TileOpExecutor;
import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
/**
@@ -153,7 +154,7 @@ class BandSelectImage extends SourceAlignedImage {
properties.put(key, value);
}
}
- image = new BufferedImage(cm,
+ image = new ObservableImage(cm,
bi.getRaster().createWritableChild(0, 0, bi.getWidth(), bi.getHeight(), 0, 0, bands),
bi.isAlphaPremultiplied(), properties);
} else if (source instanceof WritableRenderedImage) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/WritableComputedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/WritableComputedImage.java
index adcfd1b6fc..5a8cdebf0f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/WritableComputedImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/WritableComputedImage.java
@@ -22,7 +22,7 @@ import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.WritableRenderedImage;
-import org.apache.sis.internal.coverage.j2d.WriteSupport;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
/**
@@ -106,7 +106,7 @@ abstract class WritableComputedImage extends ComputedImage {
* @param observer the observer to notify.
*/
public synchronized void addTileObserver(final TileObserver observer) {
- observers = WriteSupport.addTileObserver(observers, observer);
+ observers = ObservableImage.addTileObserver(observers, observer);
}
/**
@@ -117,7 +117,7 @@ abstract class WritableComputedImage extends ComputedImage {
* @param observer the observer to stop notifying.
*/
public synchronized void removeTileObserver(final TileObserver observer) {
- observers = WriteSupport.removeTileObserver(observers, observer);
+ observers = ObservableImage.removeTileObserver(observers, observer);
}
/**
@@ -131,7 +131,7 @@ abstract class WritableComputedImage extends ComputedImage {
protected boolean markTileWritable(final int tileX, final int tileY, final boolean writing) {
final boolean notify = super.markTileWritable(tileX, tileY, writing);
if (notify && this instanceof WritableRenderedImage) {
- WriteSupport.fireTileUpdate(observers, (WritableRenderedImage) this, tileX, tileY, writing);
+ ObservableImage.fireTileUpdate(observers, (WritableRenderedImage) this, tileX, tileY, writing);
}
return notify;
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java
new file mode 100644
index 0000000000..e5319541cf
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java
@@ -0,0 +1,289 @@
+/*
+ * 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.util.Arrays;
+import java.util.Hashtable;
+import java.awt.Point;
+import java.awt.image.TileObserver;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.awt.image.WritableRenderedImage;
+import org.apache.sis.internal.feature.Resources;
+import org.apache.sis.util.ArraysExt;
+
+
+/**
+ * A buffered image which can notify tile observers when tile are acquired fir write operations.
+ * Provides also helper methods for {@link WritableRenderedImage} implementations.
+ *
+ * <p>This class should be used in preference to {@link BufferedImage} when the image may be the
+ * source of {@link org.apache.sis.image.ImageProcessor} operations. It is the case In particular
+ * when this image is given to {@link org.apache.sis.coverage.grid.GridCoverage2D} constructor.
+ * We can not prevent {@link BufferedImage} to implement {@link WritableRenderedImage}, but we
+ * can give a change to Apache SIS to be notified about modifications to pixel data.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.4
+ * @since 1.1
+ */
+public class ObservableImage extends BufferedImage {
+ /**
+ * The observers, or {@code null} if none. This is a copy-on-write array:
+ * values are never modified after construction (new arrays are created).
+ *
+ * This field is declared volatile because it is read without synchronization by
+ * {@link #getWritableTile(int, int)} and {@link #releaseWritableTile(int, int)}.
+ * Since this is a copy-on-write array, it is okay to omit synchronization for
+ * those methods but we still need the memory effect.
+ */
+ @SuppressWarnings("VolatileArrayField")
+ private volatile TileObserver[] observers;
+
+ /**
+ * Number of times that the tile has been acquired for writing and not yet released.
+ * Write operations on this field should be in synchronized blocks.
+ */
+ private volatile int writeCount;
+
+ /**
+ * Creates an image of the specified type.
+ *
+ * @param width image width.
+ * @param height image height.
+ * @param type one of {@code TYPE_*} constants.
+ */
+ public ObservableImage(int width, int height, int type) {
+ super(width, height, type);
+ }
+
+ /**
+ * Creates an image using the specified raster.
+ *
+ * @param colors color model of the new image.
+ * @param raster the singleton raster for the image data.
+ * @param isRasterPremultiplied whether data in the raster has been premultiplied with alpha.
+ * @param properties image properties as ({@code String}, {@code Object}) entries.
+ */
+ public ObservableImage(ColorModel colors, WritableRaster raster, boolean isRasterPremultiplied, Hashtable<?,?> properties) {
+ super(colors, raster, isRasterPremultiplied, properties);
+ }
+
+ /**
+ * Returns a new array with the specified observer added to the array of observers.
+ * If the observer is already present, it will receive multiple notifications.
+ *
+ * @param observers the array where to add the observer, or {@code null}.
+ * @param observer the observer to add. Null values are ignored.
+ * @return the updated array of observers.
+ */
+ public static TileObserver[] addTileObserver(TileObserver[] observers, final TileObserver observer) {
+ if (observer != null) {
+ if (observers == null) {
+ return new TileObserver[] {observer};
+ }
+ final int n = observers.length;
+ observers = Arrays.copyOf(observers, n+1);
+ observers[n] = observer;
+ }
+ return observers;
+ }
+
+ /**
+ * Returns a new array with the specified observer removed from the specified array of observers.
+ * If the observer was not registered, nothing happens and the given array is returned as-is.
+ * If the observer was registered for multiple notifications, it will now be registered for one fewer.
+ *
+ * @param observers the array where to remove the observer, or {@code null}.
+ * @param observer the observer to remove.
+ * @return the updated array of observers.
+ */
+ public static TileObserver[] removeTileObserver(final TileObserver[] observers, final TileObserver observer) {
+ if (observers != null) {
+ for (int i=observers.length; --i >= 0;) {
+ if (observers[i] == observer) {
+ return ArraysExt.remove(observers, i, 1);
+ }
+ }
+ }
+ return observers;
+ }
+
+ /**
+ * Notifies all listeners that the specified tile has been checked out for writing or has been released.
+ *
+ * @param observers the observers to notify, or {@code null} if none.
+ * @param image the image that owns the tile.
+ * @param tileX the <var>x</var> index of the tile that is being updated.
+ * @param tileY the <var>y</var> index of the tile that is being updated.
+ * @param willBeWritable if {@code true}, the tile will be grabbed for writing; otherwise it is being released.
+ */
+ public static void fireTileUpdate(final TileObserver[] observers, final WritableRenderedImage image,
+ final int tileX, final int tileY, final boolean willBeWritable)
+ {
+ if (observers != null) {
+ for (final TileObserver observer : observers) {
+ observer.tileUpdate(image, tileX, tileY, willBeWritable);
+ }
+ }
+ }
+
+ /**
+ * Adds an observer to be notified when a tile is checked out for writing.
+ * If the observer is already present, it will receive multiple notifications.
+ *
+ * @param observer the observer to notify.
+ */
+ @Override
+ public synchronized void addTileObserver(final TileObserver observer) {
+ observers = addTileObserver(observers, observer);
+ }
+
+ /**
+ * Removes an observer from the list of observers notified when a tile is checked out for writing.
+ * If the observer was not registered, nothing happens. If the observer was registered for multiple
+ * notifications, it will now be registered for one fewer.
+ *
+ * @param observer the observer to stop notifying.
+ */
+ @Override
+ public synchronized void removeTileObserver(final TileObserver observer) {
+ observers = removeTileObserver(observers, observer);
+ }
+
+ /**
+ * Notifies all listeners that the specified tile has been checked out for writing or has been released.
+ * The notifications are sent only if the given {@code count} is zero.
+ *
+ * @param count value of {@link #writeCount} before increment or after decrement.
+ * @param willBeWritable if {@code true}, the tile will be grabbed for writing; otherwise it is being released.
+ */
+ private void fireTileUpdate(final int count, final boolean willBeWritable) {
+ if (count == 0) {
+ fireTileUpdate(observers, this, 0, 0, willBeWritable);
+ }
+ }
+
+ /**
+ * Checks out a tile for writing. If the same tile is checked out many times
+ * before to be released, only the first checkout is notified to listeners.
+ *
+ * @param tileX the <var>x</var> index of the tile.
+ * @param tileY the <var>y</var> index of the tile.
+ * @return the specified tile as a writable tile.
+ * @throws IndexOutOfBoundsException if a given tile index is out of bounds.
+ */
+ @Override
+ public WritableRaster getWritableTile(final int tileX, final int tileY) {
+ if ((tileX | tileY) != 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ final WritableRaster tile = super.getWritableTile(tileX, tileY);
+ final int count;
+ synchronized (this) {
+ count = writeCount++;
+ }
+ // Should be outside the synchronized block.
+ fireTileUpdate(count, true);
+ return tile;
+ }
+
+ /**
+ * Relinquishes the right to write to a tile. If the tile goes from having
+ * one writer to having no writers, then the listeners are notified.
+ *
+ * @param tileX the <var>x</var> index of the tile.
+ * @param tileY the <var>y</var> index of the tile.
+ * @throws IndexOutOfBoundsException if a given tile index is out of bounds.
+ */
+ @Override
+ public void releaseWritableTile(final int tileX, final int tileY) {
+ if ((tileX | tileY) != 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ final int count;
+ synchronized (this) {
+ count = --writeCount;
+ if (count < 0) writeCount = 0;
+ }
+ if (count < 0) {
+ throw new IllegalArgumentException(Resources.format(Resources.Keys.TileNotWritable_2, tileX, tileY));
+ }
+ // Should be outside the synchronized block.
+ fireTileUpdate(count, false);
+ }
+
+ /**
+ * Returns whether a tile is currently checked out for writing.
+ *
+ * @param tileX the <var>x</var> index of the tile.
+ * @param tileY the <var>y</var> index of the tile.
+ * @return {@code true} if specified tile is checked out for writing, {@code false} otherwise.
+ */
+ @Override
+ public boolean isTileWritable(final int tileX, final int tileY) {
+ return (tileX | tileY) == 0 && writeCount != 0;
+ }
+
+ /**
+ * Returns the indices of all tiles checked out for writing.
+ * Returns {@code null} if none are checked out.
+ *
+ * @return indices of tiles that are checked out for writing, or {@code null} if none.
+ */
+ @Override
+ public Point[] getWritableTileIndices() {
+ return writeCount == 0 ? null : new Point[] {new Point()};
+ }
+
+ /**
+ * Returns whether any tile is checked out for writing.
+ *
+ * @return {@code true} if any tiles are checked out for writing, or {@code false} otherwise.
+ */
+ @Override
+ public boolean hasTileWriters() {
+ return writeCount != 0;
+ }
+
+ /**
+ * Sets a region of the image to the contents of the given raster.
+ * The raster is assumed to be in the same coordinate space as this image.
+ * The operation is clipped to the bounds of this image.
+ *
+ * @param data the values to write in this image.
+ */
+ @Override
+ public void setData(final Raster data) {
+ int count;
+ synchronized (this) {
+ count = writeCount++;
+ }
+ fireTileUpdate(count, true);
+ try {
+ super.setData(data);
+ } finally {
+ synchronized (this) {
+ // Similar to `releaseWritableTile(…)` but without throwing exception.
+ writeCount = count = Math.max(0, writeCount - 1);
+ }
+ fireTileUpdate(count, false);
+ }
+ }
+}
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 c8a31f3b97..8cf31909e4 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
@@ -93,14 +93,14 @@ public final class RasterFactory extends Static {
case DataBuffer.TYPE_BYTE:
case DataBuffer.TYPE_USHORT: {
if (numComponents == 1 && ColorModelFactory.isStandardRange(dataType, minimum, maximum)) {
- return new BufferedImage(width, height, (dataType == DataBuffer.TYPE_BYTE)
+ return new ObservableImage(width, height, (dataType == DataBuffer.TYPE_BYTE)
? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_USHORT_GRAY);
}
break;
}
}
final ColorModel cm = ColorModelFactory.createGrayScale(dataType, numComponents, visibleBand, minimum, maximum);
- return new BufferedImage(cm, cm.createCompatibleWritableRaster(width, height), false, null);
+ return new ObservableImage(cm, cm.createCompatibleWritableRaster(width, height), false, null);
}
/**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WritableTiledImage.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WritableTiledImage.java
index 88f9de5e94..72facf9a4f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WritableTiledImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WritableTiledImage.java
@@ -84,7 +84,7 @@ public class WritableTiledImage extends TiledImage implements WritableRenderedIm
*/
@Override
public synchronized void addTileObserver(final TileObserver observer) {
- observers = WriteSupport.addTileObserver(observers, observer);
+ observers = ObservableImage.addTileObserver(observers, observer);
}
/**
@@ -96,7 +96,7 @@ public class WritableTiledImage extends TiledImage implements WritableRenderedIm
*/
@Override
public synchronized void removeTileObserver(final TileObserver observer) {
- observers = WriteSupport.removeTileObserver(observers, observer);
+ observers = ObservableImage.removeTileObserver(observers, observer);
}
/**
@@ -116,7 +116,7 @@ public class WritableTiledImage extends TiledImage implements WritableRenderedIm
count = writables.merge(key, 1, (old, one) -> old + 1);
}
if (count <= 1) {
- WriteSupport.fireTileUpdate(observers, this, tileX, tileY, true);
+ ObservableImage.fireTileUpdate(observers, this, tileX, tileY, true);
}
return tile;
}
@@ -145,7 +145,7 @@ public class WritableTiledImage extends TiledImage implements WritableRenderedIm
throw new IllegalArgumentException(Resources.format(Resources.Keys.TileNotWritable_2, tileX, tileY));
}
if (close) {
- WriteSupport.fireTileUpdate(observers, this, tileX, tileY, false);
+ ObservableImage.fireTileUpdate(observers, this, tileX, tileY, false);
}
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WriteSupport.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WriteSupport.java
deleted file mode 100644
index 547120e467..0000000000
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/WriteSupport.java
+++ /dev/null
@@ -1,100 +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.util.Arrays;
-import java.awt.image.TileObserver;
-import java.awt.image.WritableRenderedImage;
-import org.apache.sis.util.ArraysExt;
-
-
-/**
- * Helper methods for {@link WritableRenderedImage} implementations.
- *
- * <p>A future version of this class may extends {@code PlanarImage} or {@code ComputedImage}.
- * We have not yet decided which case would be useful.</p>
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.1
- * @since 1.1
- */
-public final class WriteSupport {
- /**
- * Do not allow (for now) instantiation of this class.
- */
- private WriteSupport() {
- }
-
- /**
- * Returns a new array with the specified observer added to the array of observers.
- * If the observer is already present, it will receive multiple notifications.
- *
- * @param observers the array where to add the observer, or {@code null}.
- * @param observer the observer to add. Null values are ignored.
- * @return the updated array of observers.
- */
- public static TileObserver[] addTileObserver(TileObserver[] observers, final TileObserver observer) {
- if (observer != null) {
- if (observers == null) {
- return new TileObserver[] {observer};
- }
- final int n = observers.length;
- observers = Arrays.copyOf(observers, n+1);
- observers[n] = observer;
- }
- return observers;
- }
-
- /**
- * Returns a new array with the specified observer removed from the specified array of observers.
- * If the observer was not registered, nothing happens and the given array is returned as-is.
- * If the observer was registered for multiple notifications, it will now be registered for one fewer.
- *
- * @param observers the array where to remove the observer, or {@code null}.
- * @param observer the observer to remove.
- * @return the updated array of observers.
- */
- public static TileObserver[] removeTileObserver(final TileObserver[] observers, final TileObserver observer) {
- if (observers != null) {
- for (int i=observers.length; --i >= 0;) {
- if (observers[i] == observer) {
- return ArraysExt.remove(observers, i, 1);
- }
- }
- }
- return observers;
- }
-
- /**
- * Notifies all listeners that the specified tile has been checked out for writing.
- *
- * @param observers the observers to notify, or {@code null} if none.
- * @param image the image that owns the tile.
- * @param tileX the <var>x</var> index of the tile that is being updated.
- * @param tileY the <var>y</var> index of the tile that is being updated.
- * @param willBeWritable if {@code true}, the tile will be grabbed for writing; otherwise it is being released.
- */
- public static void fireTileUpdate(final TileObserver[] observers, final WritableRenderedImage image,
- final int tileX, final int tileY, final boolean willBeWritable)
- {
- if (observers != null) {
- for (final TileObserver observer : observers) {
- observer.tileUpdate(image, tileX, tileY, willBeWritable);
- }
- }
- }
-}
diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
index 70c5633727..5213e9cdad 100644
--- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
+++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
@@ -44,6 +44,7 @@ import org.apache.sis.coverage.grid.GridCoverage2D;
import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
import org.apache.sis.internal.storage.io.InputStreamArrayGetter;
import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -337,7 +338,7 @@ public final class RasterReader extends RasterFormat {
}
cm = ColorModelFactory.createGrayScale(dataType, numBands, visibleBand, minimum, maximum);
}
- return new BufferedImage(cm, raster, false, null);
+ return new ObservableImage(cm, raster, false, null);
}
/**
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java
index fc83cb467c..ab1c177127 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java
@@ -28,7 +28,6 @@ import java.nio.file.Path;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
-import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import org.opengis.geometry.Envelope;
import org.opengis.metadata.Metadata;
@@ -48,6 +47,7 @@ import org.apache.sis.internal.storage.PRJDataStore;
import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
import org.apache.sis.internal.coverage.j2d.ImageUtilities;
+import org.apache.sis.internal.coverage.j2d.ObservableImage;
import org.apache.sis.internal.coverage.RangeArgument;
import org.apache.sis.internal.storage.Resources;
import org.apache.sis.internal.util.UnmodifiableArrayList;
@@ -490,7 +490,7 @@ abstract class RasterStore extends PRJDataStore implements GridCoverageResource
cm = ColorModelFactory.createGrayScale(data.getSampleModel(), VISIBLE_BAND, band.getSampleRange().orElse(null));
}
}
- return new GridCoverage2D(domain, Arrays.asList(bands), new BufferedImage(cm, data, false, properties));
+ return new GridCoverage2D(domain, Arrays.asList(bands), new ObservableImage(cm, data, false, properties));
}
/**