//
// 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]);
  }

}

 

Ads help maintain this website.