001: /*
002: * Geotools 2 - OpenSource mapping toolkit
003: * (C) 2006, Geotools Project Managment Committee (PMC)
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019: package org.geotools.gce.imagemosaic;
020:
021: import java.awt.Color;
022: import java.io.BufferedInputStream;
023: import java.io.File;
024: import java.io.FileInputStream;
025: import java.io.IOException;
026: import java.io.UnsupportedEncodingException;
027: import java.net.MalformedURLException;
028: import java.net.URL;
029: import java.net.URLDecoder;
030: import java.util.HashMap;
031: import java.util.Properties;
032: import java.util.logging.Level;
033: import java.util.logging.Logger;
034:
035: import org.geotools.coverage.grid.io.AbstractGridFormat;
036: import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
037: import org.geotools.data.FeatureSource;
038: import org.geotools.data.shapefile.ShapefileDataStore;
039: import org.geotools.factory.Hints;
040: import org.geotools.feature.FeatureType;
041: import org.geotools.parameter.DefaultParameterDescriptor;
042: import org.geotools.parameter.DefaultParameterDescriptorGroup;
043: import org.geotools.parameter.ParameterGroup;
044: import org.opengis.coverage.grid.Format;
045: import org.opengis.coverage.grid.GridCoverageReader;
046: import org.opengis.coverage.grid.GridCoverageWriter;
047: import org.opengis.parameter.GeneralParameterDescriptor;
048:
049: /**
050: * {@link AbstractGridFormat} sublass for controlling {@link ImageMosaicReader}
051: * creation.
052: *
053: * As the name says, it handles mosaic of georeferenced images, which means
054: * <ol>
055: * <li>tiff+tfw+prj</li>
056: * <li>jpeg+tfw+prj</li>
057: * <li>png+tfw+prj</li>
058: * <li>geotiff</li>
059: * </ol>
060: * This does not mean that you throw there a couple of images and it will do the
061: * trick no matter how these images are. Requirements are:
062: *
063: * <ul>
064: * <li>(almost) equal spatial resolution</li>
065: * <li>same number of bands</li>
066: * <li>same data type</li>
067: * <li>same projection</li>
068: * </ul>
069: *
070: * The first requirement can be relaxed a little but if they have the same
071: * spatial resolution the performances are much better.
072: *
073: * There are parameters that you can use to control the behaviour of the mosaic
074: * in terms of thresholding and transparency. They are as follows:
075: *
076: * <ul>
077: * <li>--DefaultParameterDescriptor FINAL_ALPHA = new
078: * DefaultParameterDescriptor( "FinalAlpha", Boolean.class, null,
079: * Boolean.FALSE)-- It asks the plugin to add transparency on the final created
080: * mosaic. IT simply performs a threshonding looking for areas where there is no
081: * data, i.e., intensity is really low and transform them into transparent
082: * areas. It is obvious that depending on the nature of the input images it
083: * might interfere with the original values.</li>
084: *
085: *
086: * <li>---ALPHA_THRESHOLD = new DefaultParameterDescriptor( "AlphaThreshold",
087: * Double.class, null, new Double(1));--- Controls the transparency addition by
088: * specifying the treshold to use.</li>
089: *
090: *
091: * <li>INPUT_IMAGE_THRESHOLD = new DefaultParameterDescriptor( "InputImageROI",
092: * Boolean.class, null, Boolean.FALSE)--- INPUT_IMAGE_THRESHOLD_VALUE = new
093: * DefaultParameterDescriptor( "InputImageROIThreshold", Integer.class, null,
094: * new Integer(1));--- These two can be used to control the application of ROIs
095: * on the input images based on tresholding values. Basically using the threshold
096: * you can ask the mosaic plugin to load or not certain pixels of the original
097: * images.</li>
098: *
099: *
100: * @author Simone Giannecchini (simboss)
101: * @since 2.3
102: */
103: public final class ImageMosaicFormat extends AbstractGridFormat
104: implements Format {
105:
106: /** Logger. */
107: private final static Logger LOGGER = org.geotools.util.logging.Logging
108: .getLogger("org.geotools.gce.imagemosaic");
109:
110: /** Control the type of the final mosaic. */
111: public static final DefaultParameterDescriptor FADING = new DefaultParameterDescriptor(
112: "Fading", Boolean.class, null, Boolean.FALSE);
113:
114: /** Control the transparency of the input coverages. */
115: public static final DefaultParameterDescriptor INPUT_TRANSPARENT_COLOR = new DefaultParameterDescriptor(
116: "InputTransparentColor", Color.class, null, null);
117:
118: /** Control the transparency of the output coverage. */
119: public static final DefaultParameterDescriptor OUTPUT_TRANSPARENT_COLOR = new DefaultParameterDescriptor(
120: "OutputTransparentColor", Color.class, null, null);
121:
122: /** Control the thresholding on the input coverage */
123: public static final DefaultParameterDescriptor INPUT_IMAGE_THRESHOLD_VALUE = new DefaultParameterDescriptor(
124: "InputImageThresholdValue", Double.class, null, new Double(
125: Double.NaN));
126:
127: /**
128: * Creates an instance and sets the metadata.
129: */
130: public ImageMosaicFormat() {
131: setInfo();
132: }
133:
134: /**
135: * Sets the metadata information.
136: */
137: private void setInfo() {
138: HashMap info = new HashMap();
139:
140: info.put("name", "ImageMosaic");
141: info.put("description", "Image mosaicking plugin");
142: info.put("vendor", "Geotools");
143: info.put("docURL", "");
144: info.put("version", "1.0");
145: mInfo = info;
146:
147: // reading parameters
148: readParameters = new ParameterGroup(
149: new DefaultParameterDescriptorGroup(mInfo,
150: new GeneralParameterDescriptor[] {
151: READ_GRIDGEOMETRY2D,
152: INPUT_TRANSPARENT_COLOR,
153: INPUT_IMAGE_THRESHOLD_VALUE,
154: OUTPUT_TRANSPARENT_COLOR }));
155:
156: // reading parameters
157: writeParameters = null;
158: }
159:
160: /**
161: * @see org.geotools.data.coverage.grid.AbstractGridFormat#getReader(Object)
162: */
163: public GridCoverageReader getReader(Object source) {
164: return getReader(source, null);
165: }
166:
167: /**
168: *
169: */
170: public GridCoverageWriter getWriter(Object destination) {
171: throw new UnsupportedOperationException(
172: "This plugin does not support writing.");
173: }
174:
175: /**
176: * @see org.geotools.data.coverage.grid.AbstractGridFormat#accepts(Object
177: * input)
178: */
179: public boolean accepts(Object source) {
180: try {
181:
182: URL sourceURL;
183: // /////////////////////////////////////////////////////////////////////
184: //
185: // Check source
186: //
187: // /////////////////////////////////////////////////////////////////////
188: if (source instanceof File)
189: sourceURL = ((File) source).toURL();
190: else if (source instanceof URL)
191: sourceURL = (URL) source;
192: else if (source instanceof String) {
193: final File tempFile = new File((String) source);
194: if (tempFile.exists()) {
195: sourceURL = tempFile.toURL();
196: } else
197: try {
198: sourceURL = new URL(URLDecoder.decode(
199: (String) source, "UTF8"));
200: if (sourceURL.getProtocol() != "file") {
201: return false;
202:
203: }
204: } catch (MalformedURLException e) {
205: if (LOGGER.isLoggable(Level.FINE))
206: LOGGER.log(Level.FINE, e
207: .getLocalizedMessage(), e);
208: return false;
209:
210: } catch (UnsupportedEncodingException e) {
211: if (LOGGER.isLoggable(Level.FINE))
212: LOGGER.log(Level.FINE, e
213: .getLocalizedMessage(), e);
214: return false;
215:
216: }
217:
218: } else
219: return false;
220: // /////////////////////////////////////////////////////////////////////
221: //
222: // Load tiles informations, especially the bounds, which will be
223: // reused
224: //
225: // /////////////////////////////////////////////////////////////////////
226: final ShapefileDataStore tileIndexStore = new ShapefileDataStore(
227: sourceURL);
228: final String[] typeNames = tileIndexStore.getTypeNames();
229: if (typeNames.length <= 0)
230: return false;
231: final String typeName = typeNames[0];
232: final FeatureSource featureSource = tileIndexStore
233: .getFeatureSource(typeName);
234: final FeatureType schema = featureSource.getSchema();
235: // looking for the location attribute
236: if (schema.getAttributeType("location") == null)
237: return false;
238:
239: // /////////////////////////////////////////////////////////////////////
240: //
241: // Now look for the properties file and try to parse relevant fields
242: //
243: // /////////////////////////////////////////////////////////////////////
244: String temp = URLDecoder
245: .decode(sourceURL.getFile(), "UTF8");
246: final int index = temp.lastIndexOf(".");
247: if (index != -1)
248: temp = temp.substring(0, index);
249: final File propertiesFile = new File(new StringBuffer(temp)
250: .append(".properties").toString());
251: assert propertiesFile.exists() && propertiesFile.isFile();
252: final Properties properties = new Properties();
253: properties.load(new BufferedInputStream(
254: new FileInputStream(propertiesFile)));
255:
256: // load the envelope
257: final String envelope = properties
258: .getProperty("Envelope2D");
259: String[] pairs = envelope.split(" ");
260: final double cornersV[][] = new double[2][2];
261: String pair[];
262: for (int i = 0; i < 2; i++) {
263: pair = pairs[i].split(",");
264: cornersV[i][0] = Double.parseDouble(pair[0]);
265: cornersV[i][1] = Double.parseDouble(pair[1]);
266: }
267:
268: // resolutions levels
269: Integer.parseInt(properties.getProperty("LevelsNum"));
270: final String levels = properties.getProperty("Levels");
271: pairs = levels.split(" ");
272: pair = pairs[0].split(",");
273: Double.parseDouble(pair[0]);
274: Double.parseDouble(pair[1]);
275: properties.getProperty("Name");
276: try {
277: properties.getProperty("ExpandToRGB").equalsIgnoreCase(
278: "true");
279: } catch (Exception e) {
280:
281: }
282: return true;
283: } catch (IOException e) {
284: if (LOGGER.isLoggable(Level.FINE))
285: LOGGER.log(Level.FINE, e.getLocalizedMessage(), e);
286: return false;
287:
288: }
289:
290: }
291:
292: /**
293: * @see AbstractGridFormat#getReader(Object, Hints)
294: */
295: public GridCoverageReader getReader(Object source, Hints hints) {
296: try {
297:
298: return new ImageMosaicReader(source, hints);
299: } catch (MalformedURLException e) {
300: if (LOGGER.isLoggable(Level.WARNING))
301: LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
302: return null;
303: } catch (IOException e) {
304: if (LOGGER.isLoggable(Level.WARNING))
305: LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
306: return null;
307: }
308: }
309:
310: /**
311: * Throw an exception since this plugin is readonly.
312: *
313: * @return nothing.
314: */
315: public GeoToolsWriteParams getDefaultImageIOWriteParameters() {
316: throw new UnsupportedOperationException("Unsupported method.");
317: }
318:
319: }
|