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 <martin.desruisse...@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)); } /**