//
// LegacyTiffTools.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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
*/
package visad.data.tiff;
import java.util.*;
import java.io.*;
import loci.formats.codec.LZWCodec;
/**
* A utility class for manipulating TIFF files.
* @author Eric Kjellman egkjellman at wisc.edu
*
* @deprecated Use loci.formats.TiffTools
*/
public class LegacyTiffTools {
private static final int CLEAR_CODE = 256;
private static final int EOI_CODE = 257;
private static final int PHOTOMETRIC_INTERPRETATION_FIELD = 262;
private static final int IMPOSSIBLE_IFD = 424242;
public static Hashtable getIFDHash(RandomAccessFile readIn)
throws IOException
{
byte[] byteArray = new byte[4];
int nextOffset;
readIn.seek(4);
readIn.read(byteArray); // Gets the offset of the first IFD
readIn.seek(batoi(byteArray));
byteArray = new byte[2];
// Gets the number of directory entries in the IFD
readIn.read(byteArray);
Hashtable ifdEntries = new Hashtable();
Integer numEntries = new Integer(batoi(byteArray));
Integer entryTag, entryType, entrycount, entryOffset;
int frames = 1;
int length, offset;
Vector entryData;
// Iterate through the directory entries
for (int i = 0; i < numEntries.intValue(); i++) {
byteArray = new byte[2];
readIn.read(byteArray); // Get the entry tag
entryTag = new Integer(batoi(byteArray));
readIn.read(byteArray); // Get the entry type
entryType = new Integer(batoi(byteArray));
byteArray = new byte[4];
// Get the number of entries this offset points to.
readIn.read(byteArray);
entrycount = new Integer(batoi(byteArray));
readIn.read(byteArray); // Gets the offset for the entry
entryOffset = new Integer(batoi(byteArray));
// Adds the data to a vector, and then hashs it.
entryData = new Vector();
entryData.add(entryType);
entryData.add(entrycount);
entryData.add(entryOffset);
ifdEntries.put(entryTag, entryData);
}
readIn.read(byteArray);
nextOffset = batoi(byteArray);
ifdEntries.put(new Integer(IMPOSSIBLE_IFD), new Integer(nextOffset));
// 424242 is not possible as an IFD ID number, which are 16 bit
return ifdEntries;
}
public static Hashtable getIFDHash(RandomAccessFile readIn, int block_id)
throws IOException
{
Hashtable ifdEntries = new Hashtable();
Integer entryTag, entryType, entrycount, entryOffset;
int frames = 0;
int length, offset;
byte[] byteArray = new byte[4];
int nextOffset;
Vector entryData;
Integer numEntries;
readIn.seek(4);
readIn.read(byteArray); // Gets the offset of the first IFD
readIn.seek(batoi(byteArray));
// Get to the IFD we want.
while (frames != block_id) {
byteArray = new byte[2];
// Gets the number of directory entries in the IFD
readIn.read(byteArray);
numEntries = new Integer(batoi(byteArray));
// skips the IFD
readIn.skipBytes(12 * numEntries.intValue());
// Get the nextOffset
byteArray = new byte[4];
readIn.read(byteArray);
readIn.seek(batoi(byteArray));
frames++;
}
byteArray = new byte[2];
readIn.read(byteArray);
numEntries = new Integer(batoi(byteArray));
// Iterate through the directory entries
for (int i = 0; i < numEntries.intValue(); i++) {
byteArray = new byte[2];
readIn.read(byteArray); // Get the entry tag
entryTag = new Integer(batoi(byteArray));
readIn.read(byteArray); // Get the entry type
entryType = new Integer(batoi(byteArray));
byteArray = new byte[4];
// Get the number of entries this offset points to.
readIn.read(byteArray);
entrycount = new Integer(batoi(byteArray));
readIn.read(byteArray); // Gets the offset for the entry
entryOffset = new Integer(batoi(byteArray));
// Adds the data to a vector, and then hashs it.
entryData = new Vector();
entryData.add(entryType);
entryData.add(entrycount);
entryData.add(entryOffset);
ifdEntries.put(entryTag, entryData);
}
readIn.read(byteArray);
nextOffset = batoi(byteArray);
ifdEntries.put(new Integer(IMPOSSIBLE_IFD), new Integer(nextOffset));
// 424242 is not possible as an IFD ID number, which are 16 bit
return ifdEntries;
}
/**
* Items in an IFD can be pointers to arrays of data, and not just single
* items. This will return an array of int containing the data pointed to
* in the IFD. This does not currently handle the type RATIONAL.
*/
public static int[] getIFDArray(RandomAccessFile readIn, Vector v)
throws IOException
{
int count = ((Integer) v.get(1)).intValue();
int type = ((Integer) v.get(0)).intValue();
if (count == 1) {
// if the count is 1, there is no pointer, it's actual data
return new int[] {((Integer) v.get(2)).intValue()};
}
else {
readIn.seek(((Integer) v.get(2)).intValue());
int[] toReturn = new int[count];
int bytesPerEntry = 1;
if (type == 1) { // BYTE
bytesPerEntry = 1;
}
if (type == 2) { // ASCII
bytesPerEntry = 1;
}
if (type == 3) { // SHORT
bytesPerEntry = 2;
}
if (type == 4) { // LONG
bytesPerEntry = 4;
}
//if (type == 5) { // RATIONAL, not supported right now.
// bytesPerEntry = 4;
//}
byte[] data = new byte[count * bytesPerEntry];
readIn.read(data);
byte[] translate = new byte[bytesPerEntry];
for (int i = 0; i < count ; i++) {
System.arraycopy(data, i * bytesPerEntry, translate, 0, bytesPerEntry);
toReturn[i] = batoi(translate);
}
return toReturn;
}
}
/**
* Items in an IFD can be pointers to arrays of data, and not just single
* items. This will return an array of int containing the data pointed to
* in the IFD.
*/
public static double[] getIFDRArray(RandomAccessFile readIn, Vector v)
throws IOException
{
int count = ((Integer) v.get(1)).intValue();
int type = ((Integer) v.get(0)).intValue();
if (count == 1) {
// if the count is 1, there is no pointer, it's actual data
// return new int[] {((Integer) v.get(2)).intValue()};
// This shouldn't happen: Rationals require 2 floats.
return new double[] {-1.0D}; // TODO: Change this.
}
else {
readIn.seek(((Integer) v.get(2)).intValue());
double[] toReturn = new double[count];
int bytesPerEntry = 8;
int num, denom;
if (type != 5) { // Not a rational!
return new double[] {-1.0D}; // TODO: Change this.
}
byte[] data = new byte[count * bytesPerEntry];
readIn.read(data);
byte[] translate = new byte[bytesPerEntry];
for (int i = 0; i < count ; i++) {
System.arraycopy(data, i * bytesPerEntry, translate, 0, 4);
num = batoi(translate);
System.arraycopy(data, i * bytesPerEntry + 4, translate, 0, 4);
denom = batoi(translate);
toReturn[i] = num/denom;
}
return toReturn;
}
}
public static byte[] lzwUncompress(byte[] input) throws IOException {
try {
return new LZWCodec().decompress(input);
}
catch (Exception exc) {
return null;
}
}
public static int getPhotometricInterpretation(RandomAccessFile in)
throws IOException
{
Hashtable ifdHash = getIFDHash(in);
Vector v = (Vector) ifdHash.get(
new Integer(PHOTOMETRIC_INTERPRETATION_FIELD));
return ((Integer) v.get(2)).intValue();
}
/** Translates up to the first 4 bytes of a byte array to an integer. */
public static int batoi(byte[] inp) {
int len = inp.length>4?4:inp.length;
int total = 0;
for (int i = 0; i < len; i++) {
total += ((inp[i]<0?256+inp[i]:(int)inp[i]) << (i * 8));
}
return total;
}
public static int[] getTIFFDimensions(RandomAccessFile readIn)
throws IOException
{
// For this one, we're going to read the entire IFD, get the x and y
// coordinates out of it, and then just pass through the other IFDs to get
// z. It is conceivable that the various images are of different sizes,
// but for now I'm going to assume that they are not.
byte[] byteArray;
int nextOffset;
int numEntries;
int frames = 1;
Integer width, length;
Vector entryData;
Hashtable ifdEntries = getIFDHash(readIn);
nextOffset =
((Integer) ifdEntries.get(new Integer(IMPOSSIBLE_IFD))).intValue();
while (nextOffset != 0) {
frames++;
try {
readIn.seek(nextOffset);
}
catch (Exception e) {
e.printStackTrace();
}
byteArray = new byte[2];
readIn.read(byteArray); // Get the number of directory entries in the IFD
numEntries = batoi(byteArray);
readIn.skipBytes(12 * numEntries);
byteArray = new byte[4];
readIn.read(byteArray);
nextOffset = batoi(byteArray);
}
// This is the directory entry for width.
entryData = (Vector) ifdEntries.get(new Integer(256));
width = (Integer) entryData.get(2);
// This is the directory entry for height.
entryData = (Vector) ifdEntries.get(new Integer(257));
length = (Integer) entryData.get(2);
return new int[] {width.intValue(), length.intValue(), frames};
}
public static int getIFDValue(Hashtable h, int id) {
Integer k = new Integer(id);
Vector v = (Vector) h.get(k);
if (v == null) return -1;
Integer i = (Integer) v.get(2);
if (i == null) return -1;
return i.intValue();
}
public static boolean isIFDArray(Hashtable h, int id) {
return getIFDValue(h, id) == 1;
}
// -- Main method --
public static void main(String args[]) throws IOException {
Vector v;
Integer k;
// File f = new File(args[0]);
RandomAccessFile f = new RandomAccessFile(args[0], "r");
Hashtable h = new Hashtable();
int[] d = getTIFFDimensions(f);
for (int meh = 0; meh < d[2]; meh++) {
System.out.println("*** START HASH #" + meh);
h = getIFDHash(f, meh);
for(int i = 0; i < 65536; i++) {
k = new Integer(i);
if(h.containsKey(k)) {
v = (Vector) h.get(k);
System.out.print(k + ":");
System.out.print((Integer) v.get(0) + " ");
System.out.print((Integer) v.get(1) + " ");
System.out.println((Integer) v.get(2));
if (((Integer) v.get(1)).intValue() != 1) {
if(((Integer) v.get(1)).intValue() != 5) {
int[] a= getIFDArray(f, v);
System.out.print(" [ ");
for (int j = 0; j < a.length; j++) {
System.out.print(a[j] + " ");
}
System.out.println("]");
}
else {
double[] a= getIFDRArray(f, v);
System.out.print(" [ ");
for (int j = 0; j < a.length; j++) {
System.out.print(a[j] + " ");
}
System.out.println("]");
}
}
}
}
System.out.println("*** END HASH #" + meh);
System.out.println(" ");
}
int[] a = getTIFFDimensions(f);
System.out.println(a[0] + "x" + a[1] + "x" + a[2]);
}
}