001: package org.geotiff.image.jai;
002:
003: import org.geotiff.image.KeyRegistry;
004: import org.libtiff.jai.codec.XTIFFDirectory;
005: import org.libtiff.jai.codec.XTIFFField;
006: import org.libtiff.jai.codec.XTIFF;
007:
008: import java.util.TreeMap;
009: import java.util.Iterator;
010:
011: // Warning: media libs subject to change
012: import com.sun.media.jai.codec.SeekableStream;
013:
014: /**
015: * An extension of the XTIFFDirectory that understands
016: * the structure of the GeoTIFF key set
017: * @author Niles D. Ritter
018: */
019:
020: public class GeoTIFFDirectory extends XTIFFDirectory implements
021: java.io.Serializable {
022:
023: private TreeMap geoKeyIndex = new TreeMap();
024: private int keyDirectoryVersion;
025: private int majorRevision;
026: private int minorRevision;
027: private int numberOfKeys;
028: private double[] tiepoints = null;
029: private double[] scales = null;
030: private double[] matrix = null;
031: private boolean hasGeoKeys = false;
032:
033: /**
034: * public constructor (for serializability)
035: */
036: public GeoTIFFDirectory() {
037: }
038:
039: /**
040: * Constructs a GeoTIFFDirectory by reading a SeekableStream.
041: * The ifd_offset parameter specifies the stream offset from
042: * which to begin reading;
043: * this mechanism is sometimes used to store private IFDs within a
044: * TIFF file that are not part of the normal sequence of IFDs.
045: */
046:
047: public GeoTIFFDirectory(SeekableStream stream, long ifd_offset)
048: throws java.io.IOException {
049: super (stream, ifd_offset);
050: readGeoKeys();
051: log("GeoTIFFDirectory constructor success.");
052: }
053:
054: /**
055: * Constructs a GeoTIFFDirectory from a SeekableStream.
056: * The directory parameter specifies which directory to read
057: * from the linked list present in the stream; directory 0 is
058: * normally read but it is possible to store multiple images
059: * in a single TIFF file by maintaing multiple directories.
060: */
061:
062: public GeoTIFFDirectory(SeekableStream stream, int directory)
063: throws java.io.IOException {
064: super (stream, directory);
065: readGeoKeys();
066: log("GeoTIFFDirectory constructor success.");
067: }
068:
069: private void log(String msg) {
070: }
071:
072: /**
073: * Generates the TIFF fields from the GeoKey list
074: */
075: private void createGeoTags() {
076:
077: if (!hasGeoKeys)
078: return;
079:
080: char numberOfKeys = (char) geoKeyIndex.size();
081: char[] keys = new char[(numberOfKeys + 1) * 4];
082:
083: // Write the 4-entry header
084: keys[0] = 1; //key version
085: keys[1] = 1; //majorRevision
086: keys[2] = 0; //minorRevision
087: keys[3] = numberOfKeys;
088:
089: // Write the key directory out
090: Iterator iter = geoKeyIndex.values().iterator();
091: double[] doubles = new double[numberOfKeys];
092: String strings = "";
093: int indx = 4;
094: char numDoubles = 0;
095: char tag = 0;
096: char valueOrOffset = 0;
097: while (iter.hasNext()) {
098: XTIFFField geoKey = (XTIFFField) iter.next();
099: switch (geoKey.getType()) {
100: case XTIFFField.TIFF_SHORT:
101: // short values are stored in the valueOrOffset
102: tag = 0;
103: valueOrOffset = (char) geoKey.getAsInt(0);
104: break;
105: case XTIFFField.TIFF_DOUBLE:
106: tag = (char) XTIFF.TIFFTAG_GEO_DOUBLE_PARAMS;
107: doubles[numDoubles] = geoKey.getAsDouble(0);
108: valueOrOffset = numDoubles++;
109: break;
110: case XTIFFField.TIFF_ASCII:
111: // strings are '|' pipe delimited
112: tag = (char) XTIFF.TIFFTAG_GEO_ASCII_PARAMS;
113: valueOrOffset = (char) strings.length();
114: strings = strings + geoKey.getAsString(0) + "|";
115: break;
116: } //switch
117: keys[indx++] = (char) geoKey.getTag();
118: keys[indx++] = tag;
119: keys[indx++] = (char) geoKey.getCount();
120: keys[indx++] = valueOrOffset;
121: } //while
122:
123: // Add the Directory tag
124: addField(XTIFF.TIFFTAG_GEO_KEY_DIRECTORY,
125: XTIFFField.TIFF_SHORT, keys.length, keys);
126:
127: // Add the Ascii tag if needed
128: if (strings.length() > 0) {
129: char zero = 0;
130: strings = strings + zero;
131: addField(XTIFF.TIFFTAG_GEO_ASCII_PARAMS,
132: XTIFFField.TIFF_ASCII, strings.length(),
133: new String[] { strings });
134: }
135:
136: // Add the double tag if needed
137: if (numDoubles > 0) {
138: double[] doubleVals = new double[numDoubles];
139: for (int i = 0; i < numDoubles; i++)
140: doubleVals = doubles;
141: addField(XTIFF.TIFFTAG_GEO_DOUBLE_PARAMS,
142: XTIFFField.TIFF_DOUBLE, numDoubles, doubleVals);
143: }
144:
145: // set up the other values stored in tags
146: if (matrix != null)
147: addField(XTIFF.TIFFTAG_GEO_TRANS_MATRIX,
148: XTIFFField.TIFF_DOUBLE, matrix.length, matrix);
149: if (tiepoints != null)
150: addField(XTIFF.TIFFTAG_GEO_TIEPOINTS,
151: XTIFFField.TIFF_DOUBLE, tiepoints.length, tiepoints);
152: if (scales != null)
153: addField(XTIFF.TIFFTAG_GEO_PIXEL_SCALE,
154: XTIFFField.TIFF_DOUBLE, scales.length, scales);
155: }
156:
157: /**
158: * stores a single geoKey in the index table,
159: * from the existing field information
160: */
161: private void storeGeoKey(int keyID, int tiffTag, int valueCount,
162: int valueOrOffset) throws java.io.IOException {
163: int type = XTIFFField.TIFF_SHORT;
164: Object value = null;
165: if (tiffTag > 0) {
166: // Values are in another tag:
167: XTIFFField values = getField(tiffTag);
168: if (values != null) {
169: type = values.getType();
170: if (type == XTIFFField.TIFF_ASCII) {
171: String svalue = values.getAsString(0).substring(
172: valueOrOffset,
173: valueOrOffset + valueCount - 1);
174: value = new String[] { svalue };
175: } else if (type == XTIFFField.TIFF_DOUBLE) {
176: // we shouldn't have valueCount != 1 here
177: double dvalue = values.getAsDouble(valueOrOffset);
178: value = new double[] { dvalue };
179: }
180: } else {
181: throw new java.io.IOException("GeoTIFF tag not found");
182: } // values tag found
183: } else {
184: // value is SHORT, stored in valueOrOffset
185: type = XTIFFField.TIFF_SHORT;
186: value = new char[] { (char) valueOrOffset };
187: } // tiffTag
188: addGeoKey(keyID, type, valueCount, value);
189: }
190:
191: /**
192: * Returns an array of XTIFFFields containing all the fields
193: * in this directory. Prior to returning array, determine if
194: * there are any GeoKeys, and if so, set up the corresponding
195: * GeoTIFF fields.
196: */
197: public XTIFFField[] getFields() {
198: if (hasGeoKeys)
199: createGeoTags();
200: return super .getFields();
201: }
202:
203: /**
204: * populates the geoKeyIndex table from the values stored in
205: * the current TIFF fields.
206: */
207: private void readGeoKeys() throws java.io.IOException {
208:
209: // read in the keys
210: XTIFFField geoKeyTag = getField(XTIFF.TIFFTAG_GEO_KEY_DIRECTORY);
211: if (geoKeyTag != null) {
212: char[] keys = geoKeyTag.getAsChars();
213:
214: // Set up header info
215: keyDirectoryVersion = keys[0]; //should be 1 forever.
216: majorRevision = keys[1]; //currently 1
217: minorRevision = keys[2]; //0,1, or 2...
218: numberOfKeys = keys[3];
219:
220: // Parse out keys and values
221: for (int i = 4; i < keys.length; i += 4) {
222: int keyID = keys[i];
223: int tiffTag = keys[i + 1];
224: int valueCount = keys[i + 2];
225: int valueOrOffset = keys[i + 3];
226: storeGeoKey(keyID, tiffTag, valueCount, valueOrOffset);
227: }
228:
229: }
230:
231: // set up the values stored in tags
232: // read in the data stored as real tags
233: XTIFFField matrixTag = getField(XTIFF.TIFFTAG_GEO_TRANS_MATRIX);
234: XTIFFField tiepointTag = getField(XTIFF.TIFFTAG_GEO_TIEPOINTS);
235: XTIFFField scaleTag = getField(XTIFF.TIFFTAG_GEO_PIXEL_SCALE);
236: if (tiepointTag != null) {
237: tiepoints = tiepointTag.getAsDoubles();
238: }
239: if (scaleTag != null) {
240: scales = scaleTag.getAsDoubles();
241: }
242: if (matrixTag != null) {
243: matrix = matrixTag.getAsDoubles();
244: }
245: } //readGeoKeys
246:
247: /**
248: * Add a geoKey to the directory
249: */
250: public void addGeoKey(int key, int type, int count, Object data) {
251: XTIFFField geoKey = createField(key, type, count, data);
252: addGeoKey(geoKey);
253: }
254:
255: /**
256: * Add an existing geoKey to the directory.
257: */
258: public void addGeoKey(XTIFFField geoKey) {
259: geoKeyIndex.put(new Integer(geoKey.getTag()), geoKey);
260: hasGeoKeys = true;
261: }
262:
263: /**
264: * Returns an array of XTIFFFields containing all the fields
265: * corresponding to the GeoKeys.
266: */
267: public XTIFFField[] getGeoKeys() {
268: XTIFFField[] keys = new XTIFFField[geoKeyIndex.size()];
269: Iterator iter = geoKeyIndex.values().iterator();
270: int i = 0;
271: while (iter.hasNext()) {
272: keys[i++] = (XTIFFField) iter.next();
273: }
274: return keys;
275: }
276:
277: /**
278: * Indexed Accessor to the Geokeys,indexed by
279: * the key values.
280: */
281: public XTIFFField getGeoKey(int key) {
282: return (XTIFFField) geoKeyIndex.get(new Integer(key));
283: }
284:
285: /**
286: * return the tiepoint tag values
287: */
288: public double[] getTiepoints() {
289: return tiepoints;
290: }
291:
292: /**
293: * return the pixel scale tag values
294: */
295: public double[] getPixelScale() {
296: return scales;
297: }
298:
299: /**
300: * return the transformation matrix tag values
301: */
302: public double[] getTransformationMatrix() {
303: return matrix;
304: }
305:
306: /**
307: * set the tiepoint tag values
308: */
309: public void setTiepoints(double[] tiepoints) {
310: this .tiepoints = tiepoints;
311: }
312:
313: /**
314: * return the pixel scale tag values
315: */
316: public void setPixelScale(double[] scales) {
317: this .scales = scales;
318: }
319:
320: /**
321: * return the pixel scale tag values
322: */
323: public void setTransformationMatrix(double[] matrix) {
324: this.matrix = matrix;
325: }
326: }
|