private float readFloat(SeekableStream stream) throws IOException { if (isBigEndian) { return stream.readFloat(); } else { return stream.readFloatLE(); } }
private double readDouble(SeekableStream stream) throws IOException { if (isBigEndian) { return stream.readDouble(); } else { return stream.readDoubleLE(); } }
private long readLong(SeekableStream stream) throws IOException { if (isBigEndian) { return stream.readLong(); } else { return stream.readLongLE(); } }
private long readUnsignedInt(SeekableStream stream) throws IOException { if (isBigEndian) { return stream.readUnsignedInt(); } else { return stream.readUnsignedIntLE(); } }
private short readShort(SeekableStream stream) throws IOException { if (isBigEndian) { return stream.readShort(); } else { return stream.readShortLE(); } }
private static int readUnsignedShort(SeekableStream stream, boolean isBigEndian) throws IOException { if (isBigEndian) { return stream.readUnsignedShort(); } else { return stream.readUnsignedShortLE(); } }
/** * Returns the number of image directories (subimages) stored in a given TIFF file, represented by * a <code>SeekableStream</code>. */ public static int getNumDirectories(SeekableStream stream) throws IOException { long pointer = stream.getFilePointer(); // Save stream pointer stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("TIFFDirectory1"); } boolean isBigEndian = (endian == 0x4d4d); int magic = readUnsignedShort(stream, isBigEndian); if (magic != 42) { throw new IllegalArgumentException("TIFFDirectory2"); } stream.seek(4L); long offset = readUnsignedInt(stream, isBigEndian); int numDirectories = 0; while (offset != 0L) { ++numDirectories; stream.seek(offset); long entries = readUnsignedShort(stream, isBigEndian); stream.skipFully(12 * entries); offset = readUnsignedInt(stream, isBigEndian); } stream.seek(pointer); // Reset stream pointer return numDirectories; }
/** * Constructs a TIFFDirectory by reading a SeekableStream. The ifd_offset parameter specifies the * stream offset from which to begin reading; this mechanism is sometimes used to store private * IFDs within a TIFF file that are not part of the normal sequence of IFDs. * * @param stream a SeekableStream to read from. * @param ifd_offset the long byte offset of the directory. * @param directory the index of the directory to read beyond the one at the current stream * offset; zero indicates the IFD at the current offset. */ public TIFFDirectory(SeekableStream stream, long ifd_offset, int directory) throws IOException { long global_save_offset = stream.getFilePointer(); stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("TIFFDirectory1"); } isBigEndian = (endian == 0x4d4d); // Seek to the first IFD. stream.seek(ifd_offset); // Seek to desired IFD if necessary. int dirNum = 0; while (dirNum < directory) { // Get the number of fields in the current IFD. long numEntries = readUnsignedShort(stream); // Skip to the next IFD offset value field. stream.seek(ifd_offset + 12 * numEntries); // Read the offset to the next IFD beyond this one. ifd_offset = readUnsignedInt(stream); // Seek to the next IFD. stream.seek(ifd_offset); // Increment the directory. dirNum++; } initialize(stream); stream.seek(global_save_offset); }
/** * Constructs a TIFFDirectory from a SeekableStream. The directory parameter specifies which * directory to read from the linked list present in the stream; directory 0 is normally read but * it is possible to store multiple images in a single TIFF file by maintaing multiple * directories. * * @param stream a SeekableStream to read from. * @param directory the index of the directory to read. */ public TIFFDirectory(SeekableStream stream, int directory) throws IOException { long global_save_offset = stream.getFilePointer(); long ifd_offset; // Read the TIFF header stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("TIFFDirectory1"); } isBigEndian = (endian == 0x4d4d); int magic = readUnsignedShort(stream); if (magic != 42) { throw new IllegalArgumentException("TIFFDirectory2"); } // Get the initial ifd offset as an unsigned int (using a long) ifd_offset = readUnsignedInt(stream); for (int i = 0; i < directory; i++) { if (ifd_offset == 0L) { throw new IllegalArgumentException("TIFFDirectory3"); } stream.seek(ifd_offset); long entries = readUnsignedShort(stream); stream.skipFully(12 * entries); ifd_offset = readUnsignedInt(stream); } stream.seek(ifd_offset); initialize(stream); stream.seek(global_save_offset); }
private void initialize(SeekableStream stream) throws IOException { long nextTagOffset; int i, j; IFDOffset = stream.getFilePointer(); numEntries = readUnsignedShort(stream); fields = new TIFFField[numEntries]; for (i = 0; i < numEntries; i++) { int tag = readUnsignedShort(stream); int type = readUnsignedShort(stream); int count = (int) (readUnsignedInt(stream)); int value = 0; // The place to return to to read the next tag nextTagOffset = stream.getFilePointer() + 4; try { // If the tag data can't fit in 4 bytes, the next 4 bytes // contain the starting offset of the data if (count * sizeOfType[type] > 4) { value = (int) (readUnsignedInt(stream)); stream.seek(value); } } catch (ArrayIndexOutOfBoundsException ae) { System.err.println(tag + " " + "TIFFDirectory4"); // if the data type is unknown we should skip this TIFF Field stream.seek(nextTagOffset); continue; } fieldIndex.put(tag, i); Object obj = null; switch (type) { case TIFFField.TIFF_BYTE: case TIFFField.TIFF_SBYTE: case TIFFField.TIFF_UNDEFINED: case TIFFField.TIFF_ASCII: byte[] bvalues = new byte[count]; stream.readFully(bvalues, 0, count); if (type == TIFFField.TIFF_ASCII) { // Can be multiple strings int index = 0, prevIndex = 0; List v = new ArrayList(); while (index < count) { while ((index < count) && (bvalues[index++] != 0)) ; // When we encountered zero, means one string has ended v.add(new String(bvalues, prevIndex, (index - prevIndex))); prevIndex = index; } count = v.size(); String[] strings = new String[count]; v.toArray(strings); obj = strings; } else { obj = bvalues; } break; case TIFFField.TIFF_SHORT: char[] cvalues = new char[count]; for (j = 0; j < count; j++) { cvalues[j] = (char) (readUnsignedShort(stream)); } obj = cvalues; break; case TIFFField.TIFF_LONG: long[] lvalues = new long[count]; for (j = 0; j < count; j++) { lvalues[j] = readUnsignedInt(stream); } obj = lvalues; break; case TIFFField.TIFF_RATIONAL: long[][] llvalues = new long[count][2]; for (j = 0; j < count; j++) { llvalues[j][0] = readUnsignedInt(stream); llvalues[j][1] = readUnsignedInt(stream); } obj = llvalues; break; case TIFFField.TIFF_SSHORT: short[] svalues = new short[count]; for (j = 0; j < count; j++) { svalues[j] = readShort(stream); } obj = svalues; break; case TIFFField.TIFF_SLONG: int[] ivalues = new int[count]; for (j = 0; j < count; j++) { ivalues[j] = readInt(stream); } obj = ivalues; break; case TIFFField.TIFF_SRATIONAL: int[][] iivalues = new int[count][2]; for (j = 0; j < count; j++) { iivalues[j][0] = readInt(stream); iivalues[j][1] = readInt(stream); } obj = iivalues; break; case TIFFField.TIFF_FLOAT: float[] fvalues = new float[count]; for (j = 0; j < count; j++) { fvalues[j] = readFloat(stream); } obj = fvalues; break; case TIFFField.TIFF_DOUBLE: double[] dvalues = new double[count]; for (j = 0; j < count; j++) { dvalues[j] = readDouble(stream); } obj = dvalues; break; default: System.err.println("TIFFDirectory0"); break; } fields[i] = new TIFFField(tag, type, count, obj); stream.seek(nextTagOffset); } // Read the offset of the next IFD. nextIFDOffset = readUnsignedInt(stream); }