/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2007-2008, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.coverageio.gdal; import it.geosolutions.imageio.gdalframework.GDALCommonIIOImageMetadata; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageReaderSpi; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverageio.BaseGridCoverage2DReader; import org.geotools.data.DataSourceException; import org.geotools.factory.Hints; import org.geotools.geometry.GeneralEnvelope; import org.geotools.metadata.iso.spatial.PixelTranslation; import org.geotools.referencing.CRS; import org.geotools.referencing.operation.transform.ProjectiveTransform; import org.opengis.coverage.grid.GridCoverageReader; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.TransformException; /** * Base class for GridCoverage data access, leveraging on GDAL Java bindings * provided by the ImageIO-Ext project. See <a * href="http://imageio-ext.dev.java.net">ImageIO-Ext project</a>. * * @author Daniele Romagnoli, GeoSolutions * @author Simone Giannecchini, GeoSolutions * * * @source $URL$ */ public abstract class BaseGDALGridCoverage2DReader extends BaseGridCoverage2DReader implements GridCoverageReader { protected final static String DEFAULT_WORLDFILE_EXT = ".wld"; /** Logger. */ private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(BaseGDALGridCoverage2DReader.class.toString()); /** * Creates a new instance of a {@link BaseGDALGridCoverage2DReader}. I * assume nothing about file extension. * * @param input * Source object for which we want to build a * {@link BaseGDALGridCoverage2DReader}. * @param hints * Hints to be used by this reader throughout his life. * @param worldFileExtension * the specific world file extension of the underlying format * @param formatSpecificSpi * an instance of a proper {@code ImageReaderSpi}. * @throws DataSourceException */ protected BaseGDALGridCoverage2DReader(Object input, final Hints hints, final String worldFileExtension, final ImageReaderSpi formatSpecificSpi) throws DataSourceException { super(input, hints, worldFileExtension, formatSpecificSpi); } /** * Setting Envelope, GridRange and CRS from the given {@code ImageReader} * * @param reader * the {@code ImageReader} from which to retrieve metadata * (if available) for setting properties * @throws IOException */ protected void setCoverageProperties(ImageReader reader) throws IOException { // // // // Getting common metadata from GDAL // // // final IIOMetadata metadata = reader.getImageMetadata(0); if (!(metadata instanceof GDALCommonIIOImageMetadata)) { throw new DataSourceException("Unexpected error! Metadata should be an instance of the expected class: GDALCommonIIOImageMetadata."); } parseCommonMetadata((GDALCommonIIOImageMetadata) metadata); // // // // Envelope and CRS checks // // // if (this.crs== null) { LOGGER.info("crs not found, proceeding with default crs"); this.crs=AbstractGridFormat.getDefaultCRS(); } if (this.originalEnvelope== null) { throw new DataSourceException("Unable to compute the envelope for this coverage"); } // setting the coordinate reference system for the envelope, just to make sure we set it this.originalEnvelope.setCoordinateReferenceSystem(this.crs); } /** * Given a {@link GDALCommonIIOImageMetadata} metadata object, retrieves * several properties to properly set envelope, gridrange and crs. * * @param metadata * a {@link GDALCommonIIOImageMetadata} metadata instance * from where to search needed properties. */ private void parseCommonMetadata(final GDALCommonIIOImageMetadata metadata) { // //////////////////////////////////////////////////////////////////// // // setting CRS and Envelope directly from GDAL, if available // // //////////////////////////////////////////////////////////////////// // // // // 1) CRS // // // final Object tempCRS = this.hints.get(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM); if (tempCRS != null) { this.crs=(CoordinateReferenceSystem) tempCRS; LOGGER.log(Level.WARNING,"Using default coordinate reference system "); } else{ // // // // Default CRS override it all // // // // // // // Let the prj file override the internal representation for the undelrying source of information. // // // parsePRJFile(); // if there was not prj or the envelope could not be created easily, let's go with the standard metadata. if (this.crs == null) { final String wkt = metadata.getProjection(); if ((wkt != null) && !(wkt.equalsIgnoreCase(""))) { try { this.crs=CRS.parseWKT(wkt); final Integer epsgCode = CRS.lookupEpsgCode(this.crs, true); // Force the creation of the CRS directly from the // retrieved EPSG code in order to prevent weird transformation // between "same" CRSs having slight differences. // TODO: cache epsgCode-CRSs if (epsgCode != null) { this.crs=CRS.decode("EPSG:" + epsgCode); } } catch (FactoryException fe) { // unable to get CRS from WKT if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE,"Unable to get CRS from WKT contained in metadata. Looking for a PRJ."); } //reset crs this.crs=null; } } } } // // // // 2) Grid // // // if (this.originalGridRange == null) this.originalGridRange=new GridEnvelope2D(new Rectangle(0, 0, metadata.getWidth(), metadata.getHeight())); // // // // 3) Envelope // // // // // Let's look for a world file first. // parseWorldFile(); if (this.originalEnvelope == null) { final double[] geoTransform = metadata.getGeoTransformation(); if ((geoTransform != null) && (geoTransform.length == 6)) { final AffineTransform tempTransform = new AffineTransform( geoTransform[1], geoTransform[4], geoTransform[2], geoTransform[5], geoTransform[0], geoTransform[3]); // ATTENTION: Gdal geotransform does not use the pixel is // centre convention like world files. if (this.originalEnvelope == null) { try { // Envelope setting this.originalEnvelope=CRS.transform(ProjectiveTransform .create(tempTransform), new GeneralEnvelope( ((GridEnvelope2D) this.originalGridRange))); } catch (IllegalStateException e) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e); } } catch (TransformException e) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e); } } } // Grid2World Transformation final double tr = -PixelTranslation.getPixelTranslation(PixelInCell.CELL_CORNER); tempTransform.translate(tr, tr); this.raster2Model = ProjectiveTransform.create(tempTransform); } } } }