Class ImageRenderer
GridCoverage.render(GridExtent).
This builder does not copy any sample values. Instead, it wraps existing data arrays into
Raster objects by computing required information such as
pixel stride,
scanline stride and
band offsets.
Different setData(…) methods are provided for allowing to specify the data arrays
from different objects such as Java2D DataBuffer or NIO Buffer.
All setData(…) methods assume that the first valid element in each array is the value
located at GridCoverage.getGridGeometry().getExtent().getLow(). This ImageRenderer class
computes automatically the offsets from that position to the position of the first value included
in the sliceExtent given to the constructor.
Limitations
Current implementation constructs only images made of a single tile. Support for tiled images will be added in a future version.- Since:
- 1.0
- Version:
- 1.3
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classABufferedImagewhich will compute the "org.apache.sis.GridGeometry" property when first needed. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate int[]Offset to add to index of sample values in each band in order to reach the value in theDataBufferbank.private final SampleDimension[]The sample dimensions, to be used for defining the bands.private int[]Bank indices for each band, ornullfor 0, 1, 2, 3….private DataBufferThe data to render, ornullif not yet specified.The colors to use for each category.private final GridGeometryThe grid geometry of theGridCoveragespecified at construction time.private final int[]The dimensions to select in the grid coverage for producing an image.private final intHeight (number of pixels in a column) of the image to render.private GridGeometryThe result ofgetImageGeometry(int)if the specified number of dimension 2.private final intPixel coordinates of the image upper-left corner, as an offset relative to thesliceExtent.private final intPixel coordinates of the image upper-left corner, as an offset relative to thesliceExtent.private static final org.opengis.referencing.operation.MathTransformFactoryThe factory to use forMathTransformcreations, ornullfor a default factory.private final longLocation of the first image pixel relative to the grid coverage extent.private final longLocation of the first image pixel relative to the grid coverage extent.private final longOffset to add tobufferoffset for reaching the first sample value for the slice to render.private final intNumber of data elements between two samples for the same band on the same line.The properties to give to the image, ornullif none.private final intNumber of data elements between a given sample and the corresponding sample in the same column of the next line.private final GridExtentThe requested slice, ornullif unspecified.private intMultiplication factor forpixelStrideandscanlineStride.private intThe band to use for defining pixel colors when the image is displayed on screen.private final intWidth (number of pixels in a row) of the image to render. -
Constructor Summary
ConstructorsConstructorDescriptionImageRenderer(GridCoverage coverage, GridExtent sliceExtent) Creates a new image renderer for the given slice extent. -
Method Summary
Modifier and TypeMethodDescriptionvoidaddProperty(String key, Object value) Adds a value associated to a property.Creates an image with the data specified by the last call to asetData(…)method.Creates a raster with the data specified by the last call to asetData(…)method.private voidensureExpectedBandCount(int n, boolean acceptOne) Ensures that the given number is equal to the expected number of bands.final RectangleReturns the location of the image upper-left corner together with the image size.getImageGeometry(int dimCRS) Computes the conversion from pixel coordinates to CRS, together with the geospatial envelope of the image.final intReturns the number of bands that the image will have.getProperty(String key) Returns the value associated to the given property.final int[]The dimensions to select in the grid coverage for producing an image.private booleanisSameGeometry(int dimCRS) Returnstrueif agetImageGeometry(int)request for the given number of CRS dimensions can returngeometrydirectly.voidsetCategoryColors(Function<Category, Color[]> colors) Specifies the colors to apply for each category in a sample dimension.voidsetData(DataBuffer data) Sets the data as a Java2D buffer.voidSets the data as NIO buffers.voidSets the data as vectors.voidsetInterleavedPixelOffsets(int pixelStride, int[] bandOffsets) Specifies the offsets to add to sample index in each band in order to reach the sample value in theDataBufferbank.voidsetVisibleBand(int band) Specifies the band to use for defining pixel colors when the image is displayed on screen.
-
Field Details
-
geometry
The grid geometry of theGridCoveragespecified at construction time. Nevernull. -
sliceExtent
The requested slice, ornullif unspecified. If unspecified, then the extent to use is the full coverage grid extent. -
gridDimensions
private final int[] gridDimensionsThe dimensions to select in the grid coverage for producing an image. This is an array of length 2 obtained byGridExtent.getSubspaceDimensions(int). The array content is almost always {0,1}, but this class should work with other dimensions too.- See Also:
-
imageGeometry
The result ofgetImageGeometry(int)if the specified number of dimension 2. This is cached for avoiding to recompute this geometry if asked many times.- See Also:
-
offsetZ
private final long offsetZOffset to add tobufferoffset for reaching the first sample value for the slice to render. This is zero for a two-dimensional image, but may be greater for cube having more dimensions. Despite the "Z" letter in the field name, this field actually combines the offset for all dimensions other than X and Y. -
offsetX
private final long offsetXLocation of the first image pixel relative to the grid coverage extent. The (0,0) offset means that the first pixel in thesliceExtent(specified at construction time) is the first pixel in the wholeGridCoverage.Note: if those offsets exceed 32 bits integer capacity, then it may not be possible to build an image for givensliceExtentfrom a singleDataBuffer, because accessing sample values would exceed the capacity of index in Java arrays. In those cases the image needs to be tiled. -
offsetY
private final long offsetYLocation of the first image pixel relative to the grid coverage extent. The (0,0) offset means that the first pixel in thesliceExtent(specified at construction time) is the first pixel in the wholeGridCoverage.Note: if those offsets exceed 32 bits integer capacity, then it may not be possible to build an image for givensliceExtentfrom a singleDataBuffer, because accessing sample values would exceed the capacity of index in Java arrays. In those cases the image needs to be tiled. -
imageX
private final int imageXPixel coordinates of the image upper-left corner, as an offset relative to thesliceExtent. This is initially zero (unlesssliceExtentis partially outside the grid coverage extent), but a different value may be used if the given data are tiled. -
imageY
private final int imageYPixel coordinates of the image upper-left corner, as an offset relative to thesliceExtent. This is initially zero (unlesssliceExtentis partially outside the grid coverage extent), but a different value may be used if the given data are tiled. -
width
private final int widthWidth (number of pixels in a row) of the image to render. This is usually set to the grid extent along the first dimension having a size greater than 1.- See Also:
-
height
private final int heightHeight (number of pixels in a column) of the image to render. This is usually set to the grid extent along the second dimension having a size greater than 1.- See Also:
-
pixelStride
private final int pixelStrideNumber of data elements between two samples for the same band on the same line. This is the product of grid sizes of enclosingGridCoveragein all dimensions before the dimension of image width. This stride does not include the multiplication factor for the number of bands in a pixel interleaved sample model because whether this factor is needed or not depends on the data buffer, which is not known at construction time.- See Also:
-
scanlineStride
private final int scanlineStrideNumber of data elements between a given sample and the corresponding sample in the same column of the next line. This is the product of grid sizes of enclosingGridCoveragein all dimensions before the dimension of image height. This stride does not include the multiplication factor for the number of bands in a pixel interleaved sample model because whether this factor is needed or not depends on the data buffer, which is not known at construction time. -
strideFactor
private int strideFactorMultiplication factor forpixelStrideandscanlineStride. This is the number of data elements between two samples in the databuffer. There is no direct equivalent injava.awt.imagebecause pixel stride and scanline stride inSampleModelare pre-multiplied by this factor, but we need to keep this information separated in this builder because its value depends on which methods are invoked:- If
setInterleavedPixelOffsets(int, int[])is invoked, this is the value given to that method. - Otherwise if
setData(DataBuffer)is invoked and the given buffer has only one bank, then this isgetNumBands(). - Otherwise this is 1.
- See Also:
- If
-
bands
The sample dimensions, to be used for defining the bands. -
bandOffsets
private int[] bandOffsetsOffset to add to index of sample values in each band in order to reach the value in theDataBufferbank. This is closely related toComponentSampleModel.bandOffsetsbut not identical, because of the following differences:- Another offset for
offsetXandoffsetYmay need to be added before to give thebandOffsetstoSampleModelconstructor. - If null, a default value is inferred depending on whether the
SampleModelto construct is banded or interleaved.
- See Also:
- Another offset for
-
bankIndices
private int[] bankIndicesBank indices for each band, ornullfor 0, 1, 2, 3…. If non-null, this array length must be equal tobandsarray length. -
visibleBand
private int visibleBandThe band to use for defining pixel colors when the image is displayed on screen. All other bands, if any, will exist in the raster but be ignored at display time.- See Also:
-
buffer
The data to render, ornullif not yet specified. If non-null,DataBuffer.getNumBanks()must be equal tobandsarray length. -
colors
The colors to use for each category. Nevernull. The function may returnnull, which means transparent. The default value isColorizer.GRAYSCALE.- See Also:
-
properties
The properties to give to the image, ornullif none.- See Also:
-
mtFactory
private static final org.opengis.referencing.operation.MathTransformFactory mtFactoryThe factory to use forMathTransformcreations, ornullfor a default factory.For now this is fixed to
null. But it may become a non-static, non-final field in a future version if we want to make this property configurable.
-
-
Constructor Details
-
ImageRenderer
Creates a new image renderer for the given slice extent.- Parameters:
coverage- the source coverage for which to build an image.sliceExtent- the domain from which to create an image, ornullfor thecoverageextent.- Throws:
SubspaceNotSpecifiedException- if this method cannot infer a two-dimensional slice fromsliceExtent.DisjointExtentException- if the given extent does not intersect the given coverage.ArithmeticException- if a stride calculation overflows the 32 bits integer capacity.
-
-
Method Details
-
getNumBands
public final int getNumBands()Returns the number of bands that the image will have. By default, this is the number of sample dimensions in the grid coverage.- Returns:
- the number of bands in the rendered image.
-
ensureExpectedBandCount
private void ensureExpectedBandCount(int n, boolean acceptOne) Ensures that the given number is equal to the expected number of bands. The given number shall be either 1 (case of interleaved sample model) orgetNumBands()(case of banded sample model). -
getBounds
Returns the location of the image upper-left corner together with the image size. The image coordinate system is relative to thesliceExtentspecified at construction time: the (0,0) pixel coordinates correspond to thesliceExtentlow coordinates. Consequently, the rectangle x and y coordinates are (0,0) if the image is located exactly in the area requested bysliceExtent, or is shifted as below otherwise:( x, y ) = (grid coordinates of actually provided region) − (grid coordinates of requested region)
- Returns:
- the rendered image location and size (never null).
-
getXYDimensions
public final int[] getXYDimensions()The dimensions to select in the grid coverage for producing an image. This is the array obtained by. The array content is almost always {0,1}, i.e. the 2 first dimensions in a coordinate tuple.GridExtent.getSubspaceDimensions(2)- Returns:
- indices of x and y coordinate values in a grid coordinate tuple.
- Since:
- 1.3
-
getImageGeometry
Computes the conversion from pixel coordinates to CRS, together with the geospatial envelope of the image. TheGridGeometryreturned by this method is derived from the coverage grid geometry with the following changes:- The number of grid dimensions is always 2.
- The number of CRS dimensions
is specified by
dimCRS(usually 2). - The envelope may be a sub-region of the coverage envelope.
- The grid extent is the image bounds.
- The grid to CRS transform is derived from the coverage transform
with a translation for mapping the
sliceExtentlow coordinates to (0,0) pixel coordinates.
- Parameters:
dimCRS- desired number of dimensions in the CRS. This is usually 2.- Returns:
- conversion from pixel coordinates to CRS of the given number of dimensions, together with image bounds and geospatial envelope if possible.
- Since:
- 1.1
- See Also:
-
getProperty
Returns the value associated to the given property. By default the only property is "org.apache.sis.GridGeometry", but more properties can be added by calls toaddProperty(String, Object).- Parameters:
key- the property for which to get a value.- Returns:
- value associated to the given property, or
nullif none. - Since:
- 1.1
-
addProperty
Adds a value associated to a property. This method can be invoked only once for eachkey. Those properties will be given to the image created by thecreateImage()method.- Parameters:
key- key of the property to set.value- value to associate to the given key.- Throws:
IllegalArgumentException- if a value is already associated to the given key.- Since:
- 1.1
-
isSameGeometry
private boolean isSameGeometry(int dimCRS) Returnstrueif agetImageGeometry(int)request for the given number of CRS dimensions can returngeometrydirectly. This common case avoids the need for more costly computation withSliceGeometry. -
setData
Sets the data as a Java2D buffer. The number of banks in the given buffer must be equal to the expected number of bands. In each bank, the value located at the bank offset is the value located atGridCoverage.getGridGeometry().getExtent().getLow(), as specified in class javadoc.- Parameters:
data- the Java2D buffer containing data for all bands.- Throws:
NullArgumentException- ifdatais null.MismatchedCoverageRangeException- if the given data buffer does not have the expected amount of banks.
-
setData
Sets the data as NIO buffers. The number of buffers must be equal to the expected number of bands. All buffers must be backed by arrays of the type specified by thedataTypeargument and have the same amount of remaining elements. This method wraps the underlying arrays of a primitive type into a Java2D buffer; data are not copied. For each buffer, the grid coverage data (not only the slice data) starts at buffer position and ends at that position + remaining.The data type must be specified in order to distinguish between the signed and unsigned types.
DataType.BYTEandDataType.USHORTare unsigned, all other supported types are signed.Implementation note: the Java2D buffer is set by a call to
setData(DataBuffer), which can be overridden by subclasses if desired.- Parameters:
dataType- type of data.data- the buffers wrapping arrays of primitive type.- Throws:
NullArgumentException- ifdatais null or one ofdataelement is null.MismatchedCoverageRangeException- if the number of specified buffers is not equal to the number of bands.UnsupportedOperationException- if a buffer is not backed by an accessible array or is read-only.ArrayStoreException- if a buffer type is incompatible withdataType.RasterFormatException- if buffers do not have the same amount of remaining values.ArithmeticException- if a buffer position overflows the 32 bits integer capacity.- Since:
- 1.1
-
setData
Sets the data as vectors. The number of vectors must be equal to the expected number of bands. All vectors must be backed by arrays (indirectly, through buffers backed by arrays) and have the same size. This method wraps the underlying arrays of a primitive type into a Java2D buffer; data are not copied.Implementation note: the NIO buffers are set by a call to
setData(DataType, Buffer...), which can be overridden by subclasses if desired.- Parameters:
data- the vectors wrapping arrays of primitive type.- Throws:
NullArgumentException- ifdatais null or one ofdataelement is null.MismatchedCoverageRangeException- if the number of specified vectors is not equal to the number of bands.UnsupportedOperationException- if a vector is not backed by an accessible array or is read-only.RasterFormatException- if vectors do not have the same size.ArithmeticException- if a buffer position overflows the 32 bits integer capacity.
-
setInterleavedPixelOffsets
public void setInterleavedPixelOffsets(int pixelStride, int[] bandOffsets) Specifies the offsets to add to sample index in each band in order to reach the sample value in theDataBufferbank. This method should be invoked when the data given tosetData(…)contains only oneVector,BufferorDataBufferbank, and the bands in that unique bank are interleaved.Example: for an image having three bands named Red (R), Green (G) and Blue (B), if the sample values are stored in a single bank in a R₀,G₀,B₀, R₁,G₁,B₁, R₂,G₂,B₂, R₃,G₃,B₃, etc. fashion, then this method should be invoked as below:- Parameters:
pixelStride- the number of data elements between each pixel in the data vector or buffer.bandOffsets- offsets to add to sample index in each band. This is typically {0, 1, 2, …}. The length of this array shall be equal togetNumBands().
-
setVisibleBand
public void setVisibleBand(int band) Specifies the band to use for defining pixel colors when the image is displayed on screen. All other bands, if any, will exist in the raster but be ignored at display time. The default value is 0, the first (and often only) band.Implementation note: anIndexColorModelwill be used for displaying the image.- Parameters:
band- the band to use for display purpose.- Throws:
IllegalArgumentException- if the given band is not between 0 (inclusive) andgetNumBands()(exclusive).- Since:
- 1.2
-
setCategoryColors
Specifies the colors to apply for each category in a sample dimension. The given function can returnnull, which means transparent. If this method is never invoked, then the default is a grayscale for quantitative categories and transparent for qualitative categories (typically "no data" values).Example
the following code specifies a color palette from blue to red with white in the middle. This is useful for data with a clear 0 (white) in the middle of the range, with a minimal value equals to the negative of the maximal value.- Parameters:
colors- the colors to use for each category. Thecolorsargument cannot be null, butcolors.apply(Category)can return null.- Since:
- 1.2
-
createRaster
Creates a raster with the data specified by the last call to asetData(…)method. The raster upper-left corner is located at the position given bygetBounds(). The returned raster is often an instance ofWritableRaster, but read-only rasters are also allowed.- Returns:
- the raster, usually (but not necessarily) an instance of
WritableRaster. - Throws:
IllegalStateException- if nosetData(…)method has been invoked before this method call.RasterFormatException- if a call to aRasterfactory method failed.ArithmeticException- if a property of the raster to construct exceeds the capacity of 32 bits integers.- Since:
- 1.1
-
createImage
Creates an image with the data specified by the last call to asetData(…)method. The image upper-left corner is located at the position given bygetBounds(). The two-dimensional image geometry is stored as a property associated to the "org.apache.sis.GridGeometry" key.The default implementation returns an instance of
WritableRenderedImageif thecreateRaster()return value is an instance ofWritableRaster, or a read-onlyRenderedImageotherwise.- Returns:
- the image.
- Throws:
IllegalStateException- if nosetData(…)method has been invoked before this method call.RasterFormatException- if a call to aRasterfactory method failed.ArithmeticException- if a property of the image to construct exceeds the capacity of 32 bits integers.- Since:
- 1.1
-