/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.image.io;
import java.util.Set;
import javax.imageio.IIOParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
/**
* Interface for {@link ImageReader} and {@link ImageWriter} implementations handling data
* which can have more than two dimensions. The standard Java Image I/O API is designed for
* two-dimensional data. The Geotk library can gives access to supplemental dimensions in
* two different ways:
*
* <ul>
* <li><p>Using many {@link DimensionSlice} objects (one for each dimension) associated
* to a single {@link SpatialImageReadParam} object controlling the reading process.
* This approach is similar in spirit to the WCS 2.0 specification, but requires
* knowledge of Geotk API.</p></li>
*
* <li><p>Using the standard Java Image I/O API for <cite>bands</cite> and <cite>image
* index</cite>. An advantage of this approach is to work with libraries having no
* knowledge of the Geotk-specific {@code DimensionSlice} class. This is the approach
* enabled by this {@code MultidimensionalImageStore} interface.</p></li>
* </ul>
*
* {@section Assigning a third dimension to bands}
* Whatever a third dimension is assigned to bands or not is plugin-specific. Plugins that have
* no concept of bands (like NetCDF which has the concept of <var>n</var>-dimensional data cube
* instead) can do that. For example in a dataset having (<var>x</var>, <var>y</var>, <var>z</var>,
* <var>t</var>) dimensions, it may be useful to handle the <var>z</var> dimension as bands. After
* the method calls below, users can select one or many elevation indices through the standard
* {@link IIOParam#setSourceBands(int[])} API. Compared to the {@link DimensionSlice} API, it
* allows loading more than one slice in a single read operation.
*
* {@preformat java
* MultidimensionalImageStore reader = ...;
* DimensionIdentification bandsDimension = reader.getDimensionForAPI(DimensionSlice.API.BANDS);
* bandsDimension.addDimensionId(2); // 0-based index of the third dimension.
* }
*
* When a dimension is assigned to bands as in the above example and if no
* {@link IIOParam#sourceBands} array is specified, then all bands will be read.
* This number of bands may be large, for example in NetCDF files. Users are advised
* to always {@linkplain IIOParam#setSourceBands(int[]) set the source bands} when using
* the band API for multi-dimensional data.
* <p>
* After the <var>z</var> dimension in the above example has been assigned to the bands API,
* the bands can be used as below:
* <p>
* <ul>
* <li>The (<var>x</var>,<var>y</var>) plane at <var>z</var><sub>{@code sourceBands[0]}</sub> is stored in band 0.</li>
* <li>The (<var>x</var>,<var>y</var>) plane at <var>z</var><sub>{@code sourceBands[1]}</sub> is stored in band 1.</li>
* <li><i>etc.</i></li>
* </ul>
*
* {@section Note for implementors}
* {@code ImageReader} and {@code ImageWriter} implementors can determine which (if any) dimension
* index has been assigned to the bands API by using the code below:
*
* {@preformat java
* DimensionSet dimensionsForAPI = ...; // Typically an ImageReader/Writer field.
* DimensionIdentification bandsDimension = dimensionsForAPI.get(DimensionSlice.API.BANDS);
* if (bandsDimension != null) {
* Collection<?> propertiesOfAxes = ...; // This is plugin-specific.
* int index = bandsDimension.findDimensionIndex(propertiesOfAxes);
* if (index >= 0) {
* // We have found the dimension index of bands.
* }
* }
* }
*
* See also the {@link DimensionSet} javadoc for code snippet implementing the methods
* declared in this interface.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.20
*
* @see DimensionSlice
* @see SpatialImageReader#getDimension(int)
* @see SpatialImageReader#getGridEnvelope(int)
*
* @since 3.15
* @module
*/
public interface MultidimensionalImageStore {
/**
* The standard dimension index of pixel columns (<var>x</var> ordinates) in images,
* which is {@value}. This is for example the standard dimension index of
* {@linkplain java.awt.image.RenderedImage#getWidth() image width} in
* {@linkplain org.opengis.coverage.grid.GridEnvelope grid envelopes}.
* <p>
* In theory, the {@code MultidimensionalImageStore} API allows some flexibility about
* which dimension is the "image width". However in practice, the {@value} dimension is
* often hard-coded, sometime as an index (in which case this {@code X_DIMENSION} field
* shall be used), or sometime in the way loops are structured (in which case a
* {@code // X_DIMENSION} comment shall be put). The purpose of this constant is to
* allow traceability of code making such hard-coded assumption, in case more flexibility
* is needed in the future.
*
* @since 3.19
*/
int X_DIMENSION = 0;
/**
* The standard dimension index of pixel rows (<var>y</var> ordinates) in images,
* which is {@value}. This is for example the standard dimension index of
* {@linkplain java.awt.image.RenderedImage#getHeight() image height} in
* {@linkplain org.opengis.coverage.grid.GridEnvelope grid envelopes}.
* <p>
* In theory, the {@code MultidimensionalImageStore} API allows some flexibility about
* which dimension is the "image height". However in practice, the {@value} dimension is
* often hard-coded, sometime as an index (in which case this {@code Y_DIMENSION} field
* shall be used), or sometime in the way loops are structured (in which case a
* {@code // Y_DIMENSION} comment shall be put). The purpose of this constant is to
* allow traceability of code making such hard-coded assumption, in case more flexibility
* is needed in the future.
*
* @since 3.19
*/
int Y_DIMENSION = 1;
/**
* Returns the dimension assigned to the given API. This method never return {@code null}.
* However the returned dimension can be used only if the {@code addDimensionId(...)} method
* has been invoked at least once on the returned instance.
*
* @param api The API for which to return a dimension.
* @return The dimension assigned to the given API.
*
* @see DimensionSet#getOrCreate(DimensionSlice.API)
*/
DimensionIdentification getDimensionForAPI(DimensionSlice.API api);
/**
* Returns the API assigned to the given dimension identifiers. The identifiers can be any
* kind of objects accepted by the {@link DimensionIdentification#addDimensionId(int)
* DimensionIdentification.addDimensionId(...)} methods. Unknown identifiers are silently
* ignored.
* <p>
* If more than one dimension is found for the given identifiers, then a
* {@linkplain SpatialImageReader#warningOccurred warning is emitted} and
* this method returns the first dimension matching the given identifiers.
* If no dimension is found, {@code API.NONE} is returned.
*
* @param identifiers The identifiers of the dimension to query.
* @return The API assigned to the given dimension, or {@link DimensionSlice.API#NONE} if none.
*
* @see DimensionSet#getAPI(Object[])
*/
DimensionSlice.API getAPIForDimension(Object... identifiers);
/**
* Returns the set of APIs for which at least one dimension has identifiers. This
* is typically an empty set until the following code is invoked at least once:
*
* {@preformat java
* getDimensionForAPI(...).addDimensionId(...);
* }
*
* @return The API for which at least one dimension has identifiers.
*
* @see DimensionSet#getAPIs()
*/
Set<DimensionSlice.API> getAPIForDimensions();
}