/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.gce.image; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams; import org.geotools.data.DataSourceException; import org.geotools.data.DataUtilities; import org.geotools.factory.Hints; import org.geotools.parameter.DefaultParameterDescriptor; import org.geotools.parameter.DefaultParameterDescriptorGroup; import org.geotools.parameter.ParameterGroup; import org.opengis.coverage.grid.Format; import org.opengis.coverage.grid.GridCoverageWriter; import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.parameter.ParameterDescriptor; /** * A Format to allow discovery of Readers/Writers for raster images that support * world files containing information about the image. Supports gif+gfw, * jpg/jpeg+jgw, tif/tiff+tfw and png+pgw. wld may be used in place of * the format specific extension (jpg+wld, etc) Designed to be used with * GridCoverageExchange. * * * * @source $URL$ * @author Simone Giannecchini */ public final class WorldImageFormat extends AbstractGridFormat implements Format { /** {@link Set} of supported extensions for png world files. */ private final static Set<String> PNG_WFILE_EXT; /** {@link Set} of supported extensions for tiff world files. */ private final static Set<String> TIFF_WFILE_EXT; /** {@link Set} of supported extensions for jpeg world files. */ private final static Set<String> JPG_WFILE_EXT; /** {@link Set} of supported extensions for gif world files. */ private final static Set<String> GIF_WFILE_EXT; /** {@link Set} of supported extensions for bmp world files. */ private final static Set<String> BMP_WFILE_EXT; static { // png Set<String> tempSet = new HashSet<String>(2); tempSet.add(".pgw"); tempSet.add(".pngw"); PNG_WFILE_EXT = Collections.unmodifiableSet(tempSet); // jpeg tempSet = new HashSet<String>(3); tempSet.add(".jpw"); tempSet.add(".jgw"); tempSet.add(".jpgw"); tempSet.add(".jpegw"); JPG_WFILE_EXT = Collections.unmodifiableSet(tempSet); // gif tempSet = new HashSet<String>(2); tempSet.add(".gifw"); tempSet.add(".gfw"); GIF_WFILE_EXT = Collections.unmodifiableSet(tempSet); // png tempSet = new HashSet<String>(2); tempSet.add(".tfw"); tempSet.add(".tiffw"); TIFF_WFILE_EXT = Collections.unmodifiableSet(tempSet); // bmp tempSet = new HashSet<String>(2); tempSet.add(".bmw"); tempSet.add(".bmpw"); BMP_WFILE_EXT = Collections.unmodifiableSet(tempSet); } /** Logger. */ private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.gce.image"); /** * Format writing parameter. When writing a world image we need to provide * an output format in which we want to encode the image itself. PNG is * default output format. */ public static final ParameterDescriptor<String> FORMAT = DefaultParameterDescriptor.create( "Format", "Indicates the output format for this image",String.class, "png", true); /** * WorldImageFormat */ public WorldImageFormat() { setInfo(); } private void setInfo() { // information for this format HashMap<String, String> info = new HashMap<String, String>(); info.put("name", "WorldImage"); info.put("description","A raster file accompanied by a spatial data file"); info.put("vendor", "Geotools"); info.put("docURL", "http://www.geotools.org/WorldImageReader+formats"); info.put("version", "1.0"); mInfo = info; // reading parameters readParameters = new ParameterGroup( new DefaultParameterDescriptorGroup( mInfo, new GeneralParameterDescriptor[] { READ_GRIDGEOMETRY2D, })); // writing parameters writeParameters = new ParameterGroup( new DefaultParameterDescriptorGroup(mInfo, new GeneralParameterDescriptor[] { FORMAT })); } /** * Retrieves a {@link WorldImageReader} in case the providede * <code>source</code> can be accepted as a valid source for a world * image. The method returns null otherwise. * * @param source * The source object to read a WorldImage from * * @return a new WorldImageReader for the source */ @Override public WorldImageReader getReader(Object source) { return getReader(source, null); } /** * Call the accepts() method before asking for a writer to determine if the * current object is supported. * * @param destination * the destination object to write a WorldImage to * * @return a new WorldImageWriter for the destination */ @Override public GridCoverageWriter getWriter(Object destination) { return new WorldImageWriter(destination); } /** * Call the accepts() method before asking for a writer to determine if the * current object is supported. * * @param destination * the destination object to write a WorldImage to * * @return a new WorldImageWriter for the destination */ @Override public GridCoverageWriter getWriter(Object destination, Hints hints) { return new WorldImageWriter(destination, hints); } /** * Takes the input and determines if it is a class that we can understand * and then futher checks the format of the class to make sure we can * read/write to it. * * @param input * The object to check for acceptance. * * @return true if the input is acceptable, false otherwise */ @Override public boolean accepts(Object input,Hints hints) { String pathname = ""; if (input instanceof URL) { final URL url = (URL) input; final String protocol = url.getProtocol(); if (protocol.equalsIgnoreCase("file")) pathname = DataUtilities.urlToFile(url).getPath(); else { if (protocol.equalsIgnoreCase("http")) { final String query; try { query = java.net.URLDecoder.decode(url.getQuery() .intern(), "UTF-8"); } catch (UnsupportedEncodingException e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE, e.getLocalizedMessage(), e); return false; } // should we proceed? Let's look for a getmap WMS request // we do a very basic check we should make this stronger! // @todo if (query.toLowerCase().intern().indexOf("getmap") == -1) return false; return true; } } } else if (input instanceof File) { File file = (File) input; pathname = file.getAbsolutePath(); } else if (input instanceof String) pathname = (String) input; // else if (input instanceof InputStream // || input instanceof ImageInputStream) // return true;// @ask TODO is this right????? else return false; // check if we can decode this file if (!(pathname.endsWith(".gif") || pathname.endsWith(".jpg") || pathname.endsWith(".jpeg") || pathname.endsWith(".tif") || pathname.endsWith(".tiff") || pathname.endsWith(".png") || pathname .endsWith(".bmp"))) { return false; } // check the presence of the world file final File source = new File(pathname); if (!source.exists()) return false; String suffix; String fileName; boolean answer = false; final File parentDir = source.getParentFile(); if (parentDir != null) { final int dotIndex = pathname.lastIndexOf('.'); if (dotIndex != -1) { fileName = pathname.substring(0, dotIndex); suffix = pathname.substring(dotIndex + 1, pathname.length()); final Set<String> suffixes = WorldImageFormat.getWorldExtension(suffix); final Iterator<String> it = suffixes.iterator(); StringBuffer buff = new StringBuffer(fileName); do { answer = new File(buff.append(it.next()).toString()).exists(); buff = new StringBuffer(fileName); } while (!answer && it.hasNext()); if (!answer) { buff.setLength(0); buff.append(fileName); buff.append(".wld"); answer = new File(buff.toString()).exists(); } if (!answer) { buff.setLength(0); buff.append(fileName); buff.append(".meta"); answer = new File(buff.toString()).exists(); } } } return answer; } /** * Takes an image file extension (such as .gif, including the '.') and * returns it's corresponding world file extension (such as .gfw). * * @param fileExtension * an image file extension, including the '.' * * @return a corresponding {@link Set} of world file extensions, including * the '.' */ public static Set<String> getWorldExtension(String fileExtension) { if (fileExtension == null) { throw new NullPointerException("Provided input is null"); } if (fileExtension.equalsIgnoreCase("png")) { return PNG_WFILE_EXT; } if (fileExtension.equals("gif")) { return GIF_WFILE_EXT; } if (fileExtension.equalsIgnoreCase("jpg") || fileExtension.equalsIgnoreCase("jpeg")) { return JPG_WFILE_EXT; } if (fileExtension.equalsIgnoreCase("tif") || fileExtension.equalsIgnoreCase("tiff")) { return TIFF_WFILE_EXT; } if (fileExtension.equalsIgnoreCase("bmp")) { return BMP_WFILE_EXT; } throw new IllegalArgumentException("Unsupported file format"); } /** * Retrieves a {@link WorldImageReader} in case the providede * <code>source</code> can be accepted as a valid source for a world * image. The method returns null otherwise. * * @param source * The source object to read a WorldImage from * @param hints * {@link Hints} to control the provided {@link WorldImageReader}. * @return a new WorldImageReader for the source */ @Override public WorldImageReader getReader(Object source, Hints hints) { try { return new WorldImageReader(source, hints); } catch (DataSourceException e) { if (LOGGER.isLoggable(Level.WARNING)) LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e); return null; } } /** * Always returns null since for the moment there are no * {@link GeoToolsWriteParams} availaible for this format. * * @return always null. */ @Override public GeoToolsWriteParams getDefaultImageIOWriteParameters() { return null; } }