001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/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 04:32:57 -0800 (Thu, 27 Dec 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,
098: double resx, double resy, 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,
118: double resx, double resy, CoordinateSystem crs,
119: double offset, double scaleFactor) {
120: this .tiffields = new ArrayList<TIFFField>();
121: this .geoKeyDirectoryTag = new HashMap<Integer, int[]>();
122: int[] header = { 1, 2, 0 };
123: this .bi = image;
124: this .offset = offset;
125: this .scaleFactor = scaleFactor;
126: // sets the header. this key must be overwritten in the write-method.
127: addKeyToGeoKeyDirectoryTag(1, header);
128: // sets the boundingbox (with envelope and resolution)
129: setBoxInGeoTIFF(envelope, resx, resy);
130: // sets the CoordinateSystem
131: // TODO
132: setCoordinateSystem(crs);
133: }
134:
135: /**
136: * returns the GeoKeys as an array of Tiff Fields.
137: *
138: * @return an array of TIFFFields
139: */
140: private TIFFField[] getGeoTags() {
141: TIFFField[] extraFields = null;
142:
143: if (this .tiffields != null && this .tiffields.size() > 0) {
144: extraFields = new TIFFField[this .tiffields.size()];
145: for (int i = 0; i < extraFields.length; i++) {
146: extraFields[i] = this .tiffields.get(i);
147: }
148: }
149: return extraFields;
150: }
151:
152: /**
153: * gets the GeoKeyDirectoryTag as a chararrary.
154: *
155: * @return the GeoKeyDirectoryTag as a chararrary
156: */
157: private char[] getGeoKeyDirectoryTag() {
158: char[] ch = null;
159:
160: // check, if it contains more fields than the header
161: if (this .geoKeyDirectoryTag.size() > 1) {
162: ch = new char[this .geoKeyDirectoryTag.size() * 4];
163: Set set = this .geoKeyDirectoryTag.keySet();
164: Object[] o = set.toArray();
165:
166: Integer keyID = null;
167: int[] temparray = new int[3];
168:
169: // o.length is equals this.geoKeyDirectoryTag.size()
170: for (int i = 0; i < o.length; i++) {
171: // get the key-ID from the ObjectArray 'o'
172: keyID = (Integer) o[i];
173: // get the values of the HashMap (int[]) at the key keyID
174: temparray = this .geoKeyDirectoryTag.get(keyID);
175: ch[i * 4] = (char) keyID.intValue();
176: ch[i * 4 + 1] = (char) temparray[0];
177: ch[i * 4 + 2] = (char) temparray[1];
178: ch[i * 4 + 3] = (char) temparray[2];
179: }
180: }
181:
182: return ch;
183: }
184:
185: /**
186: *
187: * @param key
188: * @param values
189: */
190: private void addKeyToGeoKeyDirectoryTag(int key, int[] values) {
191: this .geoKeyDirectoryTag.put(new Integer(key), values);
192: }
193:
194: /**
195: * Writes the GeoTIFF as a BufferedImage to an OutputStream. The OutputStream isn't closed after
196: * the method.
197: *
198: * @param os
199: * the output stream, which has to be written.
200: * @throws IOException
201: */
202: public void write(OutputStream os) 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(
212: GeoTiffTag.GeoKeyDirectoryTag,
213: TIFFField.TIFF_SHORT, ch.length, ch);
214: this .tiffields.add(geokeydirectorytag);
215: }
216:
217: // get the geokeys
218: TIFFField[] tiffields_array = getGeoTags();
219:
220: TIFFEncodeParam encodeParam = new TIFFEncodeParam();
221: if (tiffields_array != null && tiffields_array.length > 0) {
222: encodeParam.setExtraFields(tiffields_array);
223: }
224: TIFFImageEncoder encoder = new TIFFImageEncoder(os, encodeParam);
225:
226: // void encoder( java.awt.image.RenderedImage im )
227: encoder.encode(bi);
228: }
229:
230: // ************************************************************************
231: // BoundingBox
232: // ************************************************************************
233: /**
234: * description: Extracts the GeoKeys of the GeoTIFF. The Following Tags will be
235: * extracted(http://www.remotesensing.org/geotiff/spec/geotiffhome.html):
236: * <ul>
237: * <li>ModelPixelScaleTag = 33550 (SoftDesk)
238: * <li>ModelTiepointTag = 33922 (Intergraph)
239: * </ul>
240: * implementation status: working
241: */
242: private void setBoxInGeoTIFF(Envelope envelope, double resx,
243: double resy) {
244:
245: double[] resolution = { resx, resy, 1d / scaleFactor };
246: // ModelPixelScaleTag:
247: // Tag = 33550
248: // Type = DOUBLE (IEEE Double precision)
249: // N = 3
250: // Owner: SoftDesk
251: TIFFField modelPixelScaleTag = new TIFFField(
252: GeoTiffTag.ModelPixelScaleTag, TIFFField.TIFF_DOUBLE,
253: 3, resolution);
254:
255: this .tiffields.add(modelPixelScaleTag);
256:
257: // ModelTiepointTag:
258: // calculate the first points for the upper-left corner {0,0,0} of the
259: // tiff
260: double tp_01x = 0.0; // (0, val1)
261: double tp_01y = 0.0; // (1, val2)
262: double tp_01z = 0.0; // (2) z-value. not needed
263:
264: // the real-world coordinates for the upper points (tp_01.)
265: // these are the unknown variables which have to be calculated.
266: double tp_02x = 0.0; // (3, val4)
267: double tp_02y = 0.0; // (4, val5)
268: double tp_02z = -offset; // (5) z-value. not needed
269:
270: double xmin = envelope.getMin().getX();
271: double ymax = envelope.getMax().getY();
272:
273: // transform this equation: xmin = ?[val4] - ( tp_01x * resx )
274: tp_02x = xmin + (tp_01x * resx);
275:
276: // transform this equation: ymax = ?[val5] + ( tp_01y * resy )
277: tp_02y = ymax + (tp_01y * resy);
278:
279: double[] tiepoint = { tp_01x, tp_01y, tp_01z, tp_02x, tp_02y,
280: tp_02z };
281:
282: // ModelTiepointTag:
283: // Tag = 33922 (8482.H)
284: // Type = DOUBLE (IEEE Double precision)
285: // N = 6*K, K = number of tiepoints
286: // Alias: GeoreferenceTag
287: // Owner: Intergraph
288: TIFFField modelTiepointTag = new TIFFField(
289: GeoTiffTag.ModelTiepointTag, TIFFField.TIFF_DOUBLE, 6,
290: tiepoint);
291:
292: this .tiffields.add(modelTiepointTag);
293: }
294:
295: // ************************************************************************
296: // CoordinateSystem
297: // ************************************************************************
298: /**
299: *
300: */
301: private void setCoordinateSystem(CoordinateSystem crs) {
302: /*
303: * // add GTModelTypeGeoKey int[] values_GTModelTypeGeoKey = { 0, 1, 2 };
304: * addKeyToGeoKeyDirectoryTag(GeoTiffKey.GTModelTypeGeoKey, values_GTModelTypeGeoKey);
305: *
306: * try { String horizontalDatum = crs.getHorizontalDatum().getName();
307: *
308: * if ( Geographic_CS_Codes.contains_Geodectic_Datum_Code(horizontalDatum ) ) {
309: *
310: * int[] geographictypegeokey = { 0, 1,
311: * Geographic_CS_Codes.getGeogrpahicCSTypeCode(horizontalDatum) };
312: * addKeyToGeoKeyDirectoryTag(GeoTiffKey.GeographicTypeGeoKey, geographictypegeokey); } else {
313: * throw new GeoTiffException( "Error in determining Horizontal Datum Name:\n" + ' ' +
314: * horizontalDatum + " ist not registered in Geodetic Datum Codes."); } } catch (Exception
315: * e) { throw new GeoTiffException("RemoteException: " + e.getMessage()); }
316: */
317:
318: }
319:
320: }
|