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