001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.coverage.io;
018:
019: // J2SE dependencies
020: import java.io.File;
021: import java.io.IOException;
022: import java.net.URL;
023: import java.util.Locale;
024: import javax.imageio.ImageIO;
025: import javax.imageio.ImageReader;
026:
027: // OpenGIS dependencies
028: import org.opengis.coverage.grid.GridCoverage;
029: import org.opengis.coverage.grid.GridRange;
030: import org.opengis.geometry.Envelope;
031: import org.opengis.referencing.crs.CoordinateReferenceSystem;
032:
033: // Geotools dependencies
034: import org.geotools.factory.Hints;
035: import org.geotools.resources.i18n.ErrorKeys;
036: import org.geotools.coverage.GridSampleDimension;
037:
038: /**
039: * An implementation of {@link AbstractGridCoverageReader} using informations parsed by a
040: * {@link MetadataBuilder} object. This reader is typically used for format that
041: * stores pixel values and geographic metadata in separated files. For example,
042: * pixel values may be stored as a PNG images ou a RAW binary file, and geographic
043: * metadata (coordinate system, geographic location, etc.) may be stored in a separated
044: * text file. The text file is parsed by a {@link MetadataBuilder} object, while the pixel
045: * values are read by a {@link ImageReader} object.
046: *
047: * @since 2.2
048: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/coverage/io/ExoreferencedGridCoverageReader.java $
049: * @version $Id: ExoreferencedGridCoverageReader.java 25699 2007-05-31 15:55:07Z desruisseaux $
050: * @author Martin Desruisseaux
051: */
052: public class ExoreferencedGridCoverageReader extends
053: AbstractGridCoverageReader {
054: /**
055: * The object to use for parsing the meta-data.
056: */
057: protected final MetadataBuilder metadata;
058:
059: /**
060: * File extension (by default the same than format name).
061: */
062: private final String extension;
063:
064: /**
065: * Constructs a new {@code ExoreferencedGridCoverageReader}
066: * using the specified {@link MetadataBuilder}.
067: *
068: * @param hints The factory hints to use.
069: * @param formatName The name for this format. This format name should be
070: * understood by {@link ImageIO#getImageReadersByFormatName(String)},
071: * unless {@link #getImageReaders} is overridden.
072: * @param parser The {@link MetadataBuilder} to use for reading geographic metadata.
073: */
074: public ExoreferencedGridCoverageReader(final Hints hints,
075: final String formatName, final MetadataBuilder parser) {
076: this (hints, formatName, formatName, parser);
077: }
078:
079: /**
080: * Constructs a new {@code ExoreferencedGridCoverageReader}
081: * using the specified {@link MetadataBuilder}.
082: *
083: * @param hints The factory hints to use.
084: * @param formatName The name for this format. This format name should be
085: * understood by {@link ImageIO#getImageReadersByFormatName(String)},
086: * unless {@link #getImageReaders} is overridden.
087: * @param extension Filename's extensions for file of this format.
088: * @param parser The {@link MetadataBuilder} to use for reading geographic metadata.
089: */
090: public ExoreferencedGridCoverageReader(final Hints hints,
091: final String formatName, final String extension,
092: final MetadataBuilder parser) {
093: super (hints, formatName);
094: metadata = parser;
095: if (parser == null) {
096: throw new IllegalArgumentException();
097: }
098: this .extension = extension;
099: }
100:
101: /**
102: * Restores the coverage reader to its initial state.
103: *
104: * @throws IOException if an error occurs while disposing resources.
105: */
106: //@Override
107: public synchronized void reset() throws IOException {
108: metadata.clear();
109: super .reset();
110: }
111:
112: /**
113: * Sets the current {@linkplain Locale locale} of this grid coverage reader to the given value.
114: * A value of {@code null} removes any previous setting, and indicates that the reader should
115: * localize as it sees fit.
116: */
117: //@Override
118: public synchronized void setLocale(final Locale locale) {
119: super .setLocale(locale);
120: metadata.setUserLocale(locale);
121: }
122:
123: /**
124: * Sets the input source to the given object. The input must be {@link File} or an
125: * {@link URL} object. The input source must be the <em>metadata</em> file or URL.
126: * The image file or URL will be derived from the metadata filename by a call to
127: * {@link #toImageFileName}, which may be overridden.
128: *
129: * @param input The {@link File} or {@link URL} to be read.
130: * @param seekForwardOnly if {@code true}, grid coverages and metadata may only
131: * be read in ascending order from the input source.
132: * @throws IOException if an I/O operation failed.
133: * @throws IllegalArgumentException if input is not an instance
134: * of a classe supported by this reader.
135: */
136: //@Override
137: public synchronized void setInput(Object input,
138: final boolean seekForwardOnly) throws IOException {
139: if (input instanceof File) {
140: final File file = (File) input;
141: metadata.clear();
142: metadata.load(file);
143: input = new File(file.getParent(), toImageFileName(file
144: .getName()));
145: } else if (input instanceof URL) {
146: final URL url = (URL) input;
147: metadata.clear();
148: metadata.load(url);
149: // TODO: invokes rename(String) here and rebuild the URL.
150: throw new UnsupportedOperationException(
151: "URL support not yet implemented");
152: } else {
153: throw new IllegalArgumentException(
154: getString(ErrorKeys.NO_IMAGE_READER));
155: }
156: super .setInput(input, seekForwardOnly);
157: }
158:
159: /**
160: * Returns the filename for image data. This method is invoked by {@link #setInput} after
161: * {@link #metadata} has been loaded. Default implementation just replace the file extension
162: * by the {@code extension} argument specified to the constructor.
163: *
164: * @param filename The filename part of metadata file. This is the filename part
165: * of the file supplied by users to {@link #setInput}.
166: * @return The filename to use for for the image file. The directory is assumed
167: * to be the same than the metadata file.
168: */
169: protected String toImageFileName(String filename) {
170: int ext = filename.lastIndexOf('.');
171: if (ext < 0) {
172: ext = filename.length();
173: }
174: return filename.substring(0, ext) + '.' + extension;
175: }
176:
177: /**
178: * Returns the coordinate system for the {@link GridCoverage} to be read.
179: * The default implementation invokes
180: * <code>{@linkplain #metadata}.{@linkplain MetadataBuilder#getCoordinateReferenceSystem()
181: * getCoordinateReferenceSystem()}</code>.
182: *
183: * @param index The index of the image to be queried.
184: * @return The coordinate system for the {@link GridCoverage} at the specified index.
185: * @throws IllegalStateException if the input source has not been set.
186: * @throws IndexOutOfBoundsException if the supplied index is out of bounds.
187: * @throws IOException if an error occurs reading the width information from
188: * the input source.
189: */
190: public synchronized CoordinateReferenceSystem getCoordinateReferenceSystem(
191: final int index) throws IOException {
192: checkImageIndex(index);
193: return metadata.getCoordinateReferenceSystem();
194: }
195:
196: /**
197: * Returns the envelope for the {@link GridCoverage} to be read.
198: * The default implementation invokes
199: * <code>{@linkplain #metadata}.{@linkplain MetadataBuilder#getEnvelope() getEnvelope()}</code>.
200: *
201: * @param index The index of the image to be queried.
202: * @return The envelope for the {@link GridCoverage} at the specified index.
203: * @throws IllegalStateException if the input source has not been set.
204: * @throws IndexOutOfBoundsException if the supplied index is out of bounds.
205: * @throws IOException if an error occurs reading the width information from
206: * the input source.
207: */
208: public synchronized Envelope getEnvelope(final int index)
209: throws IOException {
210: checkImageIndex(index);
211: return metadata.getEnvelope();
212: }
213:
214: /**
215: * Returns the grid range for the {@link GridCoverage} to be read.
216: * The default implementation invokes
217: * <code>{@linkplain #metadata}.{@linkplain MetadataBuilder#getGridRange() getGridRange()}</code>.
218: *
219: * @param index The index of the image to be queried.
220: * @return The grid range for the {@link GridCoverage} at the specified index.
221: * @throws IllegalStateException if the input source has not been set.
222: * @throws IndexOutOfBoundsException if the supplied index is out of bounds.
223: * @throws IOException if an error occurs reading the width information from
224: * the input source.
225: */
226: //@Override
227: public synchronized GridRange getGridRange(final int index)
228: throws IOException {
229: checkImageIndex(index);
230: return metadata.getGridRange();
231: }
232:
233: /**
234: * Returns the sample dimensions for each band of the {@link GridCoverage}
235: * to be read. If sample dimensions are not known, then this method returns
236: * {@code null}. The default implementation invokes
237: * <code>{@linkplain #metadata}.{@linkplain MetadataBuilder#getSampleDimensions()
238: * getSampleDimensions()}</code>.
239: *
240: * @param index The index of the image to be queried.
241: * @return The category lists for the {@link GridCoverage} at the specified index.
242: * This array's length must be equals to the number of bands in {@link GridCoverage}.
243: * @throws IllegalStateException if the input source has not been set.
244: * @throws IndexOutOfBoundsException if the supplied index is out of bounds.
245: * @throws IOException if an error occurs reading the width information from
246: * the input source.
247: */
248: //@Override
249: public synchronized GridSampleDimension[] getSampleDimensions(
250: final int index) throws IOException {
251: checkImageIndex(index);
252: return metadata.getSampleDimensions();
253: }
254: }
|