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 }