001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/coverage/grid/WorldFile.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2008 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/deegree/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 This library is free software; you can redistribute it and/or
012 modify it under the terms of the GNU Lesser General Public
013 License as published by the Free Software Foundation; either
014 version 2.1 of the License, or (at your option) any later version.
015
016 This library is distributed in the hope that it will be useful,
017 but WITHOUT ANY WARRANTY; without even the implied warranty of
018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019 Lesser General Public License for more details.
020
021 You should have received a copy of the GNU Lesser General Public
022 License along with this library; if not, write to the Free Software
023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024
025 Contact:
026
027 Andreas Poth
028 lat/lon GmbH
029 Aennchenstraße 19
030 53177 Bonn
031 Germany
032 E-Mail: poth@lat-lon.de
033
034 Prof. Dr. Klaus Greve
035 Department of Geography
036 University of Bonn
037 Meckenheimer Allee 166
038 53115 Bonn
039 Germany
040 E-Mail: greve@giub.uni-bonn.de
041
042 ---------------------------------------------------------------------------*/
043 package org.deegree.model.coverage.grid;
044
045 import java.awt.image.BufferedImage;
046 import java.io.BufferedReader;
047 import java.io.File;
048 import java.io.FileReader;
049 import java.io.FileWriter;
050 import java.io.IOException;
051 import java.io.PrintWriter;
052
053 import javax.media.jai.JAI;
054 import javax.media.jai.RenderedOp;
055
056 import org.deegree.framework.log.ILogger;
057 import org.deegree.framework.log.LoggerFactory;
058 import org.deegree.model.spatialschema.Envelope;
059 import org.deegree.model.spatialschema.GeometryFactory;
060
061 import com.sun.media.jai.codec.FileSeekableStream;
062
063 /**
064 * class representation of a ESRI world file. A world file may defines bounding coordinates centered
065 * on the outter pixel (e.g. ESRI software) or outside the bounding pixels (e.g.Oracle spatial).
066 * Reading a worldfile this must be considered so the type of a worldfile must be passed. For this a
067 * <code>enum</code> named <code>TYPE</code> ist defined.
068 *
069 *
070 * @version $Revision: 9343 $
071 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
072 * @author last edited by: $Author: apoth $
073 *
074 * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
075 */
076 public class WorldFile {
077
078 private static ILogger LOG = LoggerFactory.getLogger( WorldFile.class );
079
080 private double resx;
081
082 private double resy;
083
084 private double rotation1;
085
086 private double rotation2;
087
088 private Envelope envelope;
089
090 /**
091 * <code>TYPE</code> enumerates the world file types.
092 *
093 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
094 * @author last edited by: $Author: apoth $
095 *
096 * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
097 */
098 public enum TYPE {
099
100 /**
101 * Coordinates denote pixel centers.
102 */
103 CENTER,
104
105 /**
106 * Coordinates denote outer edges.
107 */
108 OUTER
109
110 }
111
112 /**
113 * @return a class represention of a ESRI world file
114 * @param filename
115 * name of the image/raster file inclusing path and extension
116 * @param type
117 * @throws IOException
118 */
119 public static WorldFile readWorldFile( String filename, TYPE type )
120 throws IOException {
121
122 FileSeekableStream fss = new FileSeekableStream( filename );
123 RenderedOp rop = JAI.create( "stream", fss );
124 int iw = ( (Integer) rop.getProperty( "image_width" ) ).intValue();
125 int ih = ( (Integer) rop.getProperty( "image_height" ) ).intValue();
126
127 return readWorldFile( filename, type, iw, ih );
128
129 }
130
131 /**
132 * @param name
133 * @return true, if the name ends with .tfw, .wld, .jgw, .gfw, .gifw, .pgw or .pngw.
134 */
135 public static boolean hasWorldfileSuffix( String name ) {
136 String lname = name.toLowerCase();
137 return lname.endsWith( ".tfw" ) || lname.endsWith( ".wld" ) || lname.endsWith( ".jgw" )
138 || lname.endsWith( ".gfw" ) || lname.endsWith( ".gifw" ) || lname.endsWith( ".pgw" )
139 || lname.endsWith( ".pngw" );
140 }
141
142 /**
143 * @return a class represention of a ESRI world file
144 * @param filename
145 * name of the image/raster file inclusing path and extension
146 * @param type
147 * @param width
148 * image width in pixel
149 * @param height
150 * image height in pixel
151 * @throws IOException
152 */
153 public static WorldFile readWorldFile( String filename, TYPE type, int width, int height )
154 throws IOException {
155 // Gets the substring beginning at the specified beginIndex (0) - the beginning index,
156 // inclusive - and extends to the character at index endIndex (position of '.') - the
157 // ending index, exclusive.
158
159 String fname = null;
160 int pos = filename.lastIndexOf( "." );
161 filename = filename.substring( 0, pos );
162
163 // Look for corresponding worldfiles.
164 if ( ( new File( filename + ".tfw" ) ).exists() ) {
165 fname = filename + ".tfw";
166 } else if ( ( new File( filename + ".wld" ) ).exists() ) {
167 fname = filename + ".wld";
168 } else if ( ( new File( filename + ".jgw" ) ).exists() ) {
169 fname = filename + ".jgw";
170 } else if ( ( new File( filename + ".jpgw" ) ).exists() ) {
171 fname = filename + ".jpgw";
172 } else if ( ( new File( filename + ".gfw" ) ).exists() ) {
173 fname = filename + ".gfw";
174 } else if ( ( new File( filename + ".gifw" ) ).exists() ) {
175 fname = filename + ".gifw";
176 } else if ( ( new File( filename + ".pgw" ) ).exists() ) {
177 fname = filename + ".pgw";
178 } else if ( ( new File( filename + ".pngw" ) ).exists() ) {
179 fname = filename + ".pngw";
180 } else {
181 throw new IOException( "Not a world file for: " + filename );
182 }
183
184 // Reads character files.
185 // The constructors of this class (FileReader) assume that the default character
186 // encoding and the default byte-buffer size are appropriate.
187 // The BufferedReader reads text from a character-input stream, buffering characters
188 // so as to provide for the efficient reading of characters.
189 BufferedReader br = new BufferedReader( new FileReader( fname ) );
190 String s = null;
191 int cnt = 0;
192 double d1 = 0;
193 double d2 = 0;
194 double d3 = 0;
195 double d4 = 0;
196 double d7 = 0;
197 double d8 = 0;
198 while ( ( s = br.readLine() ) != null ) {
199 cnt++;
200 s = s.trim();
201 switch ( cnt ) {
202 case 1:
203 // spatial resolution x direction
204 d1 = Double.parseDouble( s.replace( ',', '.' ) );
205 break;
206 case 2:
207 // rotation1
208 d7 = Double.parseDouble( s.replace( ',', '.' ) );
209 break;
210 case 3:
211 // rotation2
212 d8 = Double.parseDouble( s.replace( ',', '.' ) );
213 break;
214 case 4:
215 // spatial resolution y direction
216 d2 = Double.parseDouble( s.replace( ',', '.' ) );
217 break;
218 case 5:
219 // minimum x coordinate
220 d3 = Double.parseDouble( s.replace( ',', '.' ) );
221 break;
222 case 6:
223 // maximum y coordinate
224 d4 = Double.parseDouble( s.replace( ',', '.' ) );
225 break;
226 }
227 }
228 br.close();
229
230 double d5 = d3 + ( ( width - 1 ) * d1 );
231 double d6 = d4 + ( ( height - 1 ) * d2 );
232 double resx = Math.abs( d1 );
233 double resy = Math.abs( d2 );
234 double ymax = d4;
235 double ymin = d6;
236 double xmax = d5;
237 double xmin = d3;
238
239 if ( type == TYPE.OUTER ) {
240 LOG.logDebug( xmin + " " + ymin + " " + xmax + " " + ymax );
241 xmin = xmin + resx / 2d;
242 ymin = ymin - resy / 2d;
243 xmax = xmin + resx * ( width - 1 );
244 ymax = ymin + resy * ( height - 1 );
245 }
246
247 Envelope envelope = GeometryFactory.createEnvelope( xmin, ymin, xmax, ymax, null );
248
249 return new WorldFile( resx, resy, d7, d8, envelope );
250 }
251
252 /**
253 * returns a class represention of a ESRI world file
254 *
255 * @param filename
256 * name of the image/raster file inclusing path and extension
257 * @param type
258 * world file type
259 * @param image
260 * image/raster the worldfile belongs too
261 * @return a class represention of a ESRI world file
262 * @throws IOException
263 */
264 public static WorldFile readWorldFile( String filename, TYPE type, BufferedImage image )
265 throws IOException {
266
267 return readWorldFile( filename, type, image.getWidth(), image.getHeight() );
268 }
269
270 /**
271 * writes a WorldFile
272 *
273 * @param wf
274 * @param fileBaseName
275 * @throws IOException
276 */
277 public static void writeWorldFile( WorldFile wf, String fileBaseName )
278 throws IOException {
279
280 Envelope env = wf.envelope;
281
282 StringBuffer sb = new StringBuffer( 200 );
283
284 sb.append( wf.resx ).append( "\n" ).append( 0.0 ).append( "\n" ).append( 0.0 );
285 sb.append( "\n" ).append( ( -1 ) * wf.resy ).append( "\n" ).append( env.getMin().getX() );
286 sb.append( "\n" ).append( env.getMax().getY() ).append( "\n" );
287
288 File f = new File( fileBaseName + ".wld" );
289
290 FileWriter fw = new FileWriter( f );
291 PrintWriter pw = new PrintWriter( fw );
292
293 pw.print( sb.toString() );
294
295 pw.close();
296 fw.close();
297 }
298
299 /**
300 *
301 * @param resx
302 * resolution x-direction
303 * @param resy
304 * resolution y-direction (negative value)
305 * @param rotation1
306 * first rotation parameter
307 * @param rotation2
308 * second rotation parameter
309 * @param envelope
310 * the envelope of the worldfile
311 */
312 public WorldFile( double resx, double resy, double rotation1, double rotation2, Envelope envelope ) {
313 this.resx = resx;
314 this.resy = resy;
315 this.rotation1 = rotation1;
316 this.rotation2 = rotation2;
317 this.envelope = envelope;
318 }
319
320 /**
321 * returns the envelope described by a word file
322 *
323 * @return the envelope described by a word file
324 */
325 public Envelope getEnvelope() {
326 return envelope;
327 }
328
329 /**
330 * returns the x-resolution described by a word file
331 *
332 * @return the x-resolution described by a word file
333 */
334 public double getResx() {
335 return resx;
336 }
337
338 /**
339 * returns the y-resolution described by a word file
340 *
341 * @return the y-resolution described by a word file
342 */
343 public double getResy() {
344 return resy;
345 }
346
347 /**
348 * returns the first rotation described by a word file
349 *
350 * @return the first rotation described by a word file
351 */
352 public double getRotation1() {
353 return rotation1;
354 }
355
356 /**
357 * returns the second rotation described by a word file
358 *
359 * @return the second rotation described by a word file
360 */
361 public double getRotation2() {
362 return rotation2;
363 }
364
365 @Override
366 public String toString() {
367 StringBuffer sb = new StringBuffer( 200 );
368 sb.append( "envelope: " ).append( envelope ).append( "\n" );
369 sb.append( "resx: " ).append( resx ).append( "\n" );
370 sb.append( "resy: " ).append( resy ).append( "\n" );
371 sb.append( "rotation1: " ).append( rotation1 ).append( "\n" );
372 sb.append( "rotation2: " ).append( rotation2 );
373 return sb.toString();
374 }
375
376 }