001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/tools/raster/RasterSplitter.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.tools.raster;
044    
045    import java.awt.image.BufferedImage;
046    import java.io.File;
047    import java.io.FilenameFilter;
048    import java.net.URI;
049    import java.util.ArrayList;
050    import java.util.List;
051    import java.util.Properties;
052    
053    import javax.media.jai.TiledImage;
054    
055    import org.deegree.datatypes.QualifiedName;
056    import org.deegree.framework.log.ILogger;
057    import org.deegree.framework.log.LoggerFactory;
058    import org.deegree.framework.util.ImageUtils;
059    import org.deegree.framework.util.StringTools;
060    import org.deegree.io.dbaseapi.DBaseFile;
061    import org.deegree.model.coverage.grid.WorldFile;
062    import org.deegree.model.spatialschema.Envelope;
063    import org.deegree.model.spatialschema.GeometryFactory;
064    import org.deegree.ogcbase.CommonNamespaces;
065    
066    /**
067     * 
068     * 
069     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
070     * @author last edited by: $Author: apoth $
071     * 
072     * @version $Revision: 9346 $, $Date: 2007-12-27 17:39:07 +0100 (Do, 27 Dez 2007) $
073     */
074    public class RasterSplitter {
075    
076        private static final ILogger LOG = LoggerFactory.getLogger( RasterSplitter.class );
077    
078        private static final URI DEEGREEAPP = CommonNamespaces.buildNSURI( "http://www.deegree.org/app" );
079    
080        private static final String APP_PREFIX = "app";
081    
082        private String outDir;
083    
084        private int tileWidth = 0;
085    
086        private int tileHeight = 0;
087    
088        private String format;
089    
090        private List<String> fileList;
091    
092        /**
093         * 
094         * @param rootDir
095         * @param outDir
096         * @param tileWidth
097         * @param tileHeight
098         * @param format
099         * @param subDirs
100         */
101        RasterSplitter( String rootDir, String outDir, int tileWidth, int tileHeight, String format,
102                        boolean subDirs ) {
103            this.outDir = outDir;
104            this.format = format;
105            this.tileWidth = tileWidth;
106            this.tileHeight = tileHeight;
107            fileList = getFileList( rootDir, subDirs );
108        }
109    
110        /**
111         * @param rootDir
112         * @param outDir
113         * @param tileWidth
114         * @param tileHeight
115         * @param dBase
116         * @param format
117         * @param fileColumn
118         * @throws Exception
119         */
120        RasterSplitter( String rootDir, String outDir, int tileWidth, int tileHeight, String dBase,
121                        String format, String fileColumn ) throws Exception {
122    
123            this.outDir = outDir;
124            this.format = format;
125            this.tileWidth = tileWidth;
126            this.tileHeight = tileHeight;
127            fileList = getFileList( dBase, fileColumn, rootDir );
128        }
129    
130        /**
131         * splits all files identified by the root dir or dbase file
132         * 
133         * @throws Exception
134         */
135        public void perform()
136                                throws Exception {
137            for ( int i = 0; i < fileList.size(); i++ ) {
138                System.out.print("processing: " + fileList.get( i ) );
139                splitFile( fileList.get( i ) );
140            }
141        }
142    
143        /**
144         * returns the list of image map files to consider read from a dbase file defined by the dbase
145         * parameter
146         * 
147         * @param dbaseFile
148         *            name of the dbase file
149         * @param fileColumn
150         *            name of the column containing the image map files names
151         * @param baseDir
152         *            name of the directory where the image map files are stored if this parameter is
153         *            <code>null</code> it is assumed that the image map files are full referenced
154         *            within the dbase
155         * @return the list of image map files to consider read from a dbase file defined by the dbase
156         *         parameter
157         * @throws Exception
158         */
159        private static List<String> getFileList( String dBaseFile, String fileColumn, String baseDir )
160                                throws Exception {
161    
162            System.out.println("reading file list ...");
163            
164            // handle dbase file extension and file location/reading problems
165            if ( dBaseFile.endsWith( ".dbf" ) ) {
166                dBaseFile = dBaseFile.substring( 0, dBaseFile.lastIndexOf( "." ) );
167            }
168            DBaseFile dbf = new DBaseFile( dBaseFile );
169    
170            // sort dbase file contents chronologicaly (oldest first)
171            int cnt = dbf.getRecordNum();
172    
173            Object[] mapItems = new Object[cnt];
174            QualifiedName fileC = new QualifiedName( APP_PREFIX, fileColumn.toUpperCase(), DEEGREEAPP );
175    
176            for ( int i = 0; i < cnt; i++ ) {
177                // name of map file
178                mapItems[i] = dbf.getFRow( i + 1 ).getDefaultProperty( fileC ).getValue();
179            }
180    
181            // extract names of image files from dBase file and attach them to rootDir
182            if ( baseDir == null ) {
183                baseDir = "";
184            } else if ( !baseDir.endsWith( "/" ) && !baseDir.endsWith( "\\" ) ) {
185                baseDir = baseDir + '/';
186            }
187            List<String> imageFiles = new ArrayList<String>( mapItems.length );
188            for ( int i = 0; i < mapItems.length; i++ ) {
189                if ( mapItems[i] != null ) {
190                    imageFiles.add( baseDir + mapItems[i] );
191                }
192            }
193    
194            return imageFiles;
195        }
196    
197        /**
198         * returns the list of image map files to consider read from a defined root directory.
199         * 
200         * @param rootDir
201         *            root directory where to read image map files
202         * @param subdirs
203         *            true if subdirectories of the root directory shall be parsed for image maps too
204         * @return the list of image map files to consider read from a defined root directory.
205         */
206        private static List<String> getFileList( String rootDir, boolean subdirs ) {
207            System.out.println("reading file list ...");
208            List<String> list = new ArrayList<String>( 10000 );
209            File file = new File( rootDir );
210            String[] entries = file.list( new DFileFilter() );
211            if ( entries != null ) {
212                for ( int i = 0; i < entries.length; i++ ) {
213                    File entry = new File( rootDir + '/' + entries[i] );
214                    if ( entry.isDirectory() && subdirs ) {
215                        list = readSubDirs( entry, list );
216                    } else {
217                        list.add( rootDir + '/' + entries[i] );
218                    }
219                }
220            }
221            return list;
222        }
223    
224        /**
225         * 
226         * @param file
227         * @param list
228         * @return
229         */
230        private static List<String> readSubDirs( File file, List<String> list ) {
231    
232            String[] entries = file.list( new DFileFilter() );
233            if ( entries != null ) {
234                for ( int i = 0; i < entries.length; i++ ) {
235                    File entry = new File( file.getAbsolutePath() + '/' + entries[i] );
236                    if ( entry.isDirectory() ) {
237                        list = readSubDirs( entry, list );
238                    } else {
239                        list.add( file.getAbsolutePath() + '/' + entries[i] );
240                    }
241                }
242            }
243            return list;
244        }
245    
246        private void splitFile( String inFile )
247                                throws Exception {
248    
249            System.out.println( "processing: " + inFile );
250            BufferedImage bi = ImageUtils.loadImage( inFile );
251            WorldFile wf = WorldFile.readWorldFile( inFile, WorldFile.TYPE.CENTER, bi.getWidth(), 
252                                                    bi.getHeight() );
253            TiledImage ti = new TiledImage( bi, tileWidth, tileHeight );
254    
255            int cntx = bi.getWidth() / tileWidth;
256            if ( cntx * tileWidth < bi.getWidth() ) {
257                cntx++;
258            }
259            int cnty = bi.getHeight() / tileHeight;
260            if ( cnty * tileHeight < bi.getHeight() ) {
261                cnty++;
262            }
263    
264            int p = inFile.lastIndexOf( '/' );
265            String base = inFile.substring( p + 1, inFile.length() );
266            base = StringTools.replace( base, ".", "_", true );
267    
268            double res = wf.getResx();
269            Envelope env = wf.getEnvelope();
270            for ( int i = 0; i < cntx; i++ ) {
271                for ( int j = 0; j < cnty; j++ ) {
272                    String s = StringTools.concat( 200, "processing tile: ", i, ' ', j, " of ", 
273                                                   cntx, '/', cnty, "\r" );
274                    System.out.print( s );
275                    System.gc();
276                    int w = tileWidth;
277                    int h = tileHeight;
278                    if ( i * tileWidth + tileWidth > bi.getWidth() ) {
279                        w = bi.getWidth() - i * tileWidth;
280                    }
281                    if ( i * tileHeight + tileHeight > bi.getHeight() ) {
282                        h = bi.getHeight() - i * tileHeight;
283                    }
284                    if ( w > 0 && h > 0 ) {
285                        BufferedImage sub = ti.getSubImage( i * tileWidth, j * tileHeight, w, h ).getAsBufferedImage();
286                        double x1 = env.getMin().getX() + i * tileWidth * res;
287                        double y1 = env.getMax().getY() - ( j + 1 ) * tileHeight * res;
288                        double x2 = env.getMin().getX() + ( i + 1 ) * tileWidth * res;
289                        double y2 = env.getMax().getY() - j * tileHeight * res;;
290                        Envelope subEnv = GeometryFactory.createEnvelope( x1, y1, x2, y2, null );
291                        WorldFile subWf = new WorldFile( res, res, 0, 0, subEnv );
292                        s = StringTools.concat( 300, outDir, '/', base, '_', i, '_', j, '.', format ); 
293                        ImageUtils.saveImage( sub, s, 1 );
294                        s = StringTools.concat( 300, outDir, '/', base, '_', i, '_', j );
295                        WorldFile.writeWorldFile( subWf, s );
296                    }
297                }
298            }
299            bi = null;
300            System.gc();
301        }
302    
303        private static void printHelp() {
304            System.out.println();
305            System.out.println( "Parameter description for RasterSplitter:" );
306            System.out.println( "-tileWidth : desired width of result images (mandatory)" );
307            System.out.println( "-tileHeight : desired width of result images (mandatory)" );
308            System.out.println( "-format : desired image format of result images (mandatory)" );
309            System.out.println( "-outDir : directory where result images shall be stored (mandatory)" );
310    
311            System.out.println( "-rootDir : directory from where images to split will be read (mandatory)" );
312            System.out.println( "-subDirs : (true|false). If 'true' all sub directories of the 'rootDir' " );
313            System.out.println( "            will be searched for images too (optional; default = false)" );
314        }
315    
316        private static boolean validate( Properties map ) {
317            if ( map.getProperty( "-tileWidth" ) == null ) {
318                System.out.println( "-tileWidth must be set!" );
319                return false;
320            }
321            if ( map.getProperty( "-tileHeight" ) == null ) {
322                System.out.println( "-tileHeight must be set!" );
323                return false;
324            }
325            if ( map.getProperty( "-format" ) == null ) {
326                System.out.println( "-format must be set!" );
327                return false;
328            }
329            if ( map.getProperty( "-outDir" ) == null ) {
330                System.out.println( "-outDir must be set!" );
331                return false;
332            }
333            if ( map.getProperty( "-rootDir" ) == null ) {
334                System.out.println( "-rootDir must be set!" );
335                return false;
336            }
337            if ( map.getProperty( "-subDirs" ) != null
338                 && !"true".equals( map.getProperty( "-subDirs" ) )
339                 && !"false".equals( map.getProperty( "-subDirs" ) ) ) {
340                System.out.println( "if -subDirs is set it must be true or false!" );
341                return false;
342            }
343            return true;
344        }
345    
346        /**
347         * 
348         * @param args
349         * @throws Exception
350         */
351        public static void main( String[] args )
352                                throws Exception {
353    
354            Properties map = new Properties();
355            for ( int i = 0; i < args.length; i += 2 ) {
356                map.put( args[i], args[i + 1] );
357            }
358            if ( !validate( map ) ) {
359                printHelp();
360                return;
361            }
362    
363            int tileWidth = Integer.parseInt( map.getProperty( "-tileWidth" ) );
364            int tileHeight = Integer.parseInt( map.getProperty( "-tileHeight" ) );
365            String format = map.getProperty( "-format" );
366            String outDir = map.getProperty( "-outDir" );
367    
368            RasterSplitter rs = null;
369            if ( map.get( "-dbaseFile" ) != null ) {
370                String dBaseFile = map.getProperty( "-dbaseFile" );
371                String fileColum = map.getProperty( "-fileColumn" );
372                String baseDir = map.getProperty( "-baseDir" );
373                if ( baseDir == null ) {
374                    baseDir = map.getProperty( "-rootDir" );
375                }
376                rs = new RasterSplitter( baseDir, outDir, tileWidth, tileHeight, dBaseFile, format,
377                                         fileColum );
378            } else if ( map.get( "-rootDir" ) != null ) {
379                String rootDir = map.getProperty( "-rootDir" );
380                boolean subDirs = "true".equals( map.get( "-subDirs" ) );
381                rs = new RasterSplitter( rootDir, outDir, tileWidth, tileHeight, format, subDirs );
382    
383            } else {
384                LOG.logInfo( map.toString() );
385                System.out.println( "-rootDir or -dbaseFile parameter must be defined" );
386                return;
387            }
388            rs.perform();
389        }
390    
391        /**
392         * class: official version of a FilenameFilter
393         */
394        static class DFileFilter implements FilenameFilter {
395    
396            private List<String> extensions = null;
397    
398            /**
399             * 
400             */
401            public DFileFilter() {
402                extensions = new ArrayList<String>();
403                extensions.add( "JPEG" );
404                extensions.add( "JPG" );
405                extensions.add( "BMP" );
406                extensions.add( "PNG" );
407                extensions.add( "GIF" );
408                extensions.add( "TIF" );
409                extensions.add( "TIFF" );
410                extensions.add( "GEOTIFF" );
411            }
412    
413            /**
414             * @return the String "*.*"
415             */
416            public String getDescription() {
417                return "*.*";
418            }
419    
420            /*
421             * (non-Javadoc)
422             * 
423             * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
424             */
425            public boolean accept( java.io.File file, String name ) {
426                int pos = name.lastIndexOf( "." );
427                String ext = name.substring( pos + 1 ).toUpperCase();
428                if ( file.isDirectory() ) {
429                    String s = file.getAbsolutePath() + '/' + name;
430                    File tmp = new File( s );
431                    if ( tmp.isDirectory() ) {
432                        return true;
433                    }
434                }
435                return extensions.contains( ext );
436            }
437        }
438    }