Class AsciiGridStore

All Implemented Interfaces:
AutoCloseable, ResourceOnFileSystem, StoreResource, DataSet, GridCoverageResource, Resource, Localized
Direct Known Subclasses:
WritableStore

class AsciiGridStore extends RasterStore
Data store implementation for ESRI ASCII grid format. This is a very simple format for reading and writing single-banded raster data. As the "ASCII" name implies, files are text files in US-ASCII character encoding no matter what the OptionKey.ENCODING value is, and numbers are parsed or formatted according the US locale no matter what the OptionKey.LOCALE value is.

ASCII grid files contains a header before the actual data. The header contains (key value) pairs, one pair per line and using spaces as separator between keys and values. The valid keys are listed in the table below (note that some of them are extensions to the ESRI ASCII Grid format).

Recognized keywords in ASCII Grid header
Keyword Value type Obligation
NCOLS Integer Mandatory
NROWS Integer Mandatory
XLLCORNER or XLLCENTER Double Mandatory
YLLCORNER or YLLCENTER Double Mandatory
CELLSIZE Double Mandatory, unless an alternative below is present
XCELLSIZE and YCELLSIZE Double Non-standard alternative to CELLSIZE
XDIM and YDIM Double Non-standard alternative to CELLSIZE
DX and DY Double Non-standard alternative to CELLSIZE
NODATA_VALUE Double Optional

Extensions

The implementation in this package adds the following extensions (some of them are taken from GDAL):
  • Coordinate reference system specified by auxiliary *.prj file. If the format is WKT 1, the GDAL variant is used (that variant differs from the OGC 01-009 standard in their interpretation of units of measurement).
  • XCELLSIZE and YCELLSIZE parameters in the header are used instead of CELLSIZE if the pixels are non-square.
  • Lines in the header starting with '#' are ignored as comment lines.

Possible evolutions

If we allow subclasses in a future version, we could add a processHeader(Map) method that subclasses can override for processing their own (key, value) pairs or for modifying the values of existing pairs.

Limitations

Current implementation loads and caches the full image no matter the subregion or subsampling specified to the read(…) method. The image is loaded by getSampleDimensions() call too, because there is no other way to build a reliable sample dimension. Even the data type cannot be determined for sure without loading the full image. Loading the full image is reasonable if ASCII Grid files contain only small images, which is usually the case given how inefficient this format is.
Since:
1.2
Version:
1.3
  • Field Details

    • XLLCORNER

      static final String XLLCORNER
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • YLLCORNER

      static final String YLLCORNER
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • XLLCENTER

      static final String XLLCENTER
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • YLLCENTER

      static final String YLLCENTER
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • CELLSIZE

      static final String CELLSIZE
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • NODATA_VALUE

      static final String NODATA_VALUE
      Keys of elements expected in the header. Must be in upper-case letters.
      See Also:
    • CELLSIZES

      static final String[] CELLSIZES
      Alternatives names for "CELLSIZE" when the pixels are not squares. Those names are not part of the format defined by ESRI. Various implementations use different names.

      Names at even indices are for the x axis and names at odd indices are for the y axis.

    • DEFAULT_NODATA

      private static final double DEFAULT_NODATA
      The default no-data value. This is part of the ASCII Grid format specification.
      See Also:
    • input

      private CharactersView input
      The object to use for reading data, or null if the channel has been closed. Note that a null value does not necessarily means that the store is closed, because it may have finished to read fully the coverage.
    • width

      private int width
      The NCOLS and NROWS attributes read from the header. Those values are valid only if gridGeometry is non-null.
    • height

      private int height
      The NCOLS and NROWS attributes read from the header. Those values are valid only if gridGeometry is non-null.
    • nodataText

      private String nodataText
      The RasterStore.nodataValue as a text. This is useful when the fill value cannot be parsed as a double value, for example "NULL", "N/A", "NA", "mv", "!" or "-".
    • gridGeometry

      private GridGeometry gridGeometry
      The image size together with the "grid to CRS" transform. This is also used as a flag for checking whether the "*.prj" file and the header have been read.
    • coverage

      private GridCoverage coverage
      The full coverage, read when first requested then cached. We cache the full coverage on the assumption that the ASCII Grid format is not used for very large images.
  • Constructor Details

    • AsciiGridStore

      AsciiGridStore(AsciiGridStoreProvider provider, StorageConnector connector, boolean readOnly) throws DataStoreException
      Creates a new ASCII Grid store from the given file, URL or stream. This constructor opens the file, possibly creating it if the connector contains an option like StandardOpenOption.CREATE, but does not try to read it now. It is possible to open an empty file and have WritableStore to write in it later.
      Parameters:
      provider - the factory that created this DataStore instance, or null if unspecified.
      connector - information about the storage (URL, stream, etc).
      readOnly - whether to fail if the channel cannot be opened at least in read mode.
      Throws:
      DataStoreException - if an error occurred while opening the stream.
  • Method Details

    • canReadOrWrite

      boolean canReadOrWrite(boolean write)
      Returns whether this store can read or write. If this store cannot write, then we can close the input channel as soon as the coverage has been fully read. Otherwise we need to keep it open.
      Parameters:
      write - false for testing read capability, or true for testing write capability.
    • readHeader

      private void readHeader() throws DataStoreException
      Reads the "*.prj" file and the header if not already done. This method does nothing if the data store is already initialized. After a successful return, gridGeometry is guaranteed non-null.

      Note: we don't do this initialization in the constructor for giving a chance for users to register listeners first.

      Throws:
      DataStoreException
    • messageForProperty

      private String messageForProperty(short rk, String key)
      Returns the error message for an exception or log record.
      Parameters:
      rk - Errors.Keys.IllegalValueForProperty_2 or Errors.Keys.MissingValueForProperty_2.
      key - key of the header property which was requested.
      Returns:
      the message to use in the exception to be thrown or the warning to be logged.
    • getHeaderValue

      private String getHeaderValue(Map<String,String> header, String key) throws DataStoreException
      Gets a value from the header map and ensures that it is non-null. The entry is removed from the header map for making easy to see if there is any unknown key left.
      Parameters:
      header - map of (key, value) pairs from the header.
      key - the name of the properties to get.
      Returns:
      the value, guaranteed to be non-null.
      Throws:
      DataStoreException - if the value was null.
    • getMetadata

      public org.opengis.metadata.Metadata getMetadata() throws DataStoreException
      Returns the metadata associated to the ASII grid file. The returned object contains only the metadata that can be computed without reading the whole image.
      Specified by:
      getMetadata in interface Resource
      Specified by:
      getMetadata in class DataStore
      Returns:
      the metadata associated to the ASCII grid file.
      Throws:
      DataStoreException - if an error occurred during the parsing process.
      See Also:
    • getGridGeometry

      public GridGeometry getGridGeometry() throws DataStoreException
      Returns the valid extent of grid coordinates together with the conversion from those grid coordinates to real world coordinates.
      Returns:
      extent of grid coordinates together with their mapping to "real world" coordinates.
      Throws:
      DataStoreException - if an error occurred while reading definitions from the underlying data store.
      See Also:
    • getSampleDimensions

      public List<SampleDimension> getSampleDimensions() throws DataStoreException
      Returns the ranges of sample values together with the conversion from samples to real values. ASCII Grid files always contain a single band.

      In current implementation, fetching the sample dimension requires loading the full coverage because the ASCII Grid format provides no way to infer a reasonable SampleDimension from only the header. Even determining the type (integer or floating point values) requires parsing all values.

      Specified by:
      getSampleDimensions in interface GridCoverageResource
      Overrides:
      getSampleDimensions in class RasterStore
      Returns:
      ranges of sample values together with their mapping to "real values".
      Throws:
      DataStoreException - if an error occurred while reading definitions from the underlying data store.
      See Also:
    • read

      public GridCoverage read(GridGeometry domain, int... ranges) throws DataStoreException
      Loads the data if not already done and closes the channel if read-only. In current implementation the image is always fully loaded and cached. The given domain is ignored. We do that in order to have determinist and stable values for the range of sample values and for the data type. Loading the full image is reasonable if ASCII Grid files contain only small images, which is usually the case given how inefficient this format is.
      Parameters:
      domain - desired grid extent and resolution, or null for reading the whole domain.
      ranges - shall be either null or an array containing only 0.
      Returns:
      the grid coverage for the specified domain.
      Throws:
      DataStoreException - if an error occurred while reading the grid coverage data.
    • setCoverage

      final Number setCoverage(GridCoverage replacement, RenderedImage data, int band)
      Replaces all data by the given coverage. This is used for write operations only.
      Parameters:
      replacement - the new coverage.
      data - the image wrapped by the given coverage.
      band - index of the band to write (usually 0).
      Returns:
      the "no data" value, or Double.NaN if none.
    • input

      final CharactersView input() throws DataStoreException
      Returns the input if it has not been closed.
      Throws:
      DataStoreException
    • close

      public void close() throws DataStoreException
      Closes this data store and releases any underlying resources.
      Specified by:
      close in interface AutoCloseable
      Overrides:
      close in class RasterStore
      Throws:
      DataStoreException - if an error occurred while closing this data store.
      See Also:
    • closeOnError

      final void closeOnError(Throwable e)
      Closes this data store after an unrecoverable error occurred. The caller is expected to throw the given exception after this method call.