19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage org.apache.harmony.awt.gl.image;
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// A simple PNG decoder source code in Java.
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.Graphics;
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.Insets;
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.BufferedImage;
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.ColorModel;
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.DataBuffer;
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.DataBufferByte;
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.IndexColorModel;
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.Raster;
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.WritableRaster;
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.ByteArrayInputStream;
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.ByteArrayOutputStream;
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataInputStream;
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.EOFException;
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream;
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.zip.CRC32;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.zip.InflaterInputStream;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//import javax.swing.JFrame;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class PngDecoderJava {
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public static void main(String[] args) throws Exception {
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    String name = "logo.png";
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (args.length > 0)
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      name = args[0];
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputStream in = PngDecoderJava.class.getResourceAsStream(name);
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final BufferedImage image = PngDecoderJava.decode(in);
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    in.close();
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    JFrame f = new JFrame() {
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      public void paint(Graphics g) {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Insets insets = getInsets();
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        g.drawImage(image, insets.left, insets.top, null);
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      }
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    f.setVisible(true);
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Insets insets = f.getInsets();
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    f.setSize(image.getWidth() + insets.left + insets.right, image
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        .getHeight()
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        + insets.top + insets.bottom);
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  */
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public static BufferedImage decode(InputStream in) throws IOException {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DataInputStream dataIn = new DataInputStream(in);
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    readSignature(dataIn);
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PNGData chunks = readChunks(dataIn);
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long widthLong = chunks.getWidth();
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long heightLong = chunks.getHeight();
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE)
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      throw new IOException("That image is too wide or tall.");
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int width = (int) widthLong;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int height = (int) heightLong;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ColorModel cm = chunks.getColorModel();
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    WritableRaster raster = chunks.getRaster();
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    BufferedImage image = new BufferedImage(cm, raster, false, null);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return image;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  protected static void readSignature(DataInputStream in) throws IOException {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long signature = in.readLong();
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (signature != 0x89504e470d0a1a0aL)
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      throw new IOException("PNG signature not found!");
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  protected static PNGData readChunks(DataInputStream in) throws IOException {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PNGData chunks = new PNGData();
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean trucking = true;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (trucking) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      try {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the length.
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = in.readInt();
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (length < 0)
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          throw new IOException("Sorry, that file is too long.");
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the type.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] typeBytes = new byte[4];
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        in.readFully(typeBytes);
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the data.
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] data = new byte[length];
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        in.readFully(data);
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the CRC.
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long crc = in.readInt() & 0x00000000ffffffffL; // Make it
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // unsigned.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (verifyCRC(typeBytes, data, crc) == false)
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          throw new IOException("That file appears to be corrupted.");
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PNGChunk chunk = new PNGChunk(typeBytes, data);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        chunks.add(chunk);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      } catch (EOFException eofe) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trucking = false;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return chunks;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CRC32 crc32 = new CRC32();
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    crc32.update(typeBytes);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    crc32.update(data);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long calculated = crc32.getValue();
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (calculated == crc);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass PNGData {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  private int mNumberOfChunks;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  private PNGChunk[] mChunks;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public PNGData() {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNumberOfChunks = 0;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mChunks = new PNGChunk[10];
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public void add(PNGChunk chunk) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mChunks[mNumberOfChunks++] = chunk;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mNumberOfChunks >= mChunks.length) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10];
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      System.arraycopy(mChunks, 0, largerArray, 0, mChunks.length);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mChunks = largerArray;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public long getWidth() {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedInt(0);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public long getHeight() {    return getChunk("IHDR").getUnsignedInt(4);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getBitsPerPixel() {
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedByte(8);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getColorType() {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedByte(9);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getCompression() {
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedByte(10);
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getFilter() {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedByte(11);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getInterlace() {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return getChunk("IHDR").getUnsignedByte(12);
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public ColorModel getColorModel() {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    short colorType = getColorType();
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int bitsPerPixel = getBitsPerPixel();
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (colorType == 3) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      byte[] paletteData = getChunk("PLTE").getData();
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int paletteLength = paletteData.length / 3;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      return new IndexColorModel(bitsPerPixel, paletteLength,
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          paletteData, 0, false);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    System.out.println("Unsupported color type: " + colorType);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return null;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public WritableRaster getRaster() {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int width = (int) getWidth();
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int height = (int) getHeight();
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int bitsPerPixel = getBitsPerPixel();
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    short colorType = getColorType();
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (colorType == 3) {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      byte[] imageData = getImageData();
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      //Orig: DataBuffer db = new DataBufferByte(imageData, imageData.length);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int len = Math.max(imageData.length, (width - 1) * (height -1));
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      DataBuffer db = new DataBufferByte(imageData, len);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      WritableRaster raster = Raster.createPackedRaster(db, width,
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          height, bitsPerPixel, null);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      return raster;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      System.out.println("Unsupported color type!");
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return null;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public byte[] getImageData() {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    try {
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      ByteArrayOutputStream out = new ByteArrayOutputStream();
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      // Write all the IDAT data into the array.
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      for (int i = 0; i < mNumberOfChunks; i++) {
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PNGChunk chunk = mChunks[i];
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (chunk.getTypeString().equals("IDAT")) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          out.write(chunk.getData());
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      out.flush();
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      // Now deflate the data.
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      InflaterInputStream in = new InflaterInputStream(
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          new ByteArrayInputStream(out.toByteArray()));
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream();
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int readLength;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      byte[] block = new byte[8192];
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      while ((readLength = in.read(block)) != -1)
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        inflatedOut.write(block, 0, readLength);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      inflatedOut.flush();
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      byte[] imageData = inflatedOut.toByteArray();
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      // Compute the real length.
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int width = (int) getWidth();
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int height = (int) getHeight();
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int bitsPerPixel = getBitsPerPixel();
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      int length = width * height * bitsPerPixel / 8;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      byte[] prunedData = new byte[length];
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      // We can only deal with non-interlaced images.
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      if (getInterlace() == 0) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int index = 0;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < length; i++) {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          if ((i * 8 / bitsPerPixel) % width == 0) {
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            index++; // Skip the filter byte.
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          prunedData[i] = imageData[index++];
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      } else
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.out.println("Couldn't undo interlacing.");
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      return prunedData;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } catch (IOException ioe) {
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return null;
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public PNGChunk getChunk(String type) {
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < mNumberOfChunks; i++)
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      if (mChunks[i].getTypeString().equals(type))
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mChunks[i];
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return null;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass PNGChunk {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  private byte[] mType;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  private byte[] mData;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public PNGChunk(byte[] type, byte[] data) {
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mType = type;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mData = data;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public String getTypeString() {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    try {
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      return new String(mType, "UTF8");
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } catch (UnsupportedEncodingException uee) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      return "";
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public byte[] getData() {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mData;
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public long getUnsignedInt(int offset) {
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long value = 0;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < 4; i++)
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      value += (mData[offset + i] & 0xff) << ((3 - i) * 8);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return value;
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  public short getUnsignedByte(int offset) {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (short) (mData[offset] & 0x00ff);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}