java-org.hwo/src/org/hwo/image/tiff/IFD.java

358 lines
7.5 KiB
Java

package org.hwo.image.tiff;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.hwo.Unsigned;
import org.hwo.image.UnsupportedFormatException;
class IFD
{
final TiffFile tiffFile;
boolean decoded;
Short numEntries;
HashMap<Short, IFDEntry> entries;
BufferedImage bufferedImage;
protected IFD(TiffFile tiffFile)
{
this.tiffFile = tiffFile;
decoded = false;
entries = new HashMap<Short, IFDEntry>();
bufferedImage = null;
numEntries = this.tiffFile.sourceBuffer.getShort();
System.err.println(String.format("readIFD(): reading %d entries",numEntries));
for (int i=0;i<numEntries;i++)
{
IFDEntry entry = IFDEntry.read(this);
if (entry != null)
entries.put(entry.tag, entry);
}
Integer nextIFD = this.tiffFile.sourceBuffer.getInt();
if (nextIFD != 0)
{
this.tiffFile.sourceBuffer.position(nextIFD);
this.tiffFile.ifds.add(0,new IFD(this.tiffFile));
}
}
protected IFD(TiffFile tiffFile, BufferedImage image)
{
this.tiffFile = tiffFile;
decoded = true;
bufferedImage = image;
numEntries = 0;
entries = new HashMap<Short, IFDEntry>();
}
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<Strip> strips = new ArrayList<Strip>();
for (int i=0;i<stripOffsets.length;i++)
strips.add(new Strip(this, stripOffsets[i], stripByteCounts[i], rowsPerStrip));
switch (photometric)
{
case BLACK:
case WHITE:
decodeGray(image,strips);
break;
case RGB:
decodeRGB(image,strips);
break;
default:
throw new UnsupportedFormatException("unsupported pixel format");
}
return image;
}
private void decodeGray(BufferedImage image,List<Strip> 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<Strip> 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<samplesPerPixel;i++)
if (bitsPerSample[i] != 8)
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++)
{
byte r,g,b,a;
int[] pixel = new int[samplesPerPixel];
for (int n=0;n<samplesPerPixel;n++)
{
pixel[n] = Unsigned.byte2short(buffer.get(p + n));
if (predictor == 2 && column > 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();
}
}