- All Implemented Interfaces:
RenderedImage
,Disposable
- Direct Known Subclasses:
ResampledImage
ComputedImage
may have an arbitrary number of source images, including zero.
A TileObserver
is automatically registered to all sources that are instances of
WritableRenderedImage
. If one of those sources sends a change event, then all
ComputedImage
tiles that may be impacted by that change are marked as dirty
and will be computed again when needed.
When this ComputedImage
is garbage collected, all cached tiles are discarded
and the above-cited TileObserver
is automatically removed from all sources.
This cleanup can be requested without waiting for garbage collection by invoking the
dispose()
method, but that call should be done only if the caller is certain
that this ComputedImage
will not be used anymore.
Pixel coordinate system
Default implementation assumes that the pixel in upper-left left corner is located at coordinates (0,0). This assumption is consistent withGridCoverage.render(GridExtent)
contract, which produces an image located at (0,0) when the image region matches the GridExtent
.
However, subclasses can use a non-zero origin by overriding the methods documented in the
Sub-classing section below.
If this ComputedImage
does not have any WritableRenderedImage
source, then there is
no other assumption on the pixel coordinate system. But if there is writable sources, then the default
implementation assumes that source images occupy the same region as this ComputedImage
:
all pixels at coordinates (x, y) in this ComputedImage
depend on pixels
at the same (x, y) coordinates in the source images,
possibly shifted or expanded to neighborhood pixels as described in SOURCE_PADDING_KEY
.
If this assumption does not hold, then subclasses should override the
sourceTileChanged(RenderedImage, int, int)
method.
Sub-classing
Subclasses need to implement at least the following methods:
RenderedImage.getWidth()
— the image width in pixels.RenderedImage.getHeight()
— the image height in pixels.computeTile(int, int, WritableRaster)
— invoked when a requested tile is not in the cache or needs to be updated.
If pixel coordinates or tile indices do not start at zero, then subclasses shall also override the following methods:
PlanarImage.getMinX()
— the minimum x coordinate (inclusive) of the image.PlanarImage.getMinY()
— the minimum y coordinate (inclusive) of the image.PlanarImage.getMinTileX()
— the minimum tile index in the x direction.PlanarImage.getMinTileY()
— the minimum tile index in the y direction.
Writable computed images
ComputedImage
can itself be a WritableRenderedImage
if subclasses decide so.
A writable computed image is an image which can retro-propagate sample value changes to the source images.
This class provides hasTileWriters()
, getWritableTileIndices()
, isTileWritable(int, int)
and markTileWritable(int, int, boolean)
methods for WritableRenderedImage
implementations convenience.
Apache SIS does not yet define a synchronization policy
between getTile(…)
method and WritableRenderedImage.getWritableTile
/releaseWritableTile(…)
methods.
For example if a call to getTile(tileX, tileY)
is followed by a call to getWritableTile(tileX, tileY)
in another thread, there is no guarantee about whether or not the sample values seen in the Raster
would be
isolated from the write operations done concurrently in the WritableRaster
.
A future SIS version may define a policy (possibly based on ReadWriteLock
).
Note that despite above-cited issue, all methods in this ComputedImage
class are thread-safe.
What is not thread-safe is writing into a WritableRaster
from outside the computeTile(…)
method, or reading a Raster
after it became dirty
if the change to dirty state happened after the call to getTile(…)
.
- Since:
- 1.1
-
Field Summary
Modifier and TypeFieldDescriptionprotected final SampleModel
The sample model shared by all tiles in this image.static final String
The property for declaring the amount of additional source pixels needed on each side of a destination pixel.Fields inherited from class PlanarImage
GRID_GEOMETRY_KEY, MASK_KEY, POSITIONAL_ACCURACY_KEY, SAMPLE_DIMENSIONS_KEY, SAMPLE_RESOLUTIONS_KEY, STATISTICS_KEY
-
Constructor Summary
ModifierConstructorDescriptionprotected
ComputedImage
(SampleModel sampleModel, RenderedImage... sources) Creates an initially empty image with the given sample model. -
Method Summary
Modifier and TypeMethodDescriptionprotected boolean
clearErrorFlags
(Rectangle tiles) Clears the error status of all tiles in the given range of indices.protected abstract Raster
computeTile
(int tileX, int tileY, WritableRaster previous) Invoked when a tile need to be computed or updated.protected WritableRaster
createTile
(int tileX, int tileY) Creates an initially empty tile at the given tile grid position.void
dispose()
Advises this image that its tiles will no longer be requested.final SampleModel
Returns the sample model associated with this image.protected final RenderedImage
getSource
(int index) Returns the source at the given index.Returns the immediate sources of image data for this image (may benull
).final Raster
getTile
(int tileX, int tileY) Returns a tile of this image, computing it when needed.final int
Returns the height of tiles in this image.final int
Returns the width of tiles in this image.Point[]
Returns the indices of all tiles under computation or checked out for writing, ornull
if none.boolean
Returns whether any tile is under computation or is checked out for writing.boolean
isTileWritable
(int tileX, int tileY) Returns whether the specified tile is currently under computation or checked out for writing.protected boolean
markDirtyTiles
(Rectangle tiles) Marks all tiles in the given range of indices as in need of being recomputed.protected boolean
markTileWritable
(int tileX, int tileY, boolean writing) Sets or clears whether a tile is checked out for writing.protected Disposable
Notifies this image that tiles will be computed soon in the given region.protected void
sourceTileChanged
(RenderedImage source, int tileX, int tileY) Invoked when a tile of a source image has been updated.Methods inherited from class PlanarImage
copyData, getBounds, getData, getData, getMinTileX, getMinTileY, getMinX, getMinY, getNumXTiles, getNumYTiles, getProperty, getPropertyNames, getTileGridXOffset, getTileGridYOffset, toString, verify
Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
Methods inherited from interface RenderedImage
getColorModel, getHeight, getWidth
-
Field Details
-
SOURCE_PADDING_KEY
The property for declaring the amount of additional source pixels needed on each side of a destination pixel. This property can be used for calculations that require only a fixed rectangular source region around a source pixel in order to compute each destination pixel. A given destination pixel (x, y) may be computed from the neighborhood of source pixels beginning at (x -Insets.left
, y -Insets.top
) and extending to (x +Insets.right
, y +Insets.bottom
) inclusive. Thoseleft
,top
,right
andbottom
attributes can be positive, zero or negative, but their sums shall be positive with (left
+right
) ≥ 0 and (top
+bottom
) ≥ 0.The property value shall be an instance of
Insets
orInsets[]
. The array form can be used when a different padding is required for each source image. In that case, the image source index is used as the index for accessing theInsets
element in the array. Null or undefined elements mean that no padding is applied. If the array length is shorter than the number of source images, missing elements are considered as null.- See Also:
-
sampleModel
The sample model shared by all tiles in this image. The sample model width determines this image tile width, and the sample model height determines this image tile height.Design note
ComputedImage
requires the sample model to have exactly the desired tile size otherwise tiles created bycreateTile(int, int)
will consume more memory than needed.- See Also:
-
-
Constructor Details
-
ComputedImage
Creates an initially empty image with the given sample model. The default tile size will be the width and height of the given sample model (this default setting minimizes the amount of memory consumed bycreateTile(int, int)
). This constructor automatically registers aTileObserver
for all sources that areWritableRenderedImage
instances.- Parameters:
sampleModel
- the sample model shared by all tiles in this image.sources
- sources of this image (may be an empty array), or a null array if unknown.
-
-
Method Details
-
getSource
Returns the source at the given index.- Parameters:
index
- index of the desired source.- Returns:
- source at the given index.
- Throws:
IndexOutOfBoundsException
- if the given index is out of bounds.
-
getSources
Returns the immediate sources of image data for this image (may benull
). This method returns all sources specified at construction time.- Specified by:
getSources
in interfaceRenderedImage
- Overrides:
getSources
in classPlanarImage
- Returns:
- the immediate sources, or an empty vector is none, or
null
if unknown.
-
getSampleModel
Returns the sample model associated with this image. All rasters returned from this image will have this sample model. InComputedImage
implementation, the sample model determines the tile size (this is not necessarily true for allRenderedImage
implementations).- Specified by:
getSampleModel
in interfaceRenderedImage
- Returns:
- the sample model of this image.
-
getTileWidth
public final int getTileWidth()Returns the width of tiles in this image. InComputedImage
implementation, this is fixed toSampleModel.getWidth()
.Design note
In theory it is legal to have a tile width smaller than the sample model width, for example when a raster is a view over a subregion of another raster. But this is not allowed inComputedImage
class, because it would causecreateTile(int, int)
to consume more memory than necessary.- Specified by:
getTileWidth
in interfaceRenderedImage
- Returns:
- the width of this image in pixels.
-
getTileHeight
public final int getTileHeight()Returns the height of tiles in this image. InComputedImage
implementation, this is fixed toSampleModel.getHeight()
.Design note
In theory it is legal to have a tile height smaller than the sample model height, for example when a raster is a view over a subregion of another raster. But this is not allowed inComputedImage
class, because it would causecreateTile(int, int)
to consume more memory than necessary.- Specified by:
getTileHeight
in interfaceRenderedImage
- Returns:
- the height of this image in pixels.
-
getTile
Returns a tile of this image, computing it when needed. This method performs the first of the following actions that apply:- If the requested tile is present in the cache and is not dirty, then that tile is returned immediately.
- Otherwise if the requested tile is being computed in another thread,
then this method blocks until the other thread completed its work and returns its result.
If the other thread failed to compute the tile, an
ImagingOpException
is thrown. - Otherwise this method computes the tile and caches the result before to return it.
If an error occurred, an
ImagingOpException
is thrown.
Race conditions with write operations
If this image implements theWritableRenderedImage
interface, then a user may acquire the same tile for a write operation after this method returned. In such case there is no consistency guarantee on sample values: the tile returned by this method may show data in an unspecified stage during the write operation. A synchronization policy may be defined in a future Apache SIS version.- Specified by:
getTile
in interfaceRenderedImage
- Parameters:
tileX
- the column index of the tile to get.tileY
- the row index of the tile to get.- Returns:
- the tile at the given index (never null).
- Throws:
IndexOutOfBoundsException
- if a given tile index is out of bounds.ImagingOpException
- if an error occurred while computing the image.
-
computeTile
protected abstract Raster computeTile(int tileX, int tileY, WritableRaster previous) throws Exception Invoked when a tile need to be computed or updated. This method is invoked bygetTile(int, int)
when the requested tile is not in the cache, or when a writable source notified us that its data changed. The returned tile will be automatically cached.A typical implementation is as below:
@Override protected Raster computeTile(int tileX, int tileY, WritableRaster tile) { if (tile == null) { tile = createTile(tileX, tileY); } // Do calculation here and write results in tile. return tile; }
Error handling
If this method throws an exception or returnsnull
, thengetTile(…)
will set an error flag on the tile and throw anImagingOpException
with the exception thrown bycomputeTile(…)
as its cause. Future invocations ofgetTile(tileX, tileY)
with the same tile indices will cause anImagingOpException
to be thrown immediately without invocation ofcompute(tileX, tileY)
. If the error has been fixed, then users can invokeclearErrorFlags(Rectangle)
for allowing the tile to be computed again.- Parameters:
tileX
- the column index of the tile to compute.tileY
- the row index of the tile to compute.previous
- if the tile already exists but needs to be updated, the tile to update. Otherwisenull
.- Returns:
- computed tile for the given indices. May be the
previous
tile after update but cannot be null. - Throws:
Exception
- if an error occurred while computing the tile.
-
createTile
Creates an initially empty tile at the given tile grid position. This is a helper method forcomputeTile(int, int, WritableRaster)
implementations.- Parameters:
tileX
- the column index of the tile to create.tileY
- the row index of the tile to create.- Returns:
- initially empty tile for the given indices (cannot be null).
-
prefetch
Notifies this image that tiles will be computed soon in the given region. This method is invoked byImageProcessor.prefetch(RenderedImage, Rectangle)
before to request (potentially in multi-threads) all tiles in the area of interest. If the returnedDisposable
is non-null,ImageProcessor
guarantees that theDisposable.dispose()
method will be invoked after the prefetch operation completed, successfully or not.The default implementation does nothing. Subclasses can override this method if they need to allocate and release resources once for a group of tiles.
- Parameters:
tiles
- indices of the tiles which will be prefetched.- Returns:
- handler on which to invoke
dispose()
after the prefetch operation completed (successfully or not), ornull
if none. - Since:
- 1.2
-
hasTileWriters
public boolean hasTileWriters()Returns whether any tile is under computation or is checked out for writing. There is two reasons why this method may returntrue
:- At least one
computeTile(…)
call is running in another thread. - There is at least one call to
markTileWritable(tileX, tileY, true)
call without matching call tomarkTileWritable(tileX, tileY, false)
. This second case may happen if thisComputedImage
is also aWritableRenderedImage
.
- Returns:
- whether any tiles are under computation or checked out for writing.
- See Also:
- At least one
-
isTileWritable
public boolean isTileWritable(int tileX, int tileY) Returns whether the specified tile is currently under computation or checked out for writing. There is two reasons why this method may returntrue
:computeTile(tileX, tileY, …)
is running in another thread.- There is at least one call to
markTileWritable(tileX, tileY, true)
call without matching call tomarkTileWritable(tileX, tileY, false)
. This second case may happen if thisComputedImage
is also aWritableRenderedImage
.
- Parameters:
tileX
- the X index of the tile to check.tileY
- the Y index of the tile to check.- Returns:
- whether the specified tile is under computation or checked out for writing.
- See Also:
-
getWritableTileIndices
Returns the indices of all tiles under computation or checked out for writing, ornull
if none. This method lists all tiles for which the condition documented inisTileWritable(int, int)
istrue
.- Returns:
- an array containing the indices of tiles that are under computation or checked out for writing,
or
null
if none. - See Also:
-
markTileWritable
protected boolean markTileWritable(int tileX, int tileY, boolean writing) Sets or clears whether a tile is checked out for writing. This method is provided for subclasses that implement theWritableRenderedImage
interface. This method can be used as below:class MyImage extends ComputedImage implements WritableRenderedImage { // Constructor omitted for brevity. @Override public WritableRaster getWritableTile(int tileX, int tileY) { WritableRaster raster = ...; // Get the writable tile here. markTileWritable(tileX, tileY, true); return raster; } @Override public void releaseWritableTile(int tileX, int tileY) { markTileWritable(tileX, tileY, false); // Release the raster here. } }
- Parameters:
tileX
- the x index of the tile to acquire or release.tileY
- the y index of the tile to acquire or release.writing
-true
for acquiring the tile, orfalse
for releasing it.- Returns:
true
if the tile goes from having no writers to having one writer (may happen ifwriting
istrue
), or goes from having one writer to no writers (may happen ifwriting
isfalse
).- See Also:
-
markDirtyTiles
Marks all tiles in the given range of indices as in need of being recomputed. The tiles will not be recomputed immediately, but only on next invocation ofgetTile(tileX, tileY)
if the(tileX, tileY)
indices are contained if the specified rectangle.Subclasses can invoke this method when the tiles in the given range depend on source data that changed, typically (but not necessarily) source images. Note that there is no need to invoke this method if the source images are instances of
WritableRenderedImage
, becauseComputedImage
already hasTileObserver
for them.- Parameters:
tiles
- indices of tiles to mark as dirty.- Returns:
true
if at least one tile has been marked dirty.
-
clearErrorFlags
Clears the error status of all tiles in the given range of indices. Those tiles will be marked as dirty and recomputed next time thegetTile(int, int)
method is invoked. The status of valid tiles is unchanged by this method call.- Parameters:
tiles
- indices of tiles for which to clear the error status.- Returns:
true
if at least one tile got its error flag cleared.- See Also:
-
sourceTileChanged
Invoked when a tile of a source image has been updated. This method should mark as dirty all tiles of thisComputedImage
that depend on the updated tile.The default implementation assumes that source images use pixel coordinate systems aligned with this
ComputedImage
in such a way that all pixels at coordinates (x, y) in thesource
image are used for calculation of pixels at the same (x, y) coordinates in thisComputedImage
, possibly expanded to neighborhood pixels if the "org.apache.sis.SourcePadding" property is defined. If this assumption does not hold, then subclasses should override this method and invokemarkDirtyTiles(Rectangle)
themselves.- Parameters:
source
- the image that own the tile which has been updated.tileX
- the x index of the tile that has been updated.tileY
- the y index of the tile that has been updated.
-
dispose
public void dispose()Advises this image that its tiles will no longer be requested. This method removes all tiles from the cache and stops observation ofWritableRenderedImage
sources. This image should not be used anymore after this method call.Note: keep in mind that this image may be referenced as a source of other images. In case of doubt, it may be safer to rely on the garbage collector instead of invoking this method.
- Specified by:
dispose
in interfaceDisposable
-