001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/geotiff/GeoTiffWriter.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 53115 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 ---------------------------------------------------------------------------*/ 044 045 package org.deegree.io.geotiff; 046 047 import java.awt.image.BufferedImage; 048 import java.io.IOException; 049 import java.io.OutputStream; 050 import java.util.ArrayList; 051 import java.util.HashMap; 052 import java.util.List; 053 import java.util.Set; 054 055 import org.deegree.model.crs.CoordinateSystem; 056 import org.deegree.model.spatialschema.Envelope; 057 058 import com.sun.media.jai.codec.TIFFEncodeParam; 059 import com.sun.media.jai.codec.TIFFField; 060 import com.sun.media.jai.codecimpl.TIFFImageEncoder; 061 062 /** 063 * This class is for writing GeoTIFF files from any java.awt.image. At that time, only writing the 064 * Bounding Box is available. 065 * 066 * 067 * @author <a href="mailto:schaefer@lat-lon.de">Axel Schaefer </A> 068 * @author last edited by: $Author: apoth $ 069 * @version 2.0. $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $ 070 * @since 2.0 071 */ 072 public class GeoTiffWriter { 073 074 private List<TIFFField> tiffields = null; 075 076 private HashMap<Integer, int[]> geoKeyDirectoryTag = null; 077 078 private BufferedImage bi = null; 079 080 private double offset = 0; 081 082 private double scaleFactor = 1; 083 084 /** 085 * creates an GeoTiffWriter instance from an java.awt.image. 086 * 087 * @param image 088 * the image, to be transformed to a GeoTIFF. 089 * @param envelope 090 * the BoundingBox, the GeoTIFF should have 091 * @param resx 092 * The X-Resolution 093 * @param resy 094 * The Y-Resolution 095 * @param crs 096 */ 097 public GeoTiffWriter( BufferedImage image, Envelope envelope, double resx, double resy, 098 CoordinateSystem crs) { 099 this( image, envelope, resx, resy, crs, 0, 1 ); 100 } 101 102 /** 103 * creates an GeoTiffWriter instance from an java.awt.image. 104 * 105 * @param image 106 * the image, to be transformed to a GeoTIFF. 107 * @param envelope 108 * the BoundingBox, the GeoTIFF should have 109 * @param resx 110 * The X-Resolution 111 * @param resy 112 * The Y-Resolution 113 * @param crs 114 * @param offset 115 * @param scaleFactor 116 */ 117 public GeoTiffWriter( BufferedImage image, Envelope envelope, double resx, double resy, CoordinateSystem crs, 118 double offset, double scaleFactor ) { 119 this.tiffields = new ArrayList<TIFFField>(); 120 this.geoKeyDirectoryTag = new HashMap<Integer, int[]>(); 121 int[] header = { 1, 2, 0 }; 122 this.bi = image; 123 this.offset = offset; 124 this.scaleFactor = scaleFactor; 125 // sets the header. this key must be overwritten in the write-method. 126 addKeyToGeoKeyDirectoryTag( 1, header ); 127 // sets the boundingbox (with envelope and resolution) 128 setBoxInGeoTIFF( envelope, resx, resy ); 129 // sets the CoordinateSystem 130 // TODO 131 setCoordinateSystem( crs ); 132 } 133 134 /** 135 * returns the GeoKeys as an array of Tiff Fields. 136 * 137 * @return an array of TIFFFields 138 */ 139 private TIFFField[] getGeoTags() { 140 TIFFField[] extraFields = null; 141 142 if ( this.tiffields != null && this.tiffields.size() > 0 ) { 143 extraFields = new TIFFField[this.tiffields.size()]; 144 for ( int i = 0; i < extraFields.length; i++ ) { 145 extraFields[i] = this.tiffields.get( i ); 146 } 147 } 148 return extraFields; 149 } 150 151 /** 152 * gets the GeoKeyDirectoryTag as a chararrary. 153 * 154 * @return the GeoKeyDirectoryTag as a chararrary 155 */ 156 private char[] getGeoKeyDirectoryTag() { 157 char[] ch = null; 158 159 // check, if it contains more fields than the header 160 if ( this.geoKeyDirectoryTag.size() > 1 ) { 161 ch = new char[this.geoKeyDirectoryTag.size() * 4]; 162 Set set = this.geoKeyDirectoryTag.keySet(); 163 Object[] o = set.toArray(); 164 165 Integer keyID = null; 166 int[] temparray = new int[3]; 167 168 // o.length is equals this.geoKeyDirectoryTag.size() 169 for ( int i = 0; i < o.length; i++ ) { 170 // get the key-ID from the ObjectArray 'o' 171 keyID = (Integer) o[i]; 172 // get the values of the HashMap (int[]) at the key keyID 173 temparray = this.geoKeyDirectoryTag.get( keyID ); 174 ch[i * 4] = (char) keyID.intValue(); 175 ch[i * 4 + 1] = (char) temparray[0]; 176 ch[i * 4 + 2] = (char) temparray[1]; 177 ch[i * 4 + 3] = (char) temparray[2]; 178 } 179 } 180 181 return ch; 182 } 183 184 /** 185 * 186 * @param key 187 * @param values 188 */ 189 private void addKeyToGeoKeyDirectoryTag( int key, int[] values ) { 190 this.geoKeyDirectoryTag.put( new Integer( key ), values ); 191 } 192 193 /** 194 * Writes the GeoTIFF as a BufferedImage to an OutputStream. The OutputStream isn't closed after 195 * the method. 196 * 197 * @param os 198 * the output stream, which has to be written. 199 * @throws IOException 200 */ 201 public void write( OutputStream os ) 202 throws IOException { 203 if ( this.geoKeyDirectoryTag.size() > 1 ) { 204 // overwrite header with *real* size of GeoKeyDirectoryTag 205 int[] header = { 1, 2, this.geoKeyDirectoryTag.size() - 1 }; 206 addKeyToGeoKeyDirectoryTag( 1, header ); 207 208 char[] ch = getGeoKeyDirectoryTag(); 209 210 // int tag, int type, int count, java.lang.Object data 211 TIFFField geokeydirectorytag = new TIFFField( GeoTiffTag.GeoKeyDirectoryTag, TIFFField.TIFF_SHORT, 212 ch.length, ch ); 213 this.tiffields.add( geokeydirectorytag ); 214 } 215 216 // get the geokeys 217 TIFFField[] tiffields_array = getGeoTags(); 218 219 TIFFEncodeParam encodeParam = new TIFFEncodeParam(); 220 if ( tiffields_array != null && tiffields_array.length > 0 ) { 221 encodeParam.setExtraFields( tiffields_array ); 222 } 223 TIFFImageEncoder encoder = new TIFFImageEncoder( os, encodeParam ); 224 225 // void encoder( java.awt.image.RenderedImage im ) 226 encoder.encode( bi ); 227 } 228 229 // ************************************************************************ 230 // BoundingBox 231 // ************************************************************************ 232 /** 233 * description: Extracts the GeoKeys of the GeoTIFF. The Following Tags will be 234 * extracted(http://www.remotesensing.org/geotiff/spec/geotiffhome.html): 235 * <ul> 236 * <li>ModelPixelScaleTag = 33550 (SoftDesk) 237 * <li>ModelTiepointTag = 33922 (Intergraph) 238 * </ul> 239 * implementation status: working 240 */ 241 private void setBoxInGeoTIFF( Envelope envelope, double resx, double resy ) { 242 243 double[] resolution = { resx, resy, 1d/scaleFactor }; 244 // ModelPixelScaleTag: 245 // Tag = 33550 246 // Type = DOUBLE (IEEE Double precision) 247 // N = 3 248 // Owner: SoftDesk 249 TIFFField modelPixelScaleTag = new TIFFField( GeoTiffTag.ModelPixelScaleTag, 250 TIFFField.TIFF_DOUBLE, 3, 251 resolution ); 252 253 this.tiffields.add( modelPixelScaleTag ); 254 255 // ModelTiepointTag: 256 // calculate the first points for the upper-left corner {0,0,0} of the 257 // tiff 258 double tp_01x = 0.0; // (0, val1) 259 double tp_01y = 0.0; // (1, val2) 260 double tp_01z = 0.0; // (2) z-value. not needed 261 262 // the real-world coordinates for the upper points (tp_01.) 263 // these are the unknown variables which have to be calculated. 264 double tp_02x = 0.0; // (3, val4) 265 double tp_02y = 0.0; // (4, val5) 266 double tp_02z = -offset; // (5) z-value. not needed 267 268 double xmin = envelope.getMin().getX(); 269 double ymax = envelope.getMax().getY(); 270 271 // transform this equation: xmin = ?[val4] - ( tp_01x * resx ) 272 tp_02x = xmin + ( tp_01x * resx ); 273 274 // transform this equation: ymax = ?[val5] + ( tp_01y * resy ) 275 tp_02y = ymax + ( tp_01y * resy ); 276 277 double[] tiepoint = { tp_01x, tp_01y, tp_01z, tp_02x, tp_02y, tp_02z }; 278 279 // ModelTiepointTag: 280 // Tag = 33922 (8482.H) 281 // Type = DOUBLE (IEEE Double precision) 282 // N = 6*K, K = number of tiepoints 283 // Alias: GeoreferenceTag 284 // Owner: Intergraph 285 TIFFField modelTiepointTag = new TIFFField( GeoTiffTag.ModelTiepointTag, TIFFField.TIFF_DOUBLE, 6, tiepoint ); 286 287 this.tiffields.add( modelTiepointTag ); 288 } 289 290 // ************************************************************************ 291 // CoordinateSystem 292 // ************************************************************************ 293 /** 294 * 295 */ 296 private void setCoordinateSystem( CoordinateSystem crs ) { 297 /* 298 * // add GTModelTypeGeoKey int[] values_GTModelTypeGeoKey = { 0, 1, 2 }; 299 * addKeyToGeoKeyDirectoryTag(GeoTiffKey.GTModelTypeGeoKey, values_GTModelTypeGeoKey); 300 * 301 * try { String horizontalDatum = crs.getHorizontalDatum().getName(); 302 * 303 * if ( Geographic_CS_Codes.contains_Geodectic_Datum_Code(horizontalDatum ) ) { 304 * 305 * int[] geographictypegeokey = { 0, 1, 306 * Geographic_CS_Codes.getGeogrpahicCSTypeCode(horizontalDatum) }; 307 * addKeyToGeoKeyDirectoryTag(GeoTiffKey.GeographicTypeGeoKey, geographictypegeokey); } else { 308 * throw new GeoTiffException( "Error in determining Horizontal Datum Name:\n" + ' ' + 309 * horizontalDatum + " ist not registered in Geodetic Datum Codes."); } } catch (Exception 310 * e) { throw new GeoTiffException("RemoteException: " + e.getMessage()); } 311 */ 312 313 } 314 315 }