The following code reads the width, height and type (png/jpeg/etc…) of an image from an InputStream and closes it immediately.
public enum ImageType
{
TGA, BMP, JPG, GIF, PNG;
}
public class ImageMetaData
{
public final ImageType type;
public final int width;
public final int height;
public ImageMetaData(ImageType type, int width, int height)
{
this.type = type;
this.width = width;
this.height = height;
}
public Dimension getDimension()
{
return new Dimension(this.width, this.height);
}
public String toString()
{
return type.name() + ":" + this.width + "x" + this.height;
}
}
public static Dimension getImageSize(InputStream in) throws IOException
{
ImageMetaData meta = getImageTypeAndSize(in);
if(meta == null) return null;
return new Dimension(meta.width, meta.height);
}
public static ImageMetaData getImageTypeAndSize(InputStream in) throws IOException
{
DataInputStream dis = new DataInputStream(new BufferedInputStream(in));
try
{
int header = dis.readUnsignedShort();
if (header == 0x8950)
{
// PNG!
dis.readFully(new byte[(8 - 2) + 4 + 4]); // thanks Abuse
return new ImageMetaData(ImageType.PNG, dis.readInt(), dis.readInt());
}
if (header == 0xffd8)
{
// JPG!
while (true)
{
int marker = dis.readUnsignedShort();
switch (marker)
{
case 0xffd8: // SOI
case 0xffd0: // RST0
case 0xffd1: // RST1
case 0xffd2: // RST2
case 0xffd3: // RST3
case 0xffd4: // RST4
case 0xffd5: // RST5
case 0xffd6: // RST6
case 0xffd7: // RST7
case 0xffd9: // EOI
break;
case 0xffdd: // DRI
dis.readUnsignedShort();
break;
case 0xffe0: // APP0
case 0xffe1: // APP1
case 0xffe2: // APP2
case 0xffe3: // APP3
case 0xffe4: // APP4
case 0xffe5: // APP5
case 0xffe6: // APP6
case 0xffe7: // APP7
case 0xffe8: // APP8
case 0xffe9: // APP9
case 0xffea: // APPa
case 0xffeb: // APPb
case 0xffec: // APPc
case 0xffed: // APPd
case 0xffee: // APPe
case 0xffef: // APPf
case 0xfffe: // COM
case 0xffdb: // DQT
case 0xffc4: // DHT
case 0xffda: // SOS
dis.readFully(new byte[dis.readUnsignedShort() - 2]);
break;
case 0xffc0: // SOF0
case 0xffc2: // SOF2
dis.readUnsignedShort();
dis.readByte();
int height = dis.readUnsignedShort();
int width = dis.readUnsignedShort();
return new ImageMetaData(ImageType.JPG, width, height);
default:
throw new IllegalStateException("invalid jpg marker: " + Integer.toHexString(marker));
}
}
}
else if (header == 0x424D)
{
// BMP!
dis.readFully(new byte[16]);
int w = PrimIO.swap32(dis.readInt());
int h = PrimIO.swap32(dis.readInt());
return new ImageMetaData(ImageType.BMP, w, h);
}
else if (header == (('G' << 8) | ('I' << 0))) // GIF
{
// GIF!
dis.readFully(new byte[4]);
int w = PrimIO.swap16(dis.readUnsignedShort());
int h = PrimIO.swap16(dis.readUnsignedShort());
return new ImageMetaData(ImageType.GIF, w, h);
}
else
// TGA?
{
// TGA doesn't have a magic number, try to parse
byte[] tgaRemainingHeader = new byte[18 - 2];
try
{
dis.readFully(tgaRemainingHeader);
}
catch (EOFException exc)
{
return null;
//throw new IllegalStateException("unsupported image type. (header: " + Integer.toHexString(header) + ")");
}
try
{
if (tgaRemainingHeader[2 - 2] != 2) // uncompressed
throw new IllegalStateException();
int w = 0, h = 0;
w |= (tgaRemainingHeader[12 - 2] & 0xFF) << 0;
w |= (tgaRemainingHeader[13 - 2] & 0xFF) << 8;
h |= (tgaRemainingHeader[14 - 2] & 0xFF) << 0;
h |= (tgaRemainingHeader[15 - 2] & 0xFF) << 8;
if ((w | h) < 0)
throw new IllegalStateException();
boolean alpha;
if (tgaRemainingHeader[16 - 2] == 24)
alpha = false;
else if (tgaRemainingHeader[16 - 2] == 32)
alpha = true;
else
throw new IllegalStateException();
if (tgaRemainingHeader[17 - 2] != ((alpha ? 8 : 0) & 15))
throw new IllegalStateException();
return new ImageMetaData(ImageType.TGA, w, h);
}
catch (IllegalStateException exc)
{
return null;
//throw new IllegalStateException("unsupported image type. (header: " + Integer.toHexString(header) + ")");
}
}
}
finally
{
dis.close();
}
}