//$Header$
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstraße 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.tools.raster;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BandedSampleModel;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferShort;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.StringTools;
import org.deegree.graphics.Encoders;
import org.deegree.graphics.transformation.GeoTransform;
import org.deegree.graphics.transformation.WorldToScreenTransform;
import org.deegree.io.geotiff.GeoTiffKey;
import org.deegree.io.geotiff.GeoTiffTag;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.GeometryFactory;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.TIFFDirectory;
import com.sun.media.jai.codec.TIFFField;
/**
* This class represents a <code>MergeRaster</code> object.
* TODO more info
*
* @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
* @author last edited by: $Author$
*
* @version 2.0, $Revision$, $Date$
*
* @since 2.0
*
* @deprecated use @see org.deegree.tools.raster.RasterTreeBuilder instead; this class
* will be removed from deegree at the end of 2007
*/
public class MergeRaster {
private static final ILogger LOG = LoggerFactory.getLogger( MergeRaster.class );
private Integer bitDepth = null;
private boolean geoTiff = false;
// input for new MergeRaste object
private List imageFiles;
private String outputDir;
private String baseName;
private String outputFormat;
private double maxTileSize;
// resoultion of current input image
private double resx = 0;
private double resy = 0;
// bounding box of current input image
private Envelope envelope;
// minimum resolution of input images
private double minimumRes;
// combining image bounding box
private Envelope combiningEnvelope;
// virtual bounding box
private Envelope virtualEnvelope;
// size of virtual bounding box in px
private long pxWidthVirtualBBox;
private long pxHeightVirtualBBox;
// size of every tile in virtual bounding box in px
private long pxWidthTile;
private long pxHeightTile;
// number of tiles in virtual bounding box
private int tileRows;
private int tileCols;
/**
* TODO write comment
*
* @param imageFiles
* @param outputDir
* @param baseName
* @param outputFormat
* @param maxTileSize
* @throws Exception
*/
public MergeRaster( List imageFiles, String outputDir, String baseName, String outputFormat,
double maxTileSize, Envelope bbox, double resolution )
throws Exception {
this.imageFiles = imageFiles;
this.outputDir = outputDir;
this.baseName = baseName;
this.outputFormat = outputFormat.toLowerCase();
this.maxTileSize = maxTileSize;
combiningEnvelope = bbox;
minimumRes = resolution;
determineCombiningBBox();
determineVirtualBBox();
determineTileSize();
createTiles( tileRows, tileCols );
}
/**
* Gets the latitude and longitude coordinates (xmin, ymin, xmax and ymax) of the image.
*/
private void readWorldFile( String filename, BufferedImage image ) throws Exception {
try {
// Gets the substring beginning at the specified beginIndex (0) - the beginning index,
// inclusive - and extends to the character at index endIndex (position of '.') - the
// ending index, exclusive.
String fname = null;
int pos = filename.lastIndexOf( "." );
filename = filename.substring( 0, pos );
// Look for corresponding worldfiles.
if ( ( new File( filename + ".tfw" ) ).exists() ) {
fname = filename + ".tfw";
} else if ( ( new File( filename + ".wld" ) ).exists() ) {
fname = filename + ".wld";
} else if ( ( new File( filename + ".jgw" ) ).exists() ) {
fname = filename + ".jgw";
} else if ( ( new File( filename + ".jpgw" ) ).exists() ) {
fname = filename + ".jpgw";
} else if ( ( new File( filename + ".gfw" ) ).exists() ) {
fname = filename + ".gfw";
} else if ( ( new File( filename + ".gifw" ) ).exists() ) {
fname = filename + ".gifw";
} else if ( ( new File( filename + ".pgw" ) ).exists() ) {
fname = filename + ".pgw";
} else if ( ( new File( filename + ".pngw" ) ).exists() ) {
fname = filename + ".pngw";
} else {
throw new Exception( "Not a world file for: " + filename );
}
// Reads character files.
// The constructors of this class (FileReader) assume that the default character
// encoding and the default byte-buffer size are appropriate.
// The BufferedReader reads text from a character-input stream, buffering characters
// so as to provide for the efficient reading of characters.
BufferedReader br = new BufferedReader( new FileReader( fname ) );
String s = null;
int cnt = 0;
double d1 = 0;
double d2 = 0;
double d3 = 0;
double d4 = 0;
while ( ( s = br.readLine() ) != null ) {
cnt++;
s = s.trim();
switch (cnt) {
case 1:
// r�uml. aufl�sung in x richtung (size of 1 pixel in degree or meter)
d1 = Double.parseDouble( s.replace( ',', '.' ) );
break;
case 4:
// r�uml. aufl�sung in y richtung (size of 1 pixel in degree or meter)
d2 = Double.parseDouble( s.replace( ',', '.' ) );
break;
case 5:
// x - Ecke oben links ( = x-min )
d3 = Double.parseDouble( s.replace( ',', '.' ) );
break;
case 6:
// y - Ecke oben links ( = y-max )
d4 = Double.parseDouble( s.replace( ',', '.' ) );
break;
}
}
br.close();
double d5 = d3 + ( image.getWidth() * d1 );
double d6 = d4 + ( image.getHeight() * d2 );
double ymax = d4;
double ymin = d6;
double xmax = d5;
double xmin = d3;
resx = ( xmax - xmin ) / image.getWidth();
resy = ( ymax - ymin ) / image.getHeight();
envelope = GeometryFactory.createEnvelope( xmin, ymin, xmax, ymax, null );
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* TODO this is a copy from org.deegree.tools.raster#AutoTiler
*
* Extracts the GeoKeys of the GeoTIFF. The Following Tags will be extracted
* (http://www.remotesensing.org/geotiff/spec/geotiffhome.html):
* ModelPixelScaleTag = 33550 (SoftDesk)
* ModelTiepointTag = 33922 (Intergraph)
* implementation status: working
*/
private void readBBoxFromGeoTIFF( RenderedOp rop ) throws Exception {
TIFFDirectory tifDir = (TIFFDirectory) rop.getDynamicProperty( "tiff_directory" );
TIFFField modelPixelScaleTag = tifDir.getField( GeoTiffTag.ModelPixelScaleTag );
resx = modelPixelScaleTag.getAsDouble( 0 );
resy = modelPixelScaleTag.getAsDouble( 1 );
TIFFField modelTiepointTag = tifDir.getField( GeoTiffTag.ModelTiepointTag );
double val1 = 0.0;
val1 = modelTiepointTag.getAsDouble( 0 );
double val2 = 0.0;
val2 = modelTiepointTag.getAsDouble( 1 );
double val4 = 0.0;
val4 = modelTiepointTag.getAsDouble( 3 );
double val5 = 0.0;
val5 = modelTiepointTag.getAsDouble( 4 );
if ( ( resx == 0.0 || resy == 0.0 ) ||
( val1 == 0.0 && val2 == 0.0 && val4 == 0.0 && val5 == 0.0 ) ) {
throw new Exception( "The image/coverage has no bounding box." );
// set the geoparams derived by geoTiffTags
} else {
// upper/left pixel
double xOrigin = val4 - ( val1 * resx );
double yOrigin = val5 - ( val2 * resy );
// lower/right pixel
double xRight = xOrigin + rop.getWidth() * resx;
double yBottom = yOrigin - rop.getHeight() * resy;
envelope = GeometryFactory.createEnvelope( xOrigin, yBottom, xRight, yOrigin, null );
}
}
/**
* TODO this is a copy from org.deegree.tools.raster#AutoTiler
*
* the following TIFFKeys count as indicator if a TIFF-File carries GeoTIFF information:
* ModelPixelScaleTag = 33550 (SoftDesk)
* ModelTransformationTag = 34264 (JPL Carto Group)
* ModelTiepointTag = 33922 (Intergraph)
* GeoKeyDirectoryTag = 34735 (SPOT)
* GeoDoubleParamsTag = 34736 (SPOT)
* GeoAsciiParamsTag = 34737 (SPOT)
* implementation status: working
*/
private boolean isGeoTIFFFormat( RenderedOp rop ) {
TIFFDirectory tifDir = (TIFFDirectory) rop.getDynamicProperty( "tiff_directory" );
// definition of a geotiff
if ( tifDir.getField( GeoTiffTag.ModelPixelScaleTag ) == null
&& tifDir.getField( GeoTiffTag.ModelTransformationTag ) == null
&& tifDir.getField( GeoTiffTag.ModelTiepointTag ) == null
&& tifDir.getField( GeoTiffTag.GeoKeyDirectoryTag ) == null
&& tifDir.getField( GeoTiffTag.GeoDoubleParamsTag ) == null
&& tifDir.getField( GeoTiffTag.GeoAsciiParamsTag ) == null ) {
return false;
} else {
// is a geotiff and possibly might need to be treated as raw data
TIFFField bitsPerSample = tifDir.getField( GeoTiffTag.BitsPerSample );
if ( bitsPerSample != null ) {
int samples = bitsPerSample.getAsInt( 0 );
if ( samples == 16 )
bitDepth = new Integer( 16 );
}
// check the EPSG number
TIFFField ff = tifDir.getField( GeoTiffTag.GeoKeyDirectoryTag );
if ( ff == null ) {
return false;
}
char[] ch = ff.getAsChars();
// resulting HashMap, containing the key and the array of values
HashMap geoKeyDirectoryTag = new HashMap( ff.getCount() / 4 );
// array of values. size is 4-1.
int keydirversion, keyrevision, minorrevision, numberofkeys = -99;
for (int i = 0; i < ch.length; i = i + 4) {
int[] keys = new int[3];
keydirversion = ch[i];
keyrevision = ch[i + 1];
minorrevision = ch[i + 2];
numberofkeys = ch[i + 3];
keys[0] = keyrevision;
keys[1] = minorrevision;
keys[2] = numberofkeys;
geoKeyDirectoryTag.put( new Integer( keydirversion ), keys );
}
int[] content = new int[3];
if ( geoKeyDirectoryTag.containsKey( new Integer( GeoTiffKey.GTModelTypeGeoKey ) ) ) {
content =
(int[]) geoKeyDirectoryTag.get( new Integer( GeoTiffKey.GTModelTypeGeoKey ) );
// TIFFTagLocation
if ( content[0] == 0 ) {
// return Value_Offset
//key = content[2];
} else {
// TODO other TIFFTagLocation that GeoKeyDirectoryTag
}
} else {
System.out.println("Can't check EPSG codes, make sure it is ok!");
}
return true;
}
}
/**
* TODO this is a copy from org.deegree.tools.raster#AutoTiler
*
* loads the base image
*/
private BufferedImage loadImage( String imageSource ) throws Exception {
BufferedImage bi = null;
FileSeekableStream fss = new FileSeekableStream( imageSource );
RenderedOp rop = JAI.create( "stream", fss );
if ( imageSource.toUpperCase().endsWith( ".TIFF" )
|| imageSource.toUpperCase().endsWith( ".TIF" ) ) {
geoTiff = isGeoTIFFFormat( rop );
if ( geoTiff ) {
readBBoxFromGeoTIFF( rop );
if ( ( bitDepth != null ) && ( bitDepth.intValue() == 16 ) ) {
int width = rop.getWidth();
int height = rop.getHeight();
// read data as 'raw' information and not as image
Raster raster = rop.getData( new Rectangle( 0, 0, width, height ) );
// get the data
short[] o = (short[]) raster.getDataElements( 0, 0, width, height, null );
int bands = raster.getNumBands();
short[][] bb = new short[bands][];
for (int i = 0; i < bands; i++) {
bb[i] = new short[raster.getWidth()* raster.getHeight()];
}
int c = 0;
int u = 0;
for (int i = 0; i < raster.getWidth(); i++) {
for (int j = 0; j < raster.getHeight(); j++) {
for (int z = 0; z < bands; z++) {
bb[z][u] = o[c++];
}
u++;
}
}
// create a new image from the data and serialize it to a file
DataBuffer db = new DataBufferShort( bb, width * height );
SampleModel sm =
new BandedSampleModel( DataBuffer.TYPE_SHORT, width, height, bands );
raster = Raster.createWritableRaster( sm, db, null );
// from a theoretical point of view the usage of TYPE_USHORT_GRAY
// doesn't seem to be a very good idea but it works and I didn't find a
// way to create a RenderedImage with type Short
bi = new BufferedImage( width, height, BufferedImage.TYPE_USHORT_GRAY );
bi.setData( raster );
}
}
}
bi = rop.getAsBufferedImage();
fss.close();
return bi;
}
/**
* Determins the necessary size of a bounding box, which is large enough to hold all
* input image files. The result is stored in the combining <code>Envelope</code>.
*
* @throws Exception
*/
private void determineCombiningBBox( ) throws Exception {
System.out.println( "calculating overall bounding box ..." );
if ( imageFiles == null || imageFiles.isEmpty() ) {
throw new Exception( "No combining BoundingBox to be determined: " +
"The list of image files is null or empty." );
}
// upper left corner of combining bounding box
double minX = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
// lower right corner of combining bounding box
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
// minimum resolution within combining bounding box
double minResX = Double.MAX_VALUE;
double minResY = Double.MAX_VALUE;
if ( combiningEnvelope == null ) {
for ( int i = 0; i < imageFiles.size(); i++ ) {
File file = new File( (String)imageFiles.get(i) );
if ( file.exists() && !file.isDirectory()) {
// for faster clean up
System.gc();
BufferedImage bi = loadImage( (String)imageFiles.get(i) );
if ( !geoTiff ) {
try {
readWorldFile( (String)imageFiles.get(i), bi );
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
// now the values of resx, resy, envelope of the current image file are available
// find min for x and y
minX = Math.min( minX, envelope.getMin().getX() );
minY = Math.min( minY, envelope.getMin().getY() );
// find max for x and y
maxX = Math.max( maxX, envelope.getMax().getX() );
maxY = Math.max( maxY, envelope.getMax().getY() );
// find min for resolution of x and y
minResX = Math.min( minResX, resx );
minResY = Math.min( minResY, resy );
} else {
System.out.println( "File: " + imageFiles.get(i) + " does not exist!" );
System.out.println( "Image will be ignored" );
}
}
// store minimum resolution
minimumRes = Math.min( minResX, minResY );
combiningEnvelope = GeometryFactory.createEnvelope( minX, minY, maxX, maxY, null );
}
}
/**
* Determins a usefull size for the virtual bounding box. It is somewhat larger
* than the combining bounding box. The result is stored in the virtual <code>Envelope</code>.
*
*/
private void determineVirtualBBox() {
double width = combiningEnvelope.getWidth();
double height = combiningEnvelope.getHeight();
long pxWidth = (long)Math.round( width / minimumRes );
long pxHeight = (long)Math.round( height / minimumRes );
// set width and height to next higher even-numbered thousand
pxWidth = 2000 * (long)Math.ceil( pxWidth / 2000.0 );
pxHeight = 2000 * (long)Math.ceil( pxHeight / 2000.0 );
pxWidthVirtualBBox = pxWidth;
pxHeightVirtualBBox = pxHeight;
// upper left corner of virtual bounding box
double minX = combiningEnvelope.getMin().getX();
double maxY = combiningEnvelope.getMax().getY();
// lower right corner of virtual bounding box
double maxX = minX + ( pxWidth * minimumRes );
double minY = maxY - ( pxHeight * minimumRes );
virtualEnvelope = GeometryFactory.createEnvelope( minX, minY, maxX, maxY, null );
}
/**
* This method determins and sets the size of the tiles in pixel both horizontally (pxWidthTile)
* and vertically (pxHeightTile).
* It also sets the necessary number of <code>tileCols</code> (depending on the tileWidth)
* and <code>tileRows</code> (depending on the tileHeight).
*
* By default, all tiles have a size of close to but less than 6000 pixel either way.
*/
private void determineTileSize() {
/*
* The size of the virtual bbox gets divided by maxTileSize to find an approximat number of
* tiles (a).
*
* If the virtual bbox is in any direction (horizontally or vertically) smaler than
* maxTileSize px, then it has only 1 tile in that direction. In this case, the size of the tile
* equals the size of the virtual bbox.
*
* Otherwise, use 'tileCols' and 'tileRows' as the next larger integer to 'a' to get the
* minimum number of tiles. Increase this number until the tile size becomes a whole number.
*
* Divide the size of the virtual bbox by the final number of tiles to get its tile size.
*
*/
double a;
int tileCols, tileRows;
// determin width of tile
a = ( pxWidthVirtualBBox / maxTileSize );
tileCols = (int) Math.ceil( a );
if ( a <= 1.0 ) {
pxWidthTile = pxWidthVirtualBBox;
} else {
while ( pxWidthVirtualBBox % tileCols > 0 ) {
tileCols++;
}
pxWidthTile = pxWidthVirtualBBox / tileCols ;
}
// determin height of tile
a = ( pxHeightVirtualBBox / maxTileSize );
tileRows = (int) Math.ceil( a );
if ( a <= 1.0 ) {
pxHeightTile = pxHeightVirtualBBox;
} else {
while ( pxHeightVirtualBBox % tileRows > 0 ) {
tileRows++;
}
pxHeightTile = pxHeightVirtualBBox / tileRows ;
}
this.tileCols = tileCols;
this.tileRows = tileRows;
System.out.println( "minimum resolution: " + minimumRes );
System.out.println( "width = "+ pxWidthVirtualBBox +" *** height = " + pxHeightVirtualBBox );
System.out.println( "pxWidthTile = " + pxWidthTile + " *** pxHeightTile = " + pxHeightTile );
System.out.println( "number of tiles: horizontally = " + tileCols + ", vertically = " + tileRows );
}
/**
* Creates one <code>Tile</code> object after the other, with the number of tiles being
* specified by the given number of <code>rows</code> and <code>cols</code>.
*
* Each Tile gets written to the FileOutputStream by the internal call to #paintImagesOnTile.
*
* @param rows
* @param cols
* @throws Exception
*/
private void createTiles( int rows, int cols ) throws Exception {
Tile tile = null;
double tileWidth = virtualEnvelope.getWidth() / cols; // [�]
double tileHeight = virtualEnvelope.getHeight() / rows; // [�]
double leftX;
double upperY = virtualEnvelope.getMax().getY();
double rightX;
double lowerY;
for ( int i = 0; i < rows; i++ ) {
leftX = virtualEnvelope.getMin().getX();
lowerY = upperY - tileHeight;
for ( int j = 0; j < cols; j++ ) {
System.out.println( "processing tile: " + i + " - " + j);
rightX = leftX + tileWidth;
Envelope env =
GeometryFactory.createEnvelope( leftX, lowerY, rightX, upperY, null );
// System.out.print(" (" + leftX + "," + lowerY + " / " + rightX + "," + upperY + ") ");
leftX = rightX;
String postfix = "_" + i + "_" + j;
tile = new Tile( env, postfix );
paintImagesOnTile( tile );
createWorldFile( tile );
}
// System.out.println();
upperY = lowerY;
}
}
/**
* Paints all image files that intersect with the passed <code>tile</code> onto that tile
* and creates an output file in the <code>outputDir</code>. If no image file intersects with
* the given tile, then an empty output file is created. The name of the output file is defined
* by the <code>baseName</code> and the tile's index of row and column.
*
* @param tile The tile on which to paint the image.
* @throws Exception
*/
private void paintImagesOnTile( Tile tile ) throws Exception {
System.out.println( "creating merged image ...");
Envelope tileEnv = tile.getTileEnvelope();
String postfix = tile.getPostfix();
// for png, tif, tiff use 4 byte:
int type = BufferedImage.TYPE_INT_ARGB;
// for bmp, jpg, jpeg use 3 byte:
if ( ( "jpg" ).equals( outputFormat ) || ( "jpeg" ).equals( outputFormat ) ||
( "bmp" ).equals( outputFormat ) ) {
type = BufferedImage.TYPE_INT_RGB;
}
BufferedImage out = new BufferedImage( (int)pxWidthTile, (int)pxHeightTile, type );;
for ( int i = 0; i < imageFiles.size(); i++ ) {
File file = new File( (String)imageFiles.get(i) );
if ( file.exists() && !file.isDirectory() ) {
// for faster clean up
System.gc();
//System.out.println("processing: " + imageFiles.get(i));
BufferedImage bi = loadImage( (String)imageFiles.get(i) );
if ( !geoTiff ) {
try {
readWorldFile( (String)imageFiles.get(i), bi );
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
// now the values of resx, resy, envelope of the current image file are available
if ( envelope.intersects( tileEnv ) ) {
GeoTransform gt =
new WorldToScreenTransform( tileEnv.getMin().getX(), tileEnv.getMin().getY(),
tileEnv.getMax().getX(), tileEnv.getMax().getY(),
0, 0, out.getWidth()-1, out.getHeight()-1 );
int x1 = (int)Math.round( gt.getDestX( envelope.getMin().getX() ) );
int y1 = (int)Math.round( gt.getDestY( envelope.getMax().getY() ) );
int x2 = (int)Math.round( gt.getDestX( envelope.getMax().getX() ) );
int y2 = (int)Math.round( gt.getDestY( envelope.getMin().getY() ) );
Graphics g = out.getGraphics();
g.drawImage( bi, x1, y1, x2-x1, y2-y1 , null );
g.dispose();
}
try {
String imageFile = outputDir + baseName + postfix + "." + outputFormat;
FileOutputStream fos = new FileOutputStream( imageFile );
if ( "png".equals( outputFormat ) ) {
Encoders.encodePng( fos, out );
} else if ( "bmp".equals( outputFormat ) ) {
Encoders.encodeBmp( fos, out );
} else if ( "tif".equals( outputFormat ) || "tiff".equals( outputFormat ) ) {
Encoders.encodeTiff( fos, out );
} else if ( "jpg".equals( outputFormat ) || "jpeg".equals( outputFormat ) ) {
Encoders.encodeJpeg( fos, out, 1 );
}
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* Creates a world file for the corresponding tile in the <code>outputDir</code>. The name of
* the output file is defined by the <code>baseName</code> and the tile's index of row and
* column.
*
* @param tile The tile for which to create a world file.
* @throws IOException
*/
private void createWorldFile( Tile tile ) throws IOException {
Envelope env = tile.getTileEnvelope();
String postfix = tile.getPostfix();
StringBuffer sb = new StringBuffer( 1000 );
sb.append( resx ).append( "\n" )
.append( 0.0 ).append( "\n" )
.append( 0.0 ).append( "\n" )
.append( (-1)*resy ).append( "\n" )
.append( env.getMin().getX() ).append( "\n" )
.append( env.getMax().getY() ).append( "\n" );
File f = new File( outputDir + baseName + postfix + ".wld" );
FileWriter fw = new FileWriter( f );
PrintWriter pw = new PrintWriter( fw );
pw.print( sb.toString() );
pw.close();
fw.close();
}
/**
* Validates the content of <code>map</code>, to see, if necessary arguments were passed
* when calling this class.
*
* @param map
* @throws Exception
*/
private static void validate( HashMap map ) throws Exception {
if ( map.get( "-mapFiles" ) == null ) {
throw new Exception( "-mapFiles must be set" );
}
if ( map.get( "-outDir" ) == null ) {
throw new Exception( "-outDir must be set" );
}
if ( map.get( "-baseName" ) == null ) {
map.put( "-baseName", "out" );
}
if ( map.get( "-outputFormat" ) == null ) {
map.put( "-outputFormat", "png" );
} else {
String format = ( (String)map.get( "-outputFormat" ) ).toLowerCase();
if ( !( "bmp" ).equals( format ) && !( "png" ).equals( format ) &&
!( "jpg" ).equals( format ) && !( "jpeg" ).equals( format ) &&
!( "tif" ).equals( format ) && !( "tiff" ).equals( format ) ) {
throw new Exception( "-outputFormat must be one of the following: " +
"'bmp', 'jpeg', 'jpg', 'png', 'tif', 'tiff'." );
}
}
if ( map.get( "-maxTileSize" ) == null ) {
map.put( "-maxTileSize", "6000" );
}
}
/**
*
* @param args Example arguments to pass when calling are:
* <ul>
* <li>-mapFiles D:/temp/europe_DK.jpg,D:/temp/europe_BeNeLux.jpg</li>
* <li>-outDir D:/temp/out/</li>
* <li>-baseName pretty</li>
* <li>-outputFormat png</li>
* <li>-maxTileSize 600</li>
* </ul>
*
* @throws Exception
*/
public static void main( String[] args ) throws Exception {
if ( args == null || args.length == 0 ) {
args = new String[] { "-mapFiles", "D:/temp/europe_DK.jpg," +
"D:/temp/europe_GB.jpg,D:/temp/europe_BeNeLux.jpg",
"-outDir", "D:/temp/outdir/", "-baseName", "out",
"-outputFormat", "png", "-maxTileSize", "6000" };
}
HashMap map = new HashMap();
for (int i = 0; i < args.length; i += 2) {
map.put(args[i], args[i + 1]);
}
validate( map );
LOG.logInfo( map.toString() );
String tmp = (String)map.get( "-mapFiles" );
String[] mapFiles = StringTools.toArray( tmp, ",;|", true );
String outDir = (String)map.get( "-outDir" );
String baseName = (String)map.get( "-baseName" );
String outputFormat = (String)map.get( "-outputFormat" );
String bbox = (String)map.get( "-bbox" );
String res = (String)map.get( "-resolution" );
double maxTileSize = ( Double.valueOf( (String)map.get( "-maxTileSize" ) ) ).doubleValue();
List imageFiles = new ArrayList();
for (int i = 0; i < mapFiles.length; i++) {
imageFiles.add(mapFiles[i]);
}
Envelope env = null;
double resolution = 0;
if ( bbox != null ) {
double[] d = StringTools.toArrayDouble( bbox, "," );
env = GeometryFactory.createEnvelope( d[0], d[1], d[2], d[3], null );
resolution = Double.parseDouble( res );
}
new MergeRaster( imageFiles, outDir, baseName, outputFormat, maxTileSize,
env, resolution );
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log$
Revision 1.17 2006/08/29 19:54:14 poth
footer corrected
Revision 1.16 2006/08/24 06:43:54 poth
File header corrected
Revision 1.15 2006/05/25 20:02:39 poth
classes marked as deprecated
Revision 1.14 2006/04/06 20:25:26 poth
*** empty log message ***
Revision 1.13 2006/03/30 21:20:26 poth
*** empty log message ***
Revision 1.12 2006/01/29 20:59:08 poth
*** empty log message ***
Revision 1.11 2006/01/27 15:44:46 poth
*** empty log message ***
Revision 1.10 2006/01/20 19:45:53 poth
*** empty log message ***
Revision 1.9 2006/01/13 08:48:42 poth
*** empty log message ***
Revision 1.8 2006/01/12 15:27:26 mays
create world file for each tile and create empty image files for empty tiles
Revision 1.7 2006/01/09 09:18:39 mays
validate outputFormat
Revision 1.6 2006/01/06 18:06:28 mays
make use of args passed to main method; and minor restructuring
Revision 1.5 2006/01/06 15:18:19 poth
*** empty log message ***
Revision 1.4 2006/01/06 14:24:35 mays
major restructuring because of buffer size problems.
now, images and tiles are only read into buffer, when realy needed.
Revision 1.3 2006/01/06 10:35:53 mays
add methods to create tiles and images; major restructuring and minor cleanup
Revision 1.2 2006/01/05 11:37:55 mays
add methods to create tiles images and tiles bboxes; minor cleanup
Revision 1.1 2006/01/04 17:17:26 mays
first implementation of class - not finished yet
********************************************************************** */