    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    }