001 //$HeadURL: https://sushibar/svn/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $ 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 037 package org.deegree.tools.raster; 038 039 import java.awt.geom.AffineTransform; 040 import java.awt.geom.NoninvertibleTransformException; 041 import java.awt.image.BufferedImage; 042 import java.awt.image.ColorModel; 043 import java.awt.image.SampleModel; 044 import java.io.File; 045 import java.io.IOException; 046 import java.util.LinkedList; 047 048 import javax.imageio.ImageIO; 049 050 import org.deegree.framework.log.ILogger; 051 import org.deegree.framework.log.LoggerFactory; 052 import org.deegree.model.coverage.grid.WorldFile; 053 import org.deegree.model.spatialschema.Envelope; 054 import org.deegree.model.spatialschema.GeometryFactory; 055 import org.deegree.processing.raster.converter.Image2RawData; 056 import org.deegree.processing.raster.converter.RawData2Image; 057 058 /** 059 * <code>WorldfileNormalizer</code> 060 * 061 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a> 062 * @author last edited by: $Author:$ 063 * 064 * @version $Revision:$, $Date:$ 065 */ 066 public class WorldfileNormalizer { 067 068 private static ILogger LOG = LoggerFactory.getLogger( WorldfileNormalizer.class ); 069 070 private Config config; 071 072 private double resx, resy, rotx, roty, minx, miny; 073 074 // int xmin = Integer.MAX_VALUE; 075 // 076 // int ymin = Integer.MAX_VALUE; 077 // 078 // int xmax = Integer.MIN_VALUE; 079 // 080 // int ymax = Integer.MIN_VALUE; 081 082 private int width, height; 083 084 private AffineTransform transform = new AffineTransform(); 085 086 /** 087 * @param config 088 */ 089 public WorldfileNormalizer( Config config ) { 090 this.config = config; 091 } 092 093 // x -> y -> interpolation -> wert 094 private float getValue( Image2RawData data, double x, double y ) { 095 // transform = new AffineTransform(resx, roty, minx + x*resx, rotx, resy, miny + y*resy); 096 097 // System.out.println( transform ); 098 // try { 099 // transform = transform.createInverse(); 100 // } catch ( NoninvertibleTransformException e ) { 101 // // TODO Auto-generated catch block 102 // e.printStackTrace(); 103 // } 104 // int srcy = (int)( ( resx * ( y - miny ) - rotx * ( x - minx ) ) / denominator ); 105 // int srcx = (int)( ( x - roty * srcy - minx ) / resx ); 106 // int srcy = (int)( ( ( y ) - rotx * ( x ) ) / denominator ); 107 // int srcx = (int)( ( x - roty * srcy ) ); 108 109 // double tmpx = (int) ( x * cos1 - y * sin1 ); 110 // double tmpy = (int) ( x * sin1 + y * cos1 ); 111 double[] dest = new double[2]; 112 transform.transform( new double[] { x, y }, 0, dest, 0, 1 ); 113 int srcx = (int) ( dest[0] ); 114 int srcy = (int) ( dest[1] ); 115 if ( srcx < width && srcx >= 0 && srcy >= 0 && srcy < height ) { 116 return data.get( srcx, srcy ); 117 } 118 119 // System.out.println( srcx + "/" + srcy ); 120 return 0; 121 } 122 123 // private int getTargetWidth() { 124 // double hyp = width / Math.cos( rotx ); 125 // hyp *= hyp; 126 // double res = Math.sqrt( hyp - width * width ); 127 // return (int) ( width + res ); 128 // } 129 // 130 // private int getTargetHeight() { 131 // double hyp = height / Math.cos( rotx ); 132 // hyp *= hyp; 133 // double res = Math.sqrt( hyp - height * height ); 134 // return (int) ( height + res ); 135 // } 136 137 private void normalize( String file ) 138 throws IOException { 139 // avoid trying to read world files as images 140 if ( WorldFile.hasWorldfileSuffix( file ) ) { 141 return; 142 } 143 BufferedImage src = null; 144 try { 145 LOG.logInfo( "Reading " + file ); 146 src = ImageIO.read( new File( file ) ); // ImageUtils.loadImage( file ); 147 // src = ImageUtils.loadImage( file ); 148 } catch ( Exception e ) { 149 LOG.logError( e.getMessage(), e ); 150 LOG.logInfo( "Ignoring " + file ); 151 // ignore faulty images/files that are no images 152 return; 153 } 154 155 LOG.logInfo( "Read " + file ); 156 157 WorldFile wf = WorldFile.readWorldFile( file, config.type, src ); 158 159 Envelope env = wf.getEnvelope(); 160 161 file = file.substring( 0, file.length() - 4 ); 162 resx = wf.getResx(); 163 resy = -wf.getResy(); 164 rotx = wf.getRotation1(); 165 roty = wf.getRotation2(); 166 minx = env.getMin().getX(); 167 miny = env.getMax().getY(); 168 double maxx = Double.MIN_VALUE, maxy = Double.MIN_VALUE; 169 minx = Double.MIN_VALUE; 170 miny = Double.MIN_VALUE; 171 width = Math.abs( (int) ( wf.getEnvelope().getWidth() / resx ) ) + 1; 172 height = Math.abs( (int) ( wf.getEnvelope().getHeight() / resy ) ) + 1; 173 174 transform = new AffineTransform( resx, rotx, roty, resy, minx, miny ); 175 try { 176 177 double[] d = new double[2]; 178 for ( int x = 0; x < width; ++x ) 179 for ( int y = 0; y < height; ++y ) { 180 181 transform.transform( new double[] { x, y }, 0, d, 0, 1 ); 182 if ( d[0] > maxx ) 183 maxx = d[0]; 184 185 if ( d[1] > maxy ) 186 maxy = d[1]; 187 188 if ( d[0] < minx ) 189 minx = d[0]; 190 191 if ( d[1] < miny ) 192 miny = d[1]; 193 } 194 195 transform = transform.createInverse(); 196 } catch ( NoninvertibleTransformException e ) { 197 LOG.logError( "Worldfile was filled with invalid parameters.", e ); 198 } 199 200 int twidth = (int) ( ( maxx - minx ) / resx ); 201 int theight = (int) -( ( maxy - miny ) / resy ); 202 203 LOG.logInfo( "Target image size is " + twidth + "x" + theight ); 204 205 LOG.logInfo( "Image size is " + width + "x" + height ); 206 Image2RawData srcData = new Image2RawData( src ); 207 208 ColorModel model = src.getColorModel(); 209 SampleModel sampleModel = src.getSampleModel(); 210 211 float[][] destData = new float[theight][twidth]; 212 for ( int i = 0; i < theight; ++i ) { 213 destData[i] = new float[twidth]; 214 } 215 216 LOG.logInfo( "Transforming image." ); 217 for ( int x = 0; x < twidth; ++x ) { 218 if ( x % 1000 == 0 ) { 219 System.out.print( "\r" + x ); 220 } 221 for ( int y = 0; y < theight; ++y ) { 222 destData[destData.length - y - 1][x] = getValue( srcData, x * resx + minx, miny - y * resy ); 223 } 224 } 225 226 System.out.println( "\r " ); 227 LOG.logInfo( "Finished transforming image." ); 228 srcData = null; 229 src = null; 230 System.gc(); 231 System.gc(); 232 // LOG.logInfo( "Target image size is " + twidth + "x" + theight ); 233 234 LOG.logInfo( "Creating target image..." ); 235 BufferedImage dest = RawData2Image.rawData2Image( destData, true, model, sampleModel ); 236 destData = null; 237 System.gc(); 238 System.gc(); 239 240 LOG.logInfo( "Writing target image..." ); 241 ImageIO.write( dest, "jpeg", new File( file + "_converted.jpg" ) ); 242 LOG.logInfo( "Finished writing image." ); 243 244 double minx = env.getMin().getX(); 245 double miny = env.getMin().getY(); 246 Envelope env2 = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, env.getCoordinateSystem() ); 247 248 WorldFile outWF = new WorldFile( resx, resy, 0, 0, env2 ); 249 WorldFile.writeWorldFile( outWF, file + "_converted" ); 250 } 251 252 private void normalize() { 253 while ( config.files.size() > 0 ) { 254 String file = config.files.poll(); 255 try { 256 normalize( file ); 257 } catch ( IOException e ) { 258 LOG.logWarning( "No world file named '" + file + "' could be found/read." ); 259 e.printStackTrace(); 260 } 261 } 262 } 263 264 /** 265 * @param args 266 */ 267 public static void main( String[] args ) { 268 if ( args.length == 0 ) { 269 printUsage( null ); 270 } 271 272 WorldfileNormalizer wfn = new WorldfileNormalizer( new Config( args ) ); 273 wfn.normalize(); 274 } 275 276 /** 277 * Prints usage information and exits. 278 * 279 * @param msg 280 */ 281 public static void printUsage( String msg ) { 282 if ( msg != null ) { 283 System.out.println( msg ); 284 System.out.println(); 285 } 286 287 System.out.println( "Usage:" ); 288 System.out.println( "java -cp ... " + WorldfileNormalizer.class.getCanonicalName() + " <options> <files>" ); 289 System.out.println(); 290 System.out.println( " --help, -h:" ); 291 System.out.println( " Print out this message and exit." ); 292 System.out.println( " --directory, -d <dir>:" ); 293 System.out.println( " Adds all worldfiles in a directory to the list of files." ); 294 System.out.println( " --type, -t <type>:" ); 295 System.out.println( " Set the INPUT world file type, either to 'center' or to 'outer'." ); 296 System.out.println( " Note that the output world file type will always be 'center'." ); 297 System.out.println( " For details on the world file types see the documentation" ); 298 System.out.println( " of the RasterTreeBuilder." ); 299 System.out.println( " --interpolation, -i <method>:" ); 300 System.out.println( " Set the interpolation method. Can be one of 'bicubic', 'bilinear' or" ); 301 System.out.println( " 'nearest'. Default is nearest neighbor." ); 302 303 System.exit( 0 ); 304 } 305 306 private static class Config { 307 308 /** 309 * List of files to convert. 310 */ 311 public LinkedList<String> files = new LinkedList<String>(); 312 313 /** 314 * The type of the world files. 315 */ 316 public WorldFile.TYPE type = WorldFile.TYPE.CENTER; 317 318 /** 319 * Interpolation method, default is 'nearest'. 320 */ 321 public String interpolation = "nearest"; 322 323 /** 324 * Parses the commandline arguments. If -h or --help is contained in the array, the 325 * application will exit. 326 * 327 * @param args 328 * cmdline arguments 329 */ 330 public Config( String[] args ) { 331 int i = 0; 332 333 while ( i < args.length ) { 334 if ( args[i].equals( "-h" ) || args[i].equals( "--help" ) ) { 335 printUsage( null ); 336 } else if ( args[i].equals( "--type" ) || args[i].equals( "-t" ) ) { 337 if ( args[i + 1].equalsIgnoreCase( "outer" ) ) { 338 type = WorldFile.TYPE.OUTER; 339 } 340 if ( args[i + 1].equalsIgnoreCase( "center" ) ) { 341 type = WorldFile.TYPE.CENTER; 342 } 343 i += 2; 344 } else if ( args[i].equals( "--interpolation" ) || args[i].equals( "-i" ) ) { 345 String m = args[i + 1].toLowerCase(); 346 if ( m.equals( "nearest" ) || m.equals( "bilinear" ) || m.equals( "biqubic" ) ) { 347 interpolation = m; 348 } else { 349 printUsage( "Unknown interpolation method: '" + m + "'" ); 350 } 351 i += 2; 352 } else if ( args[i].equals( "-d" ) || args[i].equals( "--directory" ) ) { 353 File dir = new File( args[i + 1] ); 354 File[] fs = dir.listFiles(); 355 for ( File f : fs ) { 356 String s = f.getAbsolutePath(); 357 if ( s.toLowerCase().endsWith( "jpg" ) || s.toLowerCase().endsWith( "jpeg" ) 358 || s.toLowerCase().endsWith( "gif" ) || s.toLowerCase().endsWith( "png" ) 359 || s.toLowerCase().endsWith( "tif" ) || s.toLowerCase().endsWith( "tiff" ) 360 || s.toLowerCase().endsWith( "bmp" ) ) { 361 files.add( s ); 362 } 363 } 364 i += 2; 365 } else { 366 files.add( args[i] ); 367 ++i; 368 } 369 } 370 } 371 372 } 373 374 }