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    }