    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/tools/raster/RasterSplitter.java $
    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    package org.deegree.tools.raster;
    037
    038    import java.awt.image.BufferedImage;
    039    import java.io.File;
    040    import java.io.FilenameFilter;
    041    import java.net.URI;
    042    import java.util.ArrayList;
    043    import java.util.List;
    044    import java.util.Properties;
    045
    046    import javax.media.jai.TiledImage;
    047
    048    import org.deegree.datatypes.QualifiedName;
    049    import org.deegree.framework.log.ILogger;
    050    import org.deegree.framework.log.LoggerFactory;
    051    import org.deegree.framework.util.ImageUtils;
    052    import org.deegree.framework.util.StringTools;
    053    import org.deegree.io.dbaseapi.DBaseFile;
    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.ogcbase.CommonNamespaces;
    058
    059    /**
    060     *
    061     *
    062     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    063     * @author last edited by: $Author: mschneider $
    064     *
    065     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    066     */
    067    public class RasterSplitter {
    068
    069        private static final ILogger LOG = LoggerFactory.getLogger( RasterSplitter.class );
    070
    071        private static final URI DEEGREEAPP = CommonNamespaces.buildNSURI( "http://www.deegree.org/app" );
    072
    073        private static final String APP_PREFIX = "app";
    074
    075        private String outDir;
    076
    077        private int tileWidth = 0;
    078
    079        private int tileHeight = 0;
    080
    081        private String format;
    082
    083        private List<String> fileList;
    084
    085        /**
    086         *
    087         * @param rootDir
    088         * @param outDir
    089         * @param tileWidth
    090         * @param tileHeight
    091         * @param format
    092         * @param subDirs
    093         */
    094        RasterSplitter( String rootDir, String outDir, int tileWidth, int tileHeight, String format, boolean subDirs ) {
    095            this.outDir = outDir;
    096            this.format = format;
    097            this.tileWidth = tileWidth;
    098            this.tileHeight = tileHeight;
    099            fileList = getFileList( rootDir, subDirs );
    100        }
    101
    102        /**
    103         * @param rootDir
    104         * @param outDir
    105         * @param tileWidth
    106         * @param tileHeight
    107         * @param dBase
    108         * @param format
    109         * @param fileColumn
    110         * @throws Exception
    111         */
    112        RasterSplitter( String rootDir, String outDir, int tileWidth, int tileHeight, String dBase, String format,
    113                        String fileColumn ) throws Exception {
    114
    115            this.outDir = outDir;
    116            this.format = format;
    117            this.tileWidth = tileWidth;
    118            this.tileHeight = tileHeight;
    119            fileList = getFileList( dBase, fileColumn, rootDir );
    120        }
    121
    122        /**
    123         * splits all files identified by the root dir or dbase file
    124         *
    125         * @throws Exception
    126         */
    127        public void perform()
    128                                throws Exception {
    129            for ( int i = 0; i < fileList.size(); i++ ) {
    130                System.out.print( "processing: " + fileList.get( i ) );
    131                splitFile( fileList.get( i ) );
    132            }
    133        }
    134
    135        /**
    136         * returns the list of image map files to consider read from a dbase file defined by the dbase
    137         * parameter
    138         *
    139         * @param dbaseFile
    140         *            name of the dbase file
    141         * @param fileColumn
    142         *            name of the column containing the image map files names
    143         * @param baseDir
    144         *            name of the directory where the image map files are stored if this parameter is
    145         *            <code>null</code> it is assumed that the image map files are full referenced
    146         *            within the dbase
    147         * @return the list of image map files to consider read from a dbase file defined by the dbase
    148         *         parameter
    149         * @throws Exception
    150         */
    151        private static List<String> getFileList( String dBaseFile, String fileColumn, String baseDir )
    152                                throws Exception {
    153
    154            System.out.println( "reading file list ..." );
    155
    156            // handle dbase file extension and file location/reading problems
    157            if ( dBaseFile.endsWith( ".dbf" ) ) {
    158                dBaseFile = dBaseFile.substring( 0, dBaseFile.lastIndexOf( "." ) );
    159            }
    160            DBaseFile dbf = new DBaseFile( dBaseFile );
    161
    162            // sort dbase file contents chronologicaly (oldest first)
    163            int cnt = dbf.getRecordNum();
    164
    165            Object[] mapItems = new Object[cnt];
    166            QualifiedName fileC = new QualifiedName( APP_PREFIX, fileColumn.toUpperCase(), DEEGREEAPP );
    167
    168            for ( int i = 0; i < cnt; i++ ) {
    169                // name of map file
    170                mapItems[i] = dbf.getFRow( i + 1 ).getDefaultProperty( fileC ).getValue();
    171            }
    172
    173            // extract names of image files from dBase file and attach them to rootDir
    174            if ( baseDir == null ) {
    175                baseDir = "";
    176            } else if ( !baseDir.endsWith( "/" ) && !baseDir.endsWith( "\\" ) ) {
    177                baseDir = baseDir + '/';
    178            }
    179            List<String> imageFiles = new ArrayList<String>( mapItems.length );
    180            for ( int i = 0; i < mapItems.length; i++ ) {
    181                if ( mapItems[i] != null ) {
    182                    imageFiles.add( baseDir + mapItems[i] );
    183                }
    184            }
    185
    186            return imageFiles;
    187        }
    188
    189        /**
    190         * returns the list of image map files to consider read from a defined root directory.
    191         *
    192         * @param rootDir
    193         *            root directory where to read image map files
    194         * @param subdirs
    195         *            true if subdirectories of the root directory shall be parsed for image maps too
    196         * @return the list of image map files to consider read from a defined root directory.
    197         */
    198        private static List<String> getFileList( String rootDir, boolean subdirs ) {
    199            System.out.println( "reading file list ..." );
    200            List<String> list = new ArrayList<String>( 10000 );
    201            File file = new File( rootDir );
    202            String[] entries = file.list( new DFileFilter() );
    203            if ( entries != null ) {
    204                for ( int i = 0; i < entries.length; i++ ) {
    205                    File entry = new File( rootDir + '/' + entries[i] );
    206                    if ( entry.isDirectory() && subdirs ) {
    207                        list = readSubDirs( entry, list );
    208                    } else {
    209                        list.add( rootDir + '/' + entries[i] );
    210                    }
    211                }
    212            }
    213            return list;
    214        }
    215
    216        /**
    217         *
    218         * @param file
    219         * @param list
    220         * @return a list of strings
    221         */
    222        private static List<String> readSubDirs( File file, List<String> list ) {
    223
    224            String[] entries = file.list( new DFileFilter() );
    225            if ( entries != null ) {
    226                for ( int i = 0; i < entries.length; i++ ) {
    227                    File entry = new File( file.getAbsolutePath() + '/' + entries[i] );
    228                    if ( entry.isDirectory() ) {
    229                        list = readSubDirs( entry, list );
    230                    } else {
    231                        list.add( file.getAbsolutePath() + '/' + entries[i] );
    232                    }
    233                }
    234            }
    235            return list;
    236        }
    237
    238        private void splitFile( String inFile )
    239                                throws Exception {
    240
    241            System.out.println( "processing: " + inFile );
    242            BufferedImage bi = ImageUtils.loadImage( inFile );
    243            WorldFile wf = WorldFile.readWorldFile( inFile, WorldFile.TYPE.CENTER, bi.getWidth(), bi.getHeight() );
    244            TiledImage ti = new TiledImage( bi, tileWidth, tileHeight );
    245
    246            int cntx = bi.getWidth() / tileWidth;
    247            if ( cntx * tileWidth < bi.getWidth() ) {
    248                cntx++;
    249            }
    250            int cnty = bi.getHeight() / tileHeight;
    251            if ( cnty * tileHeight < bi.getHeight() ) {
    252                cnty++;
    253            }
    254
    255            int p = inFile.lastIndexOf( '/' );
    256            String base = inFile.substring( p + 1, inFile.length() );
    257            base = StringTools.replace( base, ".", "_", true );
    258
    259            double res = wf.getResx();
    260            Envelope env = wf.getEnvelope();
    261            for ( int i = 0; i < cntx; i++ ) {
    262                for ( int j = 0; j < cnty; j++ ) {
    263                    String s = StringTools.concat( 200, "processing tile: ", i, ' ', j, " of ", cntx, '/', cnty, "\r" );
    264                    System.out.print( s );
    265                    System.gc();
    266                    int w = tileWidth;
    267                    int h = tileHeight;
    268                    if ( i * tileWidth + tileWidth > bi.getWidth() ) {
    269                        w = bi.getWidth() - i * tileWidth;
    270                    }
    271                    if ( i * tileHeight + tileHeight > bi.getHeight() ) {
    272                        h = bi.getHeight() - i * tileHeight;
    273                    }
    274                    if ( w > 0 && h > 0 ) {
    275                        BufferedImage sub = ti.getSubImage( i * tileWidth, j * tileHeight, w, h ).getAsBufferedImage();
    276                        double x1 = env.getMin().getX() + i * tileWidth * res;
    277                        double y1 = env.getMax().getY() - ( j + 1 ) * tileHeight * res;
    278                        double x2 = env.getMin().getX() + ( i + 1 ) * tileWidth * res;
    279                        double y2 = env.getMax().getY() - j * tileHeight * res;
    280                        ;
    281                        Envelope subEnv = GeometryFactory.createEnvelope( x1, y1, x2, y2, null );
    282                        WorldFile subWf = new WorldFile( res, res, 0, 0, subEnv );
    283                        s = StringTools.concat( 300, outDir, '/', base, '_', i, '_', j, '.', format );
    284                        ImageUtils.saveImage( sub, s, 1 );
    285                        s = StringTools.concat( 300, outDir, '/', base, '_', i, '_', j );
    286                        WorldFile.writeWorldFile( subWf, s );
    287                    }
    288                }
    289            }
    290            bi = null;
    291            System.gc();
    292        }
    293
    294        private static void printHelp() {
    295            System.out.println();
    296            System.out.println( "Parameter description for RasterSplitter:" );
    297            System.out.println( "-tileWidth : desired width of result images (mandatory)" );
    298            System.out.println( "-tileHeight : desired width of result images (mandatory)" );
    299            System.out.println( "-format : desired image format of result images (mandatory)" );
    300            System.out.println( "-outDir : directory where result images shall be stored (mandatory)" );
    301
    302            System.out.println( "-rootDir : directory from where images to split will be read (mandatory)" );
    303            System.out.println( "-subDirs : (true|false). If 'true' all sub directories of the 'rootDir' " );
    304            System.out.println( "            will be searched for images too (optional; default = false)" );
    305        }
    306
    307        private static boolean validate( Properties map ) {
    308            if ( map.getProperty( "-tileWidth" ) == null ) {
    309                System.out.println( "-tileWidth must be set!" );
    310                return false;
    311            }
    312            if ( map.getProperty( "-tileHeight" ) == null ) {
    313                System.out.println( "-tileHeight must be set!" );
    314                return false;
    315            }
    316            if ( map.getProperty( "-format" ) == null ) {
    317                System.out.println( "-format must be set!" );
    318                return false;
    319            }
    320            if ( map.getProperty( "-outDir" ) == null ) {
    321                System.out.println( "-outDir must be set!" );
    322                return false;
    323            }
    324            if ( map.getProperty( "-rootDir" ) == null ) {
    325                System.out.println( "-rootDir must be set!" );
    326                return false;
    327            }
    328            if ( map.getProperty( "-subDirs" ) != null && !"true".equals( map.getProperty( "-subDirs" ) )
    329                 && !"false".equals( map.getProperty( "-subDirs" ) ) ) {
    330                System.out.println( "if -subDirs is set it must be true or false!" );
    331                return false;
    332            }
    333            return true;
    334        }
    335
    336        /**
    337         *
    338         * @param args
    339         * @throws Exception
    340         */
    341        public static void main( String[] args )
    342                                throws Exception {
    343
    344            Properties map = new Properties();
    345            for ( int i = 0; i < args.length; i += 2 ) {
    346                map.put( args[i], args[i + 1] );
    347            }
    348            if ( !validate( map ) ) {
    349                printHelp();
    350                return;
    351            }
    352
    353            int tileWidth = Integer.parseInt( map.getProperty( "-tileWidth" ) );
    354            int tileHeight = Integer.parseInt( map.getProperty( "-tileHeight" ) );
    355            String format = map.getProperty( "-format" );
    356            String outDir = map.getProperty( "-outDir" );
    357
    358            RasterSplitter rs = null;
    359            if ( map.get( "-dbaseFile" ) != null ) {
    360                String dBaseFile = map.getProperty( "-dbaseFile" );
    361                String fileColum = map.getProperty( "-fileColumn" );
    362                String baseDir = map.getProperty( "-baseDir" );
    363                if ( baseDir == null ) {
    364                    baseDir = map.getProperty( "-rootDir" );
    365                }
    366                rs = new RasterSplitter( baseDir, outDir, tileWidth, tileHeight, dBaseFile, format, fileColum );
    367            } else if ( map.get( "-rootDir" ) != null ) {
    368                String rootDir = map.getProperty( "-rootDir" );
    369                boolean subDirs = "true".equals( map.get( "-subDirs" ) );
    370                rs = new RasterSplitter( rootDir, outDir, tileWidth, tileHeight, format, subDirs );
    371
    372            } else {
    373                LOG.logInfo( map.toString() );
    374                System.out.println( "-rootDir or -dbaseFile parameter must be defined" );
    375                return;
    376            }
    377            rs.perform();
    378        }
    379
    380        /**
    381         * class: official version of a FilenameFilter
    382         */
    383        static class DFileFilter implements FilenameFilter {
    384
    385            private List<String> extensions = null;
    386
    387            /**
    388             *
    389             */
    390            public DFileFilter() {
    391                extensions = new ArrayList<String>();
    392                extensions.add( "JPEG" );
    393                extensions.add( "JPG" );
    394                extensions.add( "BMP" );
    395                extensions.add( "PNG" );
    396                extensions.add( "GIF" );
    397                extensions.add( "TIF" );
    398                extensions.add( "TIFF" );
    399                extensions.add( "GEOTIFF" );
    400            }
    401
    402            /**
    403             * @return the String "*.*"
    404             */
    405            public String getDescription() {
    406                return "*.*";
    407            }
    408
    409            /*
    410             * (non-Javadoc)
    411             *
    412             * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
    413             */
    414            public boolean accept( java.io.File file, String name ) {
    415                int pos = name.lastIndexOf( "." );
    416                String ext = name.substring( pos + 1 ).toUpperCase();
    417                if ( file.isDirectory() ) {
    418                    String s = file.getAbsolutePath() + '/' + name;
    419                    File tmp = new File( s );
    420                    if ( tmp.isDirectory() ) {
    421                        return true;
    422                    }
    423                }
    424                return extensions.contains( ext );
    425            }
    426        }
    427    }