001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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    }