/** * */ package org.geotools.gce.geotiff; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageMetadata; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReaderSpi; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageWriterSpi; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.channels.FileChannel; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.IIOException; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageInputStream; import org.apache.commons.io.FilenameUtils; import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffConstants; import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffIIOMetadataEncoder; import org.geotools.data.DataSourceException; import org.geotools.data.DataUtilities; import org.geotools.data.PrjFileReader; import org.geotools.data.WorldFileReader; import org.geotools.referencing.CRS; import org.geotools.util.Utilities; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Parent; import org.jdom.input.DOMBuilder; import org.jdom.output.DOMOutputter; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; /** * Sparse utilities for the various classes. I use them to extract complex code * from other places. * * @author Simone Giannecchini, GeoSolutions S.A.S. * */ class Utils { /** Logger for the {@link Utils} class. */ private final static Logger LOGGER = org.geotools.util.logging.Logging .getLogger(Utils.class.toString()); static final double EPSILON = 10E-6; static CoordinateReferenceSystem WGS84; static { try { WGS84 = CRS.decode("EPSG:4326", true); } catch (NoSuchAuthorityCodeException e) { if (LOGGER.isLoggable(Level.WARNING)){ LOGGER.log(Level.WARNING, "Unable to decode the EPSG:4326 crs." + e.getLocalizedMessage(), e); } } catch (FactoryException e) { if (LOGGER.isLoggable(Level.WARNING)){ LOGGER.log(Level.WARNING, "Unable to decode the EPSG:4326 crs." + e.getLocalizedMessage(), e); } } } static URL checkSource(Object source) throws MalformedURLException, DataSourceException { URL sourceURL = null; // // Check source // // if it is a URL or a String let's try to see if we can get a file to // check if we have to build the index if (source instanceof URL) { sourceURL = ((URL) source); source = DataUtilities.urlToFile(sourceURL); } else if (source instanceof String) { // is it a File? final String tempSource = (String) source; File tempFile = new File(tempSource); if (!tempFile.exists()) { // is it a URL try { sourceURL = new URL(tempSource); source = DataUtilities.urlToFile(sourceURL); } catch (MalformedURLException e) { sourceURL = null; source = null; } } else { sourceURL = tempFile.toURI().toURL(); source = tempFile; } } // at this point we have tried to convert the thing to a File as hard as // we could, let's see what we can do if (source instanceof File) { final File sourceFile = (File) source; if (!sourceFile.isDirectory()) { sourceURL = ((File) source).toURI().toURL(); } } else { sourceURL = null; } return sourceURL; } /** * Look for an {@link ImageReader} instance that is able to read the * provided {@link ImageInputStream}, which must be non null. * * <p> * In case no reader is found, <code>null</code> is returned. * * @param inStream * an instance of {@link ImageInputStream} for which we need to * find a suitable {@link ImageReader}. * @return a suitable instance of {@link ImageReader} or <code>null</code> * if one cannot be found. */ static ImageReader getReader(final ImageInputStream inStream) { Utilities.ensureNonNull("inStream", inStream); try { // get a reader inStream.mark(); final Iterator<ImageReader> readersIt = ImageIO.getImageReaders(inStream); if (!readersIt.hasNext()) { return null; } return readersIt.next(); } finally { try { inStream.reset(); } catch (IOException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e); } } } /** * Checks that a {@link File} is a real file, exists and is readable. * * @param file * the {@link File} instance to check. Must not be null. * * @return <code>true</code> in case the file is a real file, exists and is * readable; <code>false </code> otherwise. */ static boolean checkFileReadable(final File file) { if (LOGGER.isLoggable(Level.FINE)) { final StringBuilder builder = new StringBuilder(); builder.append("Checking file:") .append(FilenameUtils.getFullPath(file.getAbsolutePath())).append("\n") .append("canRead:").append(file.canRead()).append("\n").append("isHidden:") .append(file.isHidden()).append("\n").append("isFile").append(file.isFile()) .append("\n").append("canWrite").append(file.canWrite()).append("\n"); LOGGER.fine(builder.toString()); } if (!file.exists() || !file.canRead() || !file.isFile()) { return false; } return true; } /** * @throws IOException */ static MathTransform parseWorldFile(Object source) throws IOException { MathTransform raster2Model = null; // TODO: Add support for FileImageInputStreamExt // TODO: Check for WorldFile on URL beside the actual connection. if (source instanceof File) { final File sourceFile = ((File) source); String parentPath = sourceFile.getParent(); String filename = sourceFile.getName(); final int i = filename.lastIndexOf('.'); filename = (i == -1) ? filename : filename.substring(0, i); // getting name and extension final String base = (parentPath != null) ? parentPath + File.separator + filename : filename; // We can now construct the baseURL from this string. File file2Parse = new File(base + ".wld"); if (file2Parse.exists()) { final WorldFileReader reader = new WorldFileReader(file2Parse); raster2Model = reader.getTransform(); } else { // looking for another extension file2Parse = new File(base + ".tfw"); if (file2Parse.exists()) { // parse world file final WorldFileReader reader = new WorldFileReader(file2Parse); raster2Model = reader.getTransform(); } } } return raster2Model; } static CoordinateReferenceSystem getCRS(Object source) { CoordinateReferenceSystem crs = null; if (source instanceof File || (source instanceof URL && (((URL) source).getProtocol() == "file"))) { // getting name for the prj file final String sourceAsString; if (source instanceof File) { sourceAsString = ((File) source).getAbsolutePath(); } else { String auth = ((URL) source).getAuthority(); String path = ((URL) source).getPath(); if (auth != null && !auth.equals("")) { sourceAsString = "//" + auth + path; } else { sourceAsString = path; } } final int index = sourceAsString.lastIndexOf("."); final String base = sourceAsString.substring(0, index) + ".prj"; // does it exist? final File prjFile = new File(base); if (prjFile.exists()) { // it exists then we have top read it PrjFileReader projReader = null; try { final FileChannel channel = new FileInputStream(prjFile).getChannel(); projReader = new PrjFileReader(channel); crs = projReader.getCoordinateReferenceSystem(); } catch (FileNotFoundException e) { // warn about the error but proceed, it is not fatal // we have at least the default crs to use LOGGER.log(Level.INFO, e.getLocalizedMessage(), e); } catch (IOException e) { // warn about the error but proceed, it is not fatal // we have at least the default crs to use LOGGER.log(Level.INFO, e.getLocalizedMessage(), e); } catch (FactoryException e) { // warn about the error but proceed, it is not fatal // we have at least the default crs to use LOGGER.log(Level.INFO, e.getLocalizedMessage(), e); } finally { if (projReader != null) try { projReader.close(); } catch (IOException e) { // warn about the error but proceed, it is not fatal // we have at least the default crs to use LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); } } } } return crs; } /** * Creates image metadata which complies to the GeoTIFFWritingUtilities * specification for the given image writer, image type and * GeoTIFFWritingUtilities metadata. * * @param writer * the image writer, must not be null * @param type * the image type, must not be null * @param geoTIFFMetadata * the GeoTIFFWritingUtilities metadata, must not be null * @param params * @return the image metadata, never null * @throws IIOException * if the metadata cannot be created */ final static IIOMetadata createGeoTiffIIOMetadata(ImageWriter writer, ImageTypeSpecifier type, GeoTiffIIOMetadataEncoder geoTIFFMetadata, ImageWriteParam params) throws IIOException { IIOMetadata imageMetadata = writer.getDefaultImageMetadata(type, params); imageMetadata = writer.convertImageMetadata(imageMetadata, type, params); org.w3c.dom.Element w3cElement = (org.w3c.dom.Element) imageMetadata .getAsTree(GeoTiffConstants.GEOTIFF_IIO_METADATA_FORMAT_NAME); final Element element = new DOMBuilder().build(w3cElement); geoTIFFMetadata.assignTo(element); final Parent parent = element.getParent(); parent.removeContent(element); final Document document = new Document(element); try { final org.w3c.dom.Document w3cDoc = new DOMOutputter().output(document); final IIOMetadata iioMetadata = new TIFFImageMetadata(TIFFImageMetadata.parseIFD(w3cDoc .getDocumentElement().getFirstChild())); imageMetadata = iioMetadata; } catch (JDOMException e) { throw new IIOException("Failed to set GeoTIFFWritingUtilities specific tags.", e); } catch (IIOInvalidTreeException e) { throw new IIOException("Failed to set GeoTIFFWritingUtilities specific tags.", e); } return imageMetadata; } /** factory for getting tiff writers. */ final static TIFFImageWriterSpi TIFFWRITERFACTORY = new TIFFImageWriterSpi(); /** SPI for creating tiff readers in ImageIO tools */ final static TIFFImageReaderSpi TIFFREADERFACTORY = new TIFFImageReaderSpi(); }