All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.monte.media.tiff.TIFFInputStream Maven / Gradle / Ivy

The newest version!

package org.monte.media.tiff;

import org.monte.media.math.Rational;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
import javax.imageio.stream.ImageInputStream;


public class TIFFInputStream extends InputStream {

    
    private ByteOrder byteOrder;
    
    private long firstIFDOffset;
    
    private ImageInputStream in;

    public TIFFInputStream(ImageInputStream in) throws IOException {
        this.in = in;
        readHeader();
    }

    
    public TIFFInputStream(ImageInputStream in, ByteOrder byteOrder, long firstIFDOffset) {
        this.in = in;
        this.byteOrder = byteOrder;
        this.firstIFDOffset = firstIFDOffset;
    }

    public ByteOrder getByteOrder() {
        return byteOrder;
    }

    public void setByteOrder(ByteOrder newValue) {
        byteOrder = newValue;
    }

    public long getFirstIFDOffset() {
        return firstIFDOffset;
    }

    
    public IFD readIFD(long offset) throws IOException {
        return readIFD(offset, true, false);
    }

    
    public IFD readIFD(long offset, boolean hasNextOffset, boolean isFirstIFD) throws IOException {
        if ((offset % 1) != 0) {
            throw new IOException("IFD does not start at word boundary");
        }
        if (offset == 0 && !isFirstIFD) {
            return null;
        }
        in.seek(offset);
        int numEntries = readSHORT();
        IFD ifd = new IFD(offset, hasNextOffset);
        for (int i = 0; i < numEntries; i++) {
            long entryOffset = in.getStreamPosition();
            int tag = readSHORT();
            int type = readSHORT();
            long count = readLONG();
            long valueOffset = readSLONG();
            if (count == 0) {
                throw new IOException("IFDEntry " + i + " of " + numEntries + " has count 0 in TIFF stream at offset 0x" + Long.toHexString(offset));

            }
            ifd.add(new IFDEntry(tag, type, count, valueOffset, entryOffset));
        }
        if (hasNextOffset) {
            ifd.setNextOffset(readSLONG());
            if ((ifd.getNextOffset() % 1) != 0) {
                throw new IOException("next IFD does not start at word boundary");
            }
        }

        return ifd;
    }

    
    public String readASCII(long offset, long length) throws IOException {
        in.seek(offset);
        return readASCII(length);
    }

    private String readASCII(long length) throws IOException {
        byte[] buf = new byte[(int) length];
        readFully(buf);
        if (buf[(int) length - 1] != 0) {
            throw new IOException("String does not end with NUL byte.");
        }
        return new String(buf, 0, (int) length - 1, "ASCII");
    }

    private void readFully(byte b[]) throws IOException {
        readFully(b, 0, b.length);

    }

    private void readFully(byte b[], int off, int len) throws IOException {
        if (len < 0) {
            throw new IndexOutOfBoundsException();
        }
        int n = 0;
        while (n < len) {
            int count = in.read(b, off + n, len - n);
            if (count < 0) {
                throw new EOFException("EOF after " + n + " bytes (needed " + len + " bytes)");
            }
            n += count;
        }
    }

    
    public long readLONG(long offset) throws IOException {
        in.seek(offset);
        return readLONG();
    }

    
    public long[] readLONG(long offset, long count) throws IOException {
        in.seek(offset);
        long[] longs = new long[(int) count];
        for (int i = 0; i < count; i++) {
            longs[i] = readLONG();
        }
        return longs;
    }

    
    public int[] readSHORT(long offset, long count) throws IOException {
        in.seek(offset);
        int[] shorts = new int[(int) count];
        for (int i = 0; i < count; i++) {
            shorts[i] = readSHORT();
        }
        return shorts;
    }

    
    public short[] readSSHORT(long offset, long count) throws IOException {
        in.seek(offset);
        short[] shorts = new short[(int) count];
        for (int i = 0; i < count; i++) {
            shorts[i] = readSSHORT();
        }
        return shorts;
    }

    
    public Rational readRATIONAL(long offset) throws IOException {
        in.seek(offset);
        long num = readLONG();
        long denom = readLONG();
        return new Rational(num, denom);
    }

    
    public Rational readSRATIONAL(long offset) throws IOException {
        in.seek(offset);
        int num = readSLONG();
        int denom = readSLONG();
        return new Rational(num, denom);
    }

    
    public Rational[] readRATIONAL(long offset, long count) throws IOException {
        in.seek(offset);
        Rational[] r = new Rational[(int) count];
        for (int i = 0; i < count; i++) {
            r[i] = new Rational(readLONG(), readLONG());
        }
        return r;
    }

    
    public Rational[] readSRATIONAL(long offset, long count) throws IOException {
        in.seek(offset);
        Rational[] r = new Rational[(int) count];
        for (int i = 0; i < count; i++) {
            r[i] = new Rational(readSLONG(), readSLONG());
        }
        return r;
    }

    
    private short readSSHORT() throws IOException {
        int b0 = in.read();
        int b1 = in.read();
        if (b0 == -1 || b1 == -1) {
            throw new EOFException();
        }

        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
            return (short) ((b1 << 8) | b0);
        } else {
            return (short) ((b0 << 8) | b1);
        }
    }

    
    private int readSHORT() throws IOException {
        return readSSHORT() & 0xffff;
    }

    
    private int readSLONG() throws IOException {
        int b0 = in.read();
        int b1 = in.read();
        int b2 = in.read();
        int b3 = in.read();
        if (b0 == -1 || b1 == -1 || b1 == -1 || b2 == -1) {
            throw new EOFException();
        }

        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
            return ((b3 << 24) | (b2 << 16) | (b1 << 8) | b0);
        } else {
            return ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3);
        }
    }

    
    private long readLONG() throws IOException {
        return readSLONG() & 0xffffffffL;
    }

    
    private void readHeader() throws IOException {
        in.seek(0);
        byteOrder = ByteOrder.BIG_ENDIAN;
        int byteOrder = readSHORT();
        switch (byteOrder) {
            case 0x4949:
                this.byteOrder = ByteOrder.LITTLE_ENDIAN;
                break;
            case 0x4d4d:
                this.byteOrder = ByteOrder.BIG_ENDIAN;
                break;
            default:
                throw new IOException("Image File Header illegal byte order value 0x" + Integer.toHexString(byteOrder));
        }

        int magic = readSHORT();
        if (magic != 42) {
            throw new IOException("Image File Header illegal magic value 0x" + Integer.toHexString(magic));
        }

        firstIFDOffset = readSLONG();
        if ((firstIFDOffset & 1) == 1) {
            throw new IOException("Image File Header IFD must be on a word boundary 0x" + Long.toHexString(firstIFDOffset));
        }
    }

    @Override
    public int read() throws IOException {
        return in.read();
    }

    @Override
    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    public int read(long offset, byte b[], int off, int len) throws IOException {
        in.seek(offset);
        return in.read(b, off, len);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy