//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/io/geotiff/GeoTiffWriter.java,v 1.11 2006/08/06 20:56:50 poth Exp $
/*---------------- 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
Aennchenstr. 19
53115 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.io.geotiff;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import org.deegree.model.crs.CoordinateSystem;
import org.deegree.model.spatialschema.Envelope;
import com.sun.media.jai.codec.TIFFEncodeParam;
import com.sun.media.jai.codec.TIFFField;
import com.sun.media.jai.codecimpl.TIFFImageEncoder;
/**
* This class is for writing GeoTIFF files from any java.awt.image. At that
* time, only writing the Bounding Box is available.
*
*
* @author <a href="mailto:schaefer@lat-lon.de">Axel Schaefer </A>
* @author last edited by: $Author: poth $
* @version 2.0. $Revision: 1.11 $, $Date: 2006/08/06 20:56:50 $
* @since 2.0
*/
public class GeoTiffWriter {
private ArrayList tiffields = null;
private HashMap geoKeyDirectoryTag = null;
private BufferedImage bi = null;
/**
* private constructor. called from any other public constructor
*/
private GeoTiffWriter(Envelope envelope, double resx, double resy, CoordinateSystem crs) {
this.tiffields = new ArrayList();
this.geoKeyDirectoryTag = new HashMap();
int[] header = { 1, 2, 0 };
// sets the header. this key must be overwritten in the write-method.
addKeyToGeoKeyDirectoryTag(1, header);
// sets the boundingbox (with envelope and resolution)
setBoxInGeoTIFF(envelope, resx, resy);
// sets the CoordinateSystem
// TODO
//setCoordinateSystem(crs);
}
/**
* creates an GeoTiffWriter instance from an java.awt.image.
*
*
* @param image
* the image, to be transformed to a GeoTIFF.
* @param envelope
* the BoundingBox, the GeoTIFF should have
* @param resx
* The X-Resolution
* @param resy
* The Y-Resolution
*/
public GeoTiffWriter(BufferedImage image, Envelope envelope,
double resx, double resy, CoordinateSystem crs) {
this(envelope, resx, resy, crs);
this.bi = image;
}
/**
* creates an GeoTiffWriter instance. TODO
*
* @param img
* @param envelope
* @param resx
* @param resy
*/
public GeoTiffWriter(byte[][] img, Envelope envelope, double resx,
double resy, CoordinateSystem crs) {
// TODO constructor byte[][]
this(envelope, resx, resy, crs);
}
/**
* creates an GeoTiffWriter instance. TODO
*
* @param img
* @param envelope
* @param resx
* @param resy
*/
public GeoTiffWriter(short[][] img, Envelope envelope, double resx,
double resy, CoordinateSystem crs) {
this(envelope, resx, resy, crs);
}
/**
* creates an GeoTiffWriter instance. TODO
*
* @param img
* @param envelope
* @param resx
* @param resy
*/
public GeoTiffWriter(float[][] img, Envelope envelope, double resx,
double resy, CoordinateSystem crs) {
// TODO constructor float[][]
this(envelope, resx, resy, crs);
}
/**
* returns the GeoKeys as an array of Tiff Fields.
*
* @return an array of TIFFFields
*/
private TIFFField[] getGeoTags() {
TIFFField[] extraFields = null;
if (this.tiffields != null && this.tiffields.size() > 0) {
extraFields = new TIFFField[this.tiffields.size()];
for (int i = 0; i < extraFields.length; i++) {
extraFields[i] = (TIFFField) this.tiffields.get(i);
}
}
return extraFields;
}
/**
* gets the GeoKeyDirectoryTag as a chararrary.
*
* @return
*/
private char[] getGeoKeyDirectoryTag() {
char[] ch = null;
// check, if it contains more fields than the header
if (this.geoKeyDirectoryTag.size() > 1) {
ch = new char[this.geoKeyDirectoryTag.size() * 4];
Set set = this.geoKeyDirectoryTag.keySet();
Object[] o = set.toArray();
Integer keyID = null;
int[] temparray = new int[3];
// o.length is equals this.geoKeyDirectoryTag.size()
for (int i = 0; i < o.length; i++) {
// get the key-ID from the ObjectArray 'o'
keyID = (Integer) o[i];
// get the values of the HashMap (int[]) at the key keyID
temparray = (int[]) this.geoKeyDirectoryTag.get(keyID);
ch[i * 4] = (char) keyID.intValue();
ch[i * 4 + 1] = (char) temparray[0];
ch[i * 4 + 2] = (char) temparray[1];
ch[i * 4 + 3] = (char) temparray[2];
}
}
return ch;
}
/**
*
* @param key
* @param values
*/
private void addKeyToGeoKeyDirectoryTag(int key, int[] values) {
this.geoKeyDirectoryTag.put(new Integer(key), values);
}
/**
* Writes the GeoTIFF as a BufferedImage to an OutputStream. The
* OutputStream isn't closed after the method.
*
* @param os
* the output stream, which has to be written.
* @throws IOException
*/
public void write(OutputStream os) throws IOException {
if (this.geoKeyDirectoryTag.size() > 1) {
// overwriter header with *real* size of GeoKeyDirectoryTag
int[] header = { 1, 2, this.geoKeyDirectoryTag.size() - 1 };
addKeyToGeoKeyDirectoryTag(1, header);
char[] ch = getGeoKeyDirectoryTag();
// int tag, int type, int count, java.lang.Object data
TIFFField geokeydirectorytag =
new TIFFField( GeoTiffTag.GeoKeyDirectoryTag, TIFFField.TIFF_SHORT, ch.length, ch);
this.tiffields.add( geokeydirectorytag );
}
// get the geokeys
TIFFField[] tiffields_array = getGeoTags();
TIFFEncodeParam encodeParam = new TIFFEncodeParam();
if (tiffields_array != null && tiffields_array.length > 0) {
encodeParam.setExtraFields(tiffields_array);
}
TIFFImageEncoder encoder = new TIFFImageEncoder(os, encodeParam);
// void encoder( java.awt.image.RenderedImage im )
encoder.encode(bi);
}
// ************************************************************************
// BoundingBox
// ************************************************************************
/**
* description: Extracts the GeoKeys of the GeoTIFF. The Following Tags will
* be extracted(http://www.remotesensing.org/geotiff/spec/geotiffhome.html):
* <ul>
* <li>ModelPixelScaleTag = 33550 (SoftDesk)
* <li>ModelTiepointTag = 33922 (Intergraph)
* </ul>
* implementation status: working
*/
private void setBoxInGeoTIFF(Envelope envelope, double resx, double resy) {
double[] resolution = { resx, resy, 0.0 };
// ModelPixelScaleTag:
// Tag = 33550
// Type = DOUBLE (IEEE Double precision)
// N = 3
// Owner: SoftDesk
TIFFField modelPixelScaleTag =
new TIFFField( GeoTiffTag.ModelPixelScaleTag, TIFFField.TIFF_DOUBLE, 3, resolution);
this.tiffields.add(modelPixelScaleTag);
// ModelTiepointTag:
// calculate the first points for the upper-left corner {0,0,0} of the
// tiff
double tp_01x = 0.0; // (0, val1)
double tp_01y = 0.0; // (1, val2)
double tp_01z = 0.0; // (2) z-value. not needed
// the real-world coordinates for the upper points (tp_01.)
// these are the unknown variables which have to be calculated.
double tp_02x = 0.0; // (3, val4)
double tp_02y = 0.0; // (4, val5)
double tp_02z = 0.0; // (5) z-value. not needed
double xmin = envelope.getMin().getX();
double ymax = envelope.getMax().getY();
// transform this equation: xmin = ?[val4] - ( tp_01x * resx )
tp_02x = xmin + (tp_01x * resx);
// transform this equation: ymax = ?[val5] + ( tp_01y * resy )
tp_02y = ymax + (tp_01y * resy);
double[] tiepoint = { tp_01x, tp_01y, tp_01z, tp_02x, tp_02y, tp_02z };
// ModelTiepointTag:
// Tag = 33922 (8482.H)
// Type = DOUBLE (IEEE Double precision)
// N = 6*K, K = number of tiepoints
// Alias: GeoreferenceTag
// Owner: Intergraph
TIFFField modelTiepointTag =
new TIFFField(GeoTiffTag.ModelTiepointTag, TIFFField.TIFF_DOUBLE, 6, tiepoint);
this.tiffields.add(modelTiepointTag);
}
// ************************************************************************
// CoordinateSystem
// ************************************************************************
/**
*
*/
private void setCoordinateSystem(CoordinateSystem crs) throws GeoTiffException {
/*
// add GTModelTypeGeoKey
int[] values_GTModelTypeGeoKey = { 0, 1, 2 };
addKeyToGeoKeyDirectoryTag(GeoTiffKey.GTModelTypeGeoKey,
values_GTModelTypeGeoKey);
try {
String horizontalDatum = crs.getHorizontalDatum().getName();
if ( Geographic_CS_Codes.contains_Geodectic_Datum_Code(horizontalDatum ) ) {
int[] geographictypegeokey = { 0, 1,
Geographic_CS_Codes.getGeogrpahicCSTypeCode(horizontalDatum) };
addKeyToGeoKeyDirectoryTag(GeoTiffKey.GeographicTypeGeoKey,
geographictypegeokey);
} else {
throw new GeoTiffException( "Error in determining Horizontal Datum Name:\n"
+ ' ' + horizontalDatum
+ " ist not registered in Geodetic Datum Codes.");
}
} catch (Exception e) {
throw new GeoTiffException("RemoteException: " + e.getMessage());
}
*/
}
}
/*
* ****************************************************************************
* Changes to this class. What the people have been up to:
*
* $Log: GeoTiffWriter.java,v $
* Revision 1.11 2006/08/06 20:56:50 poth
* TODO set
*
* Revision 1.10 2006/07/26 10:25:58 poth
* never thrown exceptions removed
*
* Revision 1.9 2006/05/01 20:15:27 poth
* *** empty log message ***
*
* Revision 1.8 2006/04/06 20:25:29 poth
* *** empty log message ***
*
* Revision 1.7 2006/04/04 20:39:43 poth
* *** empty log message ***
*
* Revision 1.6 2006/03/30 21:20:27 poth
* *** empty log message ***
*
* Revision 1.5 2006/03/05 17:41:07 poth
* *** empty log message ***
*
* Revision 1.4 2006/01/25 10:39:39 poth
* *** empty log message ***
*
* Revision 1.3 2005/12/06 13:45:20 poth
* System.out.println substituted by logging api
*
* Revision 1.2 2005/01/18 22:08:54 poth
* no message
*
* Revision 1.2 2004/07/20 15:34:30 ap
* no message
*
* Revision 1.6 2004/07/16 08:48:01 axel_schaefer
* Wrong check of GeoKeyDirectoryTag size.
* Revision 1.5 2004/07/16 07:04:53 poth no message
*
* Revision 1.4 2004/07/15 15:33:43 axel_schaefer no message Revision 1.3
* 2004/07/15 09:57:10 axel_schaefer secure saving at noontime Revision 1.2
* 2004/07/12 08:55:48 poth no message
*
* Revision 1.1 2004/07/08 15:35:22 axel_schaefer first version
*
* ****************************************************************************
*/