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