001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.gce.image;
018:
019: import java.io.File;
020: import java.io.UnsupportedEncodingException;
021: import java.net.URL;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.HashMap;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Set;
029: import java.util.logging.Level;
030: import java.util.logging.Logger;
031:
032: import org.geotools.coverage.grid.io.AbstractGridFormat;
033: import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
034: import org.geotools.data.DataSourceException;
035: import org.geotools.factory.Hints;
036: import org.geotools.parameter.DefaultParameterDescriptor;
037: import org.geotools.parameter.DefaultParameterDescriptorGroup;
038: import org.geotools.parameter.ParameterGroup;
039: import org.opengis.coverage.grid.Format;
040: import org.opengis.coverage.grid.GridCoverageReader;
041: import org.opengis.coverage.grid.GridCoverageWriter;
042: import org.opengis.parameter.GeneralParameterDescriptor;
043: import org.opengis.parameter.ParameterDescriptor;
044:
045: /**
046: * A Format to allow discovery of Readers/Writers for raster images that support
047: * world files containing information about the image. Supports gif+gfw,
048: * jpg/jpeg+jgw, tif/tiff+tfw and png+pgw. wld may be used in place of
049: * the format specific extension (jpg+wld, etc) Designed to be used with
050: * GridCoverageExchange.
051: *
052: * @source $URL:
053: * http://svn.geotools.org/geotools/trunk/gt/plugin/image/src/org/geotools/gce/image/WorldImageFormat.java $
054: * @author Simone Giannecchini
055: */
056: public final class WorldImageFormat extends AbstractGridFormat
057: implements Format {
058:
059: /** {@link Set} of supported extensions for png world files. */
060: private final static Set PNG_WFILE_EXT;
061:
062: /** {@link Set} of supported extensions for tiff world files. */
063: private final static Set TIFF_WFILE_EXT;
064:
065: /** {@link Set} of supported extensions for jpeg world files. */
066: private final static Set JPG_WFILE_EXT;
067:
068: /** {@link Set} of supported extensions for gif world files. */
069: private final static Set GIF_WFILE_EXT;
070:
071: /** {@link Set} of supported extensions for bmp world files. */
072: private final static Set BMP_WFILE_EXT;
073:
074: static {
075: // png
076: Set tempSet = new HashSet(2);
077: tempSet.add(".pgw");
078: tempSet.add(".pngw");
079: PNG_WFILE_EXT = Collections.unmodifiableSet(tempSet);
080:
081: // jpeg
082: tempSet = new HashSet(3);
083: tempSet.add(".jpw");
084: tempSet.add(".jgw");
085: tempSet.add(".jpgw");
086: tempSet.add(".jpegw");
087: JPG_WFILE_EXT = Collections.unmodifiableSet(tempSet);
088:
089: // gif
090: tempSet = new HashSet(2);
091: tempSet.add(".gifw");
092: tempSet.add(".gfw");
093: GIF_WFILE_EXT = Collections.unmodifiableSet(tempSet);
094:
095: // png
096: tempSet = new HashSet(2);
097: tempSet.add(".tfw");
098: tempSet.add(".tiffw");
099: TIFF_WFILE_EXT = Collections.unmodifiableSet(tempSet);
100:
101: // bmp
102: tempSet = new HashSet(2);
103: tempSet.add(".bmw");
104: tempSet.add(".bmpw");
105: BMP_WFILE_EXT = Collections.unmodifiableSet(tempSet);
106:
107: }
108:
109: /** Logger. */
110: private final static Logger LOGGER = org.geotools.util.logging.Logging
111: .getLogger("org.geotools.gce.image");
112:
113: /**
114: * Format writing parameter. When writing a world image we need to provide
115: * an output format in which we want to encode the image itself. PNG is
116: * default output format.
117: */
118: public static final ParameterDescriptor FORMAT = new DefaultParameterDescriptor(
119: "Format", "Indicates the output format for this image",
120: "png", true);
121:
122: /**
123: * WorldImageFormat
124: */
125: public WorldImageFormat() {
126: setInfo();
127: }
128:
129: private void setInfo() {
130: // information for this format
131: HashMap info = new HashMap();
132:
133: info.put("name", "WorldImage");
134: info.put("description",
135: "A raster file accompanied by a spatial data file");
136: info.put("vendor", "Geotools");
137: info.put("docURL",
138: "http://www.geotools.org/WorldImageReader+formats");
139: info.put("version", "1.0");
140: mInfo = info;
141:
142: // reading parameters
143: readParameters = new ParameterGroup(
144: new DefaultParameterDescriptorGroup(
145: mInfo,
146: new GeneralParameterDescriptor[] { READ_GRIDGEOMETRY2D, }));
147:
148: // writing parameters
149: writeParameters = new ParameterGroup(
150: new DefaultParameterDescriptorGroup(mInfo,
151: new GeneralParameterDescriptor[] { FORMAT }));
152: }
153:
154: /**
155: * Retrieves a {@link WorldImageReader} in case the providede
156: * <code>source</code> can be accepted as a valid source for a world
157: * image. The method returns null otherwise.
158: *
159: * @param source
160: * The source object to read a WorldImage from
161: *
162: * @return a new WorldImageReader for the source
163: */
164: public GridCoverageReader getReader(Object source) {
165: return getReader(source, null);
166: }
167:
168: /**
169: * Call the accepts() method before asking for a writer to determine if the
170: * current object is supported.
171: *
172: * @param destination
173: * the destination object to write a WorldImage to
174: *
175: * @return a new WorldImageWriter for the destination
176: */
177: public GridCoverageWriter getWriter(Object destination) {
178: return new WorldImageWriter(destination);
179: }
180:
181: /**
182: * Call the accepts() method before asking for a writer to determine if the
183: * current object is supported.
184: *
185: * @param destination
186: * the destination object to write a WorldImage to
187: *
188: * @return a new WorldImageWriter for the destination
189: */
190: public GridCoverageWriter getWriter(Object destination, Hints hints) {
191: return new WorldImageWriter(destination, hints);
192: }
193:
194: /**
195: * Takes the input and determines if it is a class that we can understand
196: * and then futher checks the format of the class to make sure we can
197: * read/write to it.
198: *
199: * @param input
200: * The object to check for acceptance.
201: *
202: * @return true if the input is acceptable, false otherwise
203: */
204: public boolean accepts(Object input) {
205: String pathname = "";
206:
207: if (input instanceof URL) {
208: final URL url = (URL) input;
209: final String protocol = url.getProtocol();
210: if (protocol.equalsIgnoreCase("file"))
211: pathname = url.getFile();
212: else {
213: if (protocol.equalsIgnoreCase("http")) {
214: final String query;
215: try {
216: query = java.net.URLDecoder.decode(url
217: .getQuery().intern(), "UTF-8");
218: } catch (UnsupportedEncodingException e) {
219: if (LOGGER.isLoggable(Level.FINE))
220: LOGGER.log(Level.FINE, e
221: .getLocalizedMessage(), e);
222: return false;
223: }
224:
225: // should we proceed? Let's look for a getmap WMS request
226: // we do a very basic check we should make this stronger!
227: // @todo
228: if (query.toLowerCase().intern().indexOf("getmap") == -1)
229: return false;
230: return true;
231:
232: }
233: }
234: } else if (input instanceof File) {
235: File file = (File) input;
236:
237: pathname = file.getAbsolutePath();
238: } else if (input instanceof String)
239: pathname = (String) input;
240: // else if (input instanceof InputStream
241: // || input instanceof ImageInputStream)
242: // return true;// @ask TODO is this right?????
243: else
244: return false;
245: // check if we can decode this file
246: if (!(pathname.endsWith(".gif") || pathname.endsWith(".jpg")
247: || pathname.endsWith(".jpeg")
248: || pathname.endsWith(".tif")
249: || pathname.endsWith(".tiff")
250: || pathname.endsWith(".png") || pathname
251: .endsWith(".bmp"))) {
252: return false;
253: }
254:
255: // check the presence of the world file
256: final File source = new File(pathname);
257: if (!source.exists())
258: return false;
259: String suffix;
260: String fileName;
261:
262: boolean answer = false;
263: final File parentDir = source.getParentFile();
264: if (parentDir != null) {
265: final int dotIndex = pathname.lastIndexOf('.');
266: if (dotIndex != -1) {
267: fileName = pathname.substring(0, dotIndex);
268: suffix = pathname.substring(dotIndex + 1, pathname
269: .length());
270: final Set suffixes = WorldImageFormat
271: .getWorldExtension(suffix);
272: final Iterator it = suffixes.iterator();
273: StringBuffer buff = new StringBuffer(fileName);
274: do {
275: answer = new File(buff.append((String) it.next())
276: .toString()).exists();
277: buff = new StringBuffer(fileName);
278: } while (!answer && it.hasNext());
279: if (!answer) {
280: buff.setLength(0);
281: buff.append(fileName);
282: buff.append(".wld");
283: answer = new File(buff.toString()).exists();
284: }
285: if (!answer) {
286: buff.setLength(0);
287: buff.append(fileName);
288: buff.append(".meta");
289: answer = new File(buff.toString()).exists();
290: }
291: }
292:
293: }
294: return answer;
295: }
296:
297: /**
298: * Takes an image file extension (such as .gif, including the '.') and
299: * returns it's corresponding world file extension (such as .gfw).
300: *
301: * @param fileExtension
302: * an image file extension, including the '.'
303: *
304: * @return a corresponding {@link Set} of world file extensions, including
305: * the '.'
306: */
307: public static Set getWorldExtension(String fileExtension) {
308: if (fileExtension == null) {
309: return null;
310: }
311:
312: if (fileExtension.equalsIgnoreCase("png")) {
313: return PNG_WFILE_EXT;
314: }
315:
316: if (fileExtension.equals("gif")) {
317: return GIF_WFILE_EXT;
318: }
319:
320: if (fileExtension.equalsIgnoreCase("jpg")
321: || fileExtension.equalsIgnoreCase("jpeg")) {
322: return JPG_WFILE_EXT;
323: }
324:
325: if (fileExtension.equalsIgnoreCase("tif")
326: || fileExtension.equalsIgnoreCase("tiff")) {
327: return TIFF_WFILE_EXT;
328: }
329:
330: if (fileExtension.equalsIgnoreCase("bmp")) {
331: return BMP_WFILE_EXT;
332: }
333:
334: return null;
335: }
336:
337: /**
338: * Retrieves a {@link WorldImageReader} in case the providede
339: * <code>source</code> can be accepted as a valid source for a world
340: * image. The method returns null otherwise.
341: *
342: * @param source
343: * The source object to read a WorldImage from
344: * @param hints
345: * {@link Hints} to control the provided {@link WorldImageReader}.
346: * @return a new WorldImageReader for the source
347: */
348: public GridCoverageReader getReader(Object source, Hints hints) {
349: try {
350: return new WorldImageReader(source, hints);
351: } catch (DataSourceException e) {
352: if (LOGGER.isLoggable(Level.WARNING))
353: LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
354: return null;
355: }
356: }
357:
358: /**
359: * Always returns null since for the moment there are no
360: * {@link GeoToolsWriteParams} availaible for this format.
361: *
362: * @return always null.
363: */
364: public GeoToolsWriteParams getDefaultImageIOWriteParameters() {
365: return null;
366: }
367: }
|