org.geotoolkit.image.io
Class SpatialImageReader

Object
  extended by ImageReader
      extended by SpatialImageReader
All Implemented Interfaces:
Disposable, Localized, WarningProducer
Direct Known Subclasses:
ImageReaderAdapter, ImageReaderAdapter, RawImageReader, RawTiffImageReader, StreamImageReader

public abstract class SpatialImageReader
extends ImageReader
implements WarningProducer, Disposable

Base class for readers of spatial (usually geographic) data. This class extends the standard ImageReader class in order to improve the support of file formats having the following characteristics:


New API
This class provides the following API, which are new compared to the standard ImageReader class:


Services for implementors
This class provides the following conveniences for implementors. Note that the default behavior described below assumes the simplest file format: one image made of one band of floating point values using a grayscale color palette scaled to fit the range of sample values. This behavior can be changed by overriding the methods listed below.

See the getDestination(int, ImageReadParam, int, int, SampleConverter[]) method for an example of code using some of the services provided by this class.

Since:
3.06 (derived from 1.2)
Version:
3.19
Author:
Martin Desruisseaux (IRD, Geomatys)
See Also:
SpatialImageWriter
Module:
coverage/geotk-coverageio (download)    View source code for this class

Nested Class Summary
protected static class SpatialImageReader.Spi
          Service provider interfaces (SPI) for SpatialImageReaders.
 
Field Summary
 
Fields inherited from class ImageReader
availableLocales, ignoreMetadata, input, locale, minIndex, originatingProvider, progressListeners, seekForwardOnly, updateListeners, warningListeners, warningLocales
 
Fields inherited from interface WarningProducer
LOGGER
 
Constructor Summary
protected SpatialImageReader(SpatialImageReader.Spi provider)
          Constructs a new image reader.
 
Method Summary
protected  void checkBandIndex(int imageIndex, int bandIndex)
          Ensures that the specified band index is inside the expected range.
protected  void checkImageIndex(int imageIndex)
          Ensures that the specified image index is inside the expected range.
protected  void close()
          Invoked when a new input is set or when the reader is disposed.
protected  boolean collapseNoDataValues(boolean isZeroValid, double[] nodataValues, int unusedSpace)
          Returns true if the no-data values should be collapsed to 0 in order to save memory.
protected  SpatialMetadata createMetadata(int imageIndex)
          Creates a new stream or image metadata.
 void dispose()
          Allows any resources held by this reader to be released.
 SpatialImageReadParam getDefaultReadParam()
          Returns a default parameter object appropriate for this format.
protected  BufferedImage getDestination(int imageIndex, ImageReadParam parameters, int width, int height, SampleConverter[] converters)
          Returns the buffered image to which decoded pixel data should be written.
 int getDimension(int imageIndex)
          Returns the number of dimension of the image at the given index.
 GridEnvelope getGridEnvelope(int imageIndex)
          Returns the grid envelope of the image at the given index.
 SpatialMetadata getImageMetadata(int imageIndex)
          Returns metadata associated with the given image.
protected  ImageTypeSpecifier getImageType(int imageIndex, ImageReadParam parameters, SampleConverter[] converters)
          Returns an image type specifier indicating the SampleModel and ColorModel to use for reading the image.
 Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
          Returns a collection of ImageTypeSpecifier containing possible image types to which the given image may be decoded.
 int getNumBands(int imageIndex)
          Returns the number of bands available for the specified image.
 int getNumImages(boolean allowSearch)
          Returns the number of images available from the current input source.
protected  int getRawDataType(int imageIndex)
          Returns the data type which most closely represents the "raw" internal data of the image.
 ImageTypeSpecifier getRawImageType(int imageIndex)
          Returns an image type specifier indicating the SampleModel and ColorModel which most closely represents the "raw" internal format of the image.
 SpatialMetadata getStreamMetadata()
          Returns metadata associated with the input source as a whole.
 boolean hasColors(int imageIndex)
          Returns true if the image at the given index has a color palette.
 void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata)
          Sets the input source to use.
 boolean warningOccurred(LogRecord record)
          Invoked when a warning occurred.
 
Methods inherited from class ImageReader
abort, abortRequested, addIIOReadProgressListener, addIIOReadUpdateListener, addIIOReadWarningListener, canReadRaster, checkReadParamBandSettings, clearAbortRequest, computeRegions, getAspectRatio, getAvailableLocales, getDestination, getFormatName, getHeight, getImageMetadata, getInput, getLocale, getMinIndex, getNumThumbnails, getOriginatingProvider, getSourceRegion, getStreamMetadata, getThumbnailHeight, getThumbnailWidth, getTileGridXOffset, getTileGridYOffset, getTileHeight, getTileWidth, getWidth, hasThumbnails, isIgnoringMetadata, isImageTiled, isRandomAccessEasy, isSeekForwardOnly, processImageComplete, processImageProgress, processImageStarted, processImageUpdate, processPassComplete, processPassStarted, processReadAborted, processSequenceComplete, processSequenceStarted, processThumbnailComplete, processThumbnailPassComplete, processThumbnailPassStarted, processThumbnailProgress, processThumbnailStarted, processThumbnailUpdate, processWarningOccurred, processWarningOccurred, read, read, readAll, readAll, readAsRenderedImage, readerSupportsThumbnails, readRaster, readThumbnail, readTile, readTileRaster, removeAllIIOReadProgressListeners, removeAllIIOReadUpdateListeners, removeAllIIOReadWarningListeners, removeIIOReadProgressListener, removeIIOReadUpdateListener, removeIIOReadWarningListener, reset, setInput, setInput, setLocale
 
Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface Localized
getLocale
 

Constructor Detail

SpatialImageReader

protected SpatialImageReader(SpatialImageReader.Spi provider)
Constructs a new image reader.

Parameters:
provider - The ImageReaderSpi that is constructing this object, or null.
Method Detail

setInput

public void setInput(Object input,
                     boolean seekForwardOnly,
                     boolean ignoreMetadata)
Sets the input source to use. This method invokes close() before to set the new input.

Overrides:
setInput in class ImageReader
Parameters:
input - The input object to use for future decoding.
seekForwardOnly - If true, images and metadata may only be read in ascending order from this input source.
ignoreMetadata - If true, metadata may be ignored during reads.

checkImageIndex

protected void checkImageIndex(int imageIndex)
                        throws IOException,
                               IndexOutOfBoundsException
Ensures that the specified image index is inside the expected range. The expected range is minIndex inclusive (initially 0) to getNumImages(false) exclusive. If getNumImages(false) returned -1, then this method does not check the upper bound.

Parameters:
imageIndex - Index to check for validity.
Throws:
IndexOutOfBoundsException - if the specified index is outside the expected range.
IOException - If the operation failed because of an I/O error.

checkBandIndex

protected void checkBandIndex(int imageIndex,
                              int bandIndex)
                       throws IOException,
                              IndexOutOfBoundsException
Ensures that the specified band index is inside the expected range. The expected range is 0 inclusive to getNumBands(imageIndex) exclusive.

Parameters:
imageIndex - The image index.
bandIndex - Index to check for validity.
Throws:
IndexOutOfBoundsException - if the specified index is outside the expected range.
IOException - If the operation failed because of an I/O error.

getNumImages

public int getNumImages(boolean allowSearch)
                 throws IllegalStateException,
                        IOException
Returns the number of images available from the current input source. The default implementation returns 1.

Specified by:
getNumImages in class ImageReader
Parameters:
allowSearch - If true, the number of images will be returned even if a search is required.
Returns:
The number of images, or -1 if allowSearch is false and a search would be required.
Throws:
IllegalStateException - if the input source has not been set.
IOException - if an error occurs reading the information from the input source.

getNumBands

public int getNumBands(int imageIndex)
                throws IOException
Returns the number of bands available for the specified image. The default implementation returns 1.

Parameters:
imageIndex - The image index.
Returns:
The number of bands available for the specified image.
Throws:
IOException - if an error occurs reading the information from the input source.

getDimension

public int getDimension(int imageIndex)
                 throws IOException
Returns the number of dimension of the image at the given index. The default implementation returns 2. MultidimensionalImageStore implementations provide a different value.

Parameters:
imageIndex - The image index.
Returns:
The number of dimension for the image at the given index.
Throws:
IOException - if an error occurs reading the information from the input source.
Since:
2.5
See Also:
MultidimensionalImageStore

getGridEnvelope

public GridEnvelope getGridEnvelope(int imageIndex)
                             throws IOException
Returns the grid envelope of the image at the given index. The default implementation creates a grid envelope from the information provided by getDimension(int), ImageReader.getWidth(int) and ImageReader.getHeight(int) methods. MultidimensionalImageStore implementations provide a different value.

Parameters:
imageIndex - The image index.
Returns:
The grid envelope for the image at the given index.
Throws:
IOException - if an error occurs reading the information from the input source.
Since:
3.19
See Also:
MultidimensionalImageStore

getStreamMetadata

public SpatialMetadata getStreamMetadata()
                                  throws IOException
Returns metadata associated with the input source as a whole. The default implementation performs the following choice:

Specified by:
getStreamMetadata in class ImageReader
Returns:
The metadata, or null if none.
Throws:
IOException - if an error occurs during reading.

getImageMetadata

public SpatialMetadata getImageMetadata(int imageIndex)
                                 throws IOException
Returns metadata associated with the given image. The default implementation performs the following choice:

Specified by:
getImageMetadata in class ImageReader
Parameters:
imageIndex - The image index.
Returns:
The metadata, or null if none.
Throws:
IOException - if an error occurs during reading.

createMetadata

protected SpatialMetadata createMetadata(int imageIndex)
                                  throws IOException
Creates a new stream or image metadata. This method is invoked by the default implementation of getStreamMetadata() and getImageMetadata(int) when the requested metadata were not cached by a previous call, and ImageReader.isIgnoringMetadata() returns false.

The default implementation returns null if every cases. Subclasses should override this method if they can provide metadata.

Parameters:
imageIndex - -1 for stream metadata, or the image index for image metadata.
Returns:
The requested metadata, or null if none.
Throws:
IOException - If an error occurred while reading metadata.

hasColors

public boolean hasColors(int imageIndex)
                  throws IOException
Returns true if the image at the given index has a color palette. Some formats like RAW, ASCII Grid or NetCDF don't store any color information with the pixel values, while other formats like PNG or JPEG (optionally wrapped in a World File reader) provide such color palette.

If this method returns false, no color information is included in the stream to be read and users can provide their own color palette with a call to the SpatialImageReadParam.setPaletteName(String) method. If this mehod returns true, then the image to be read already have its own color information and any call to the above-mentioned setPaletteName method are likely to be ignored.

The default implementation returns false in every cases. Subclasses shall override this method if the implemented image format may have a color palette.

Parameters:
imageIndex - The index of the image to be queried.
Returns:
true if the image at the given index has a color palette.
Throws:
IOException - If an error occurs reading the information from the input source.
Since:
3.11
See Also:
SpatialImageReadParam.setPaletteName(String)

getImageTypes

public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
                                           throws IOException
Returns a collection of ImageTypeSpecifier containing possible image types to which the given image may be decoded. The default implementation returns a singleton containing getRawImageType(imageIndex).

Specified by:
getImageTypes in class ImageReader
Parameters:
imageIndex - The index of the image to be queried.
Returns:
A set of suggested image types for decoding the current given image.
Throws:
IOException - If an error occurs reading the format information from the input source.

getRawImageType

public ImageTypeSpecifier getRawImageType(int imageIndex)
                                   throws IOException
Returns an image type specifier indicating the SampleModel and ColorModel which most closely represents the "raw" internal format of the image. The default implementation delegates to the following:
return getImageType(imageIndex, getDefaultReadParam(), null);
If this method needs to be overridden, consider overriding the later instead.

Overrides:
getRawImageType in class ImageReader
Parameters:
imageIndex - The index of the image to be queried.
Returns:
The image type (never null).
Throws:
IOException - If an error occurs reading the format information from the input source.
See Also:
getImageType(int, ImageReadParam, SampleConverter[]), getDefaultReadParam()

getImageType

protected ImageTypeSpecifier getImageType(int imageIndex,
                                          ImageReadParam parameters,
                                          SampleConverter[] converters)
                                   throws IOException
Returns an image type specifier indicating the SampleModel and ColorModel to use for reading the image. In addition, this method also detects if some conversions (represented by SampleConverter instances) are required in order to store the sample values using the selected models. The conversions (if any) are keept as small as possible, but are sometime impossible to avoid for example because IndexColorModel does not allow negative sample values.

The default implementation applies the following steps:

  1. The range of expected values and the fill values are extracted from the image metadata, if any.

  2. If the given parameters argument is an instance of SpatialImageReadParam, then the user-supplied palette name is fetched. Otherwise or if no palette name was explicitly set, then this method default to "grayscale". The palette name will be used in order to read a predefined set of colors (as [A]RGB values) to be given to the index color model.

  3. If the raw data type is TYPE_FLOAT or TYPE_DOUBLE, then this method builds a continuous palette suitable for the range fetched at step 1. The data are assumed geophysics values rather than some packed values. Consequently, the sample converters will replace no-data values by NaN, but no other changes will be applied.

  4. Otherwise, if the raw data type is a unsigned integer type like TYPE_BYTE or TYPE_USHORT, then this method builds an indexed palette (i.e. a palette backed by an index color model) with just the minimal size needed for containing fully the range and the no-data values fetched at step 1. The data are assumed packed values rather than geophysics values. Consequently, the sample converters will be the identity converter except in the following cases:

    • The range of valid values is outside the range allowed by the raw data type (e.g. the range of valid values contains negative integers). In this case, the sample converter will shift the values to a strictly positive range and replace fill values by 0.
    • At least one fill value is outside the range of values allowed by the raw data type. In this case, this method will try to only replace the fill values by 0, without shifting the valid values if this shift can be avoided.
    • At least one fill value is far away from the range of valid values (for example 9999 while the range of valid values is [0…255]). The meaning of "far away" is determined by the collapseNoDataValues method.

  5. Otherwise, if the raw data type is a signed integer type like TYPE_SHORT, then this method builds an indexed palette with the maximal size supported by the raw data type (note that this is memory expensive - typically 256 kilobytes). Negative values will be stored in their two's complement binary form in order to fit in the range of positive integers supported by the index color model.

Using the Sample Converters
If the converters argument is non-null, then this method will store the SampleConverter instances in the supplied array. The array length shall be equals to the number of source and destination bands.

The converters shall be used by read method implementations for converting the values read in the datafile to values acceptable by the color model. See the getDestination method for code example.

Overriding this method
Subclasses can override this method for example if the color palette and range of values should be computed in a different way. The example below creates an image type using hard-coded objects:

int minimum     = -2000;      // Minimal expected value
int maximum     = +2300;      // Maximal expected value
int fillValue   = -9999;      // Value for missing data
String colors   = "rainbow";  // Named set of RGB colors
converters[0]   = SampleConverter.createOffset(1 - minimum, fillValue);
Palette palette = PaletteFactory.getDefault().getPalettePadValueFirst(colors, maximum - minimum);
return palette.getImageTypeSpecifier();

Parameters:
imageIndex - The index of the image to be queried.
parameters - The user-supplied parameters, or null. Note: we recommend to supply getDefaultReadParam() instead of null since subclasses may override the later with default values suitable to a particular format.
converters - If non-null, an array where to store the converters created by this method. The length of this array shall be equals to the number of target bands.
Returns:
The image type (never null).
Throws:
IOException - If an error occurs while reading the format information from the input source.
See Also:
getRawDataType(int), collapseNoDataValues(boolean, double[], int), getDestination(int, ImageReadParam, int, int, SampleConverter[])

getRawDataType

protected int getRawDataType(int imageIndex)
                      throws IOException
Returns the data type which most closely represents the "raw" internal data of the image. It should be one of DataBuffer TYPE_* constants. This information is used by getImageType(...) in order to create a default ImageTypeSpecifier.

The default SpatialImageReader implementation works better with TYPE_BYTE, TYPE_SHORT, TYPE_USHORT and TYPE_FLOAT. Other types may work, but developers are advised to override the getImageType(...) method as well.

The default implementation returns TYPE_FLOAT in every cases.

Special case for negative integer values (TYPE_SHORT)
If the sample values are integers but the range of valid values contains negative values, then strictly speaking this method should return a signed type (TYPE_SHORT or TYPE_INT). If nevertheless this method return a unsigned type (TYPE_BYTE or TYPE_USHORT), then the default getImageType(...) implementation will add an offset in order to fit all sample values in the range of strictly positive values.

Example: if the range of sample values is [-23000 … +23000], then there is a choice:
  1. Signed integers storage: If this method returns TYPE_SHORT, then the data will be stored "as is" without transformation. However the size of the Index Color Model will be the maximal length allowed by 16 bits integers, which result in a Color Model consuming 256 kilobytes of memory no matter how large is the range of values actually used.

    Positive values are stored in the [0 … 32767] range directly, while the negative values are converted in their two's complement binary form before to be stored in the [32768 … 65535] range. The space not used by the [-23000 … +23000] range is lost.

  2. Unsigned integers storage: If this method returns TYPE_USHORT, then the data will be translated to the smallest strictly positive range that can holds the data ([1 … 46001] for the above example). The 0 value is reserved for missing data. The result is a smaller Index Color Model than the one used by untranslated data.

Beware that signed integers (case 1 in the above example) used with IndexColorModel require explicit casts to the short type as in the example below. Using directly the Raster.getSample(int,int,int) return value is not sufficient because the returned value would be unsigned no matter what this getRawDataType(int) method returned.

int value = (short) myRaster.getSample(x, y, b); // Intentional casts int → short → int.
Given this gotcha and the fact that signed integers require large color palette, users are advised to prefer unsigned types if they can afford the offset applied on sample values.

Parameters:
imageIndex - The index of the image to be queried.
Returns:
The data type (DataBuffer.TYPE_FLOAT by default).
Throws:
IOException - If an error occurs reading the format information from the input source.
See Also:
getImageType(int, ImageReadParam, SampleConverter[]), SampleConversionType.SHIFT_SIGNED_INTEGERS

collapseNoDataValues

protected boolean collapseNoDataValues(boolean isZeroValid,
                                       double[] nodataValues,
                                       int unusedSpace)
Returns true if the no-data values should be collapsed to 0 in order to save memory. This method is invoked automatically by the getImageType(...) method when it detected some unused space between the range of valid values and at least one no-data value.

The default implementation returns false in all cases, thus avoiding arbitrary choice. Subclasses can override this method with some arbitrary threashold, as in the example below:

return unusedSpace >= 1024;

Parameters:
isZeroValid - true if 0 is a valid value. If this method returns true while isZeroValid is true, then the sample converter to be returned by getImageType(...) will offset all valid values by 1.
nodataValues - The sorted no-data values (never null and never empty).
unusedSpace - The largest amount of unused space outside the range of valid values.
Returns:
true if the no-data values should be collapsed to 0 in order to save memory.

getDestination

protected BufferedImage getDestination(int imageIndex,
                                       ImageReadParam parameters,
                                       int width,
                                       int height,
                                       SampleConverter[] converters)
                                throws IOException
Returns the buffered image to which decoded pixel data should be written. The image is determined by inspecting the supplied parameters if it is non-null, as described in the super-class method. In addition, this method also detects if the sample values need to be converted before to be stored in the BufferedImage, for example because IndexColorModel does not support negative integers. The conversions (if any) are represented by SampleConverter objects, which are computed as documented in the getImageType method.

Using the Sample Converters
If the converters argument is non-null, then this method will store the SampleConverter instances in the supplied array. The array length shall be equals to the number of source and destination bands.

The converters shall be used by read method implementations for converting the values read in the datafile to values acceptable by the color model. Example (omitting the subsamplings handling for simplicity):

public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    final int[] srcBands, dstBands;
    if (param != null) {
        srcBands = param.getSourceBands();
        dstBands = param.getDestinationBands();
    } else {
        srcBands = null;
        dstBands = null;
    }
    final int numSrcBands = (srcBands != null) ? srcBands.length : ...; // Image-dependant
    final int numDstBands = (dstBands != null) ? dstBands.length : numSrcBands;
    checkReadParamBandSettings(param, numSrcBands, numDstBands);

    final int width  = ...;  // Image-dependant
    final int height = ...;  // Image-dependant
    final SampleConverter[] converters = new SampleConverter[numDstBands];
    final BufferedImage  image  = getDestination(imageIndex, param, width, height, converters);
    final WritableRaster raster = image.getRaster();
    final Rectangle   srcRegion = new Rectangle();
    final Rectangle  destRegion = new Rectangle();
    computeRegions(param, width, height, image, srcRegion, destRegion);
    final int xmin = destRegion.x;
    final int ymin = destRegion.y;
    final int xmax = destRegion.width  + xmin;
    final int ymax = destRegion.height + ymin;
    for (int band=0; band < numDstBands; band++) {
        final int srcBand = (srcBands == null) ? band : srcBands[band];
        final int dstBand = (dstBands == null) ? band : dstBands[band];
        final SampleConverter converter = converters[band];
        for (int y=ymin; y<ymax; y++) {
            for (int x=xmin; x<xmax; x++) {
                float value = ...; // Image-dependant
                value = converter.convert(value);
                raster.setSample(x, y, dstBand, value);
            }
        }
    }
}

Parameters:
imageIndex - The index of the image to be retrieved.
parameters - The parameter given to the read method.
width - The true width of the image or tile begin decoded.
height - The true width of the image or tile being decoded.
converters - If non-null, an array where to store the converters required for converting decoded pixel data into stored pixel data.
Returns:
The buffered image to which decoded pixel data should be written.
Throws:
IOException - If an error occurs reading the format information from the input source.
See Also:
getImageType(int, ImageReadParam, SampleConverter[])

getDefaultReadParam

public SpatialImageReadParam getDefaultReadParam()
Returns a default parameter object appropriate for this format. The default implementation constructs and returns a new SpatialImageReadParam.

Overrides:
getDefaultReadParam in class ImageReader
Returns:
An ImageReadParam object which may be used.

warningOccurred

public boolean warningOccurred(LogRecord record)
Invoked when a warning occurred. The default implementation makes the following choice:

Subclasses may override this method if more processing is wanted, or for throwing exception if some warnings should be considered as fatal errors.

Specified by:
warningOccurred in interface WarningProducer
Parameters:
record - The warning to log.
Returns:
true if the message has been sent to at least one warning listener, or false if it has been sent to the logging system as a fallback.
See Also:
MetadataNodeParser.warningOccurred(LogRecord)

close

protected void close()
              throws IOException
Invoked when a new input is set or when the reader is disposed. The default implementation clears the internal cache. Sub-classes can override this method if they have more resources to dispose, but should always invoke super.close().

Throws:
IOException - If an error occurred while closing a stream.
Since:
3.16

dispose

public void dispose()
Allows any resources held by this reader to be released. If an input stream were created by StreamImageReader or ImageReaderAdapter, it will be closed before to dispose this reader.

Specified by:
dispose in interface Disposable
Overrides:
dispose in class ImageReader


Copyright © 2009-2013 Geotoolkit.org. All Rights Reserved.