FileDocCategorySizeDatePackage
PNGDecoder.javaAPI DocExample3079Mon Apr 05 11:21:12 BST 1999None

PNGDecoder.java

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);
  }
}