import java.awt.image.*; import java.io.*; import java.util.*; import java.util.zip.*; import java.awt.*; import java.awt.event.*; public class PNGDecoder { public static void main(String[] args) throws Exception { String name = "basn3p08.png"; if (args.length > 0) name = args[0]; InputStream in = PNGDecoder.class.getResourceAsStream(name); final BufferedImage image = PNGDecoder.decode(in); in.close(); // Create a Frame to display the image. Frame f = new ApplicationFrame("PNGDecoder v1.0") { public void paint(Graphics g) { Insets insets = getInsets(); g.drawImage(image, insets.left, insets.top, null); } }; f.setVisible(true); Insets insets = f.getInsets(); f.setSize(image.getWidth() + insets.left + insets.right, image.getHeight() + insets.top + insets.bottom); } public static BufferedImage decode(InputStream in) throws IOException { DataInputStream dataIn = new DataInputStream(in); readSignature(dataIn); PNGData chunks = readChunks(dataIn); long widthLong = chunks.getWidth(); long heightLong = chunks.getHeight(); if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE) throw new IOException("That image is too wide or tall."); int width = (int)widthLong; int height = (int)heightLong; ColorModel cm = chunks.getColorModel(); WritableRaster raster = chunks.getRaster(); BufferedImage image = new BufferedImage(cm, raster, false, null); return image; } protected static void readSignature(DataInputStream in) throws IOException { long signature = in.readLong(); if (signature != 0x89504e470d0a1a0aL) throw new IOException("PNG signature not found!"); } protected static PNGData readChunks(DataInputStream in) throws IOException { PNGData chunks = new PNGData(); boolean trucking = true; while (trucking) { try { // Read the length. int length = in.readInt(); if (length < 0) throw new IOException("Sorry, that file is too long."); // Read the type. byte[] typeBytes = new byte[4]; in.readFully(typeBytes); // Read the data. byte[] data = new byte[length]; in.readFully(data); // Read the CRC. long crc = in.readInt() & 0x00000000ffffffffL; // Make it unsigned. if (verifyCRC(typeBytes, data, crc) == false) throw new IOException("That file appears to be corrupted."); PNGChunk chunk = new PNGChunk(typeBytes, data); chunks.add(chunk); } catch (EOFException eofe) { trucking = false; } } return chunks; } protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) { CRC32 crc32 = new CRC32(); crc32.update(typeBytes); crc32.update(data); long calculated = crc32.getValue(); return (calculated == crc); } }