package org.hwo.image.tiff; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import org.hwo.Unsigned; import org.hwo.image.UnsupportedFormatException; class IFD { final TiffFile tiffFile; boolean decoded; Short numEntries; HashMap entries; BufferedImage bufferedImage; protected IFD(TiffFile tiffFile) { this.tiffFile = tiffFile; decoded = false; entries = new HashMap(); bufferedImage = null; numEntries = this.tiffFile.sourceBuffer.getShort(); System.err.println(String.format("readIFD(): reading %d entries",numEntries)); for (int i=0;i(); } public boolean isDecoded() { return decoded; } private BufferedImage decode() { System.err.println("TiffFile: Decoding..."); if (isDecoded()) return bufferedImage; int width = getWidth(), height = getHeight(); Short compression = getCompression(); short[] bitsPerSample = getBitsPerSample(); PHOTOMETRIC photometric = getPhotometric(); short samplesPerPixel = getSamplesPerPixel(); System.err.println(String.format("Size: %dx%d TYPE: %s COMP: %d BPS: %s",width,height,photometric.toString(),compression,Arrays.toString(bitsPerSample))); BufferedImage image = new BufferedImage(width, height, getJImageType(photometric, bitsPerSample)); int rowsPerStrip = getRowsPerStrip(); int[] stripOffsets = getStripOffsets(); int[] stripByteCounts = getStripByteCounts(); if (stripOffsets.length != stripByteCounts.length) throw new UnsupportedFormatException("StripOffset.length != StripbyteCount.length"); if ((stripOffsets.length * rowsPerStrip) < height) throw new UnsupportedFormatException("stripped lines < scanlines"); ArrayList strips = new ArrayList(); for (int i=0;i strips) { PHOTOMETRIC photometric = getPhotometric(); int width = getWidth(), height = getHeight(); short[] bitsPerSample = getBitsPerSample(); short samplesPerPixel = getSamplesPerPixel(); switch (bitsPerSample[0]) { case 1: case 4: case 8: break; default: throw new UnsupportedFormatException(); } int y = 0; short predictor = getPredictor(); for (Strip strip:strips) { ByteBuffer buffer = strip.getBuffer(); int p = 0; for (int row=0; (row < strip.rowcount) && (y + row < height); row++) { int[] lastPixel = new int[0]; for (int column = 0; column < width ; column++) { int[] pixel = new int[1]; pixel[0] = Unsigned.byte2short(buffer.get(p)); if (predictor == 2 && column > 0) pixel[0] += lastPixel[0]; image.getRaster().setPixel(column, y + row, pixel); p += samplesPerPixel; lastPixel = pixel; } } y += strip.rowcount; } } private void decodeRGB(BufferedImage image,List strips) { int width = getWidth(), height = getHeight(); short[] bitsPerSample = getBitsPerSample(); short samplesPerPixel = getSamplesPerPixel(); switch (samplesPerPixel) { case 3: break; case 4: break; default: throw new UnsupportedFormatException(); } for (int i=0;i 0) { pixel[n] += lastPixel[n]; } } image.getRaster().setPixel(column, y + row, pixel); p += samplesPerPixel; lastPixel = pixel; } } y += strip.rowcount; } } public BufferedImage getBufferedImage() { if (bufferedImage == null) bufferedImage = decode(); return bufferedImage; } int getJImageType(PHOTOMETRIC p,short[] bitsPerSample) { switch (p) { case WHITE: case BLACK: return BufferedImage.TYPE_BYTE_GRAY; case RGB: switch (bitsPerSample.length) { case 3: return BufferedImage.TYPE_3BYTE_BGR; case 4: return BufferedImage.TYPE_4BYTE_ABGR; } break; case PALETTE: return BufferedImage.TYPE_3BYTE_BGR; } throw new UnsupportedFormatException(); } IFDEntry getEntry(short tag) { if (entries.containsKey(tag)) return entries.get(tag); return null; } int getWidth() { IFDEntry e = getEntry((short)256); if (e == null) throw new UnsupportedFormatException("missing width tag"); return ((NumericEntry)e).getInteger(); } int getHeight() { IFDEntry e = getEntry((short)257); if (e == null) throw new UnsupportedFormatException("missing width tag"); return ((NumericEntry)e).getInteger(); } short getPageNumber() { ShortEntry e = (ShortEntry)entries.get((short)297); if (e == null) return -1; return e.getShort(); } PHOTOMETRIC getPhotometric() { ShortEntry e = (ShortEntry)entries.get((short)262); if (e == null) return PHOTOMETRIC.WHITE; return PHOTOMETRIC.fromCode(e.getShort()); } short[] getBitsPerSample() { ShortEntry e = (ShortEntry)entries.get((short)258); if (e == null) return new short[]{1}; return e.getShortArray(); } Integer getRowsPerStrip() { NumericEntry e = (NumericEntry)entries.get((short)278); if (e == null) return 0; return e.getInteger(); } short getSamplesPerPixel() { ShortEntry e = (ShortEntry)entries.get((short)277); if (e == null) return 1; return e.getShort(); } int[] getStripOffsets() { NumericEntry e = (NumericEntry)entries.get((short)273); if (e == null) return new int[0]; return e.getIntArray(); } int[] getStripByteCounts() { NumericEntry e = (NumericEntry)entries.get((short)279); if (e == null) return new int[0]; return e.getIntArray(); } short getCompression() { ShortEntry e = (ShortEntry)entries.get((short)259); if (e == null) return 1; return e.getShort(); } short getPredictor() { ShortEntry e = (ShortEntry)entries.get((short)317); if (e == null) return 1; return e.getShort(); } short getFillOrder() { ShortEntry e = (ShortEntry)entries.get((short)266); if (e == null) return 1; return e.getShort(); } }