Декодер PNG формата в Java

Эта подсказка содержит простой декодер PNG исходного кода в Java.


import java.awt.Graphics;

import java.awt.Insets;

import java.awt.image.BufferedImage;

import java.awt.image.ColorModel;

import java.awt.image.DataBuffer;

import java.awt.image.DataBufferByte;

import java.awt.image.IndexColorModel;

import java.awt.image.Raster;

import java.awt.image.WritableRaster;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.DataInputStream;

import java.io.EOFException;

import java.io.IOException;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.util.zip.CRC32;

import java.util.zip.InflaterInputStream;



import javax.swing.JFrame;



public class PNGDecoder {

  public static void main(String[] argsthrows Exception {

    String name = "logo.png";

    if (args.length > 0)

      name = args[0];

    InputStream in = PNGDecoder.class.getResourceAsStream(name);

    final BufferedImage image = PNGDecoder.decode(in);

    in.close();



    JFrame f = new JFrame() {

      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 inthrows 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 = (intwidthLong;

    int height = (intheightLong;



    ColorModel cm = chunks.getColorModel();

    WritableRaster raster = chunks.getRaster();



    BufferedImage image = new BufferedImage(cm, raster, false, null);



    return image;

  }



  protected static void readSignature(DataInputStream inthrows IOException {

    long signature = in.readLong();

    if (signature != 0x89504e470d0a1a0aL)

      throw new IOException("PNG signature not found!");

  }



  protected static PNGData readChunks(DataInputStream inthrows 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);

  }

}



class PNGData {

  private int mNumberOfChunks;



  private PNGChunk[] mChunks;



  public PNGData() {

    mNumberOfChunks = 0;

    mChunks = new PNGChunk[10];

  }



  public void add(PNGChunk chunk) {

    mChunks[mNumberOfChunks++= chunk;

    if (mNumberOfChunks >= mChunks.length) {

      PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10];

      System.arraycopy(mChunks, 0, largerArray, 0, mChunks.length);

      mChunks = largerArray;

    }

  }



  public long getWidth() {

    return getChunk("IHDR").getUnsignedInt(0);

  }



  public long getHeight() {    return getChunk("IHDR").getUnsignedInt(4);

  }



  public short getBitsPerPixel() {

    return getChunk("IHDR").getUnsignedByte(8);

  }



  public short getColorType() {

    return getChunk("IHDR").getUnsignedByte(9);

  }



  public short getCompression() {

    return getChunk("IHDR").getUnsignedByte(10);

  }



  public short getFilter() {

    return getChunk("IHDR").getUnsignedByte(11);

  }



  public short getInterlace() {

    return getChunk("IHDR").getUnsignedByte(12);

  }



  public ColorModel getColorModel() {

    short colorType = getColorType();

    int bitsPerPixel = getBitsPerPixel();



    if (colorType == 3) {

      byte[] paletteData = getChunk("PLTE").getData();

      int paletteLength = paletteData.length / 3;

      return new IndexColorModel(bitsPerPixel, paletteLength,

          paletteData, 0false);

    }

    System.out.println("Unsupported color type: " + colorType);

    return null;

  }



  public WritableRaster getRaster() {

    int width = (intgetWidth();

    int height = (intgetHeight();

    int bitsPerPixel = getBitsPerPixel();

    short colorType = getColorType();



    if (colorType == 3) {

      byte[] imageData = getImageData();

      DataBuffer db = new DataBufferByte(imageData, imageData.length);

      WritableRaster raster = Raster.createPackedRaster(db, width,

          height, bitsPerPixel, null);

      return raster;

    else

      System.out.println("Unsupported color type!");

    return null;

  }



  public byte[] getImageData() {

    try {

      ByteArrayOutputStream out = new ByteArrayOutputStream();

      // Write all the IDAT data into the array.

      for (int i = 0; i < mNumberOfChunks; i++) {

        PNGChunk chunk = mChunks[i];

        if (chunk.getTypeString().equals("IDAT")) {

          out.write(chunk.getData());

        }

      }

      out.flush();

      // Now deflate the data.

      InflaterInputStream in = new InflaterInputStream(

          new ByteArrayInputStream(out.toByteArray()));

      ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream();

      int readLength;

      byte[] block = new byte[8192];

      while ((readLength = in.read(block)) != -1)

        inflatedOut.write(block, 0, readLength);

      inflatedOut.flush();

      byte[] imageData = inflatedOut.toByteArray();

      // Compute the real length.

      int width = (intgetWidth();

      int height = (intgetHeight();

      int bitsPerPixel = getBitsPerPixel();

      int length = width * height * bitsPerPixel / 8;



      byte[] prunedData = new byte[length];



      // We can only deal with non-interlaced images.

      if (getInterlace() == 0) {

        int index = 0;

        for (int i = 0; i < length; i++) {

          if ((i * / bitsPerPixel% width == 0) {

            index++; // Skip the filter byte.

          }

          prunedData[i= imageData[index++];

        }

      else

        System.out.println("Couldn't undo interlacing.");



      return prunedData;

    catch (IOException ioe) {

    }

    return null;

  }



  public PNGChunk getChunk(String type) {

    for (int i = 0; i < mNumberOfChunks; i++)

      if (mChunks[i].getTypeString().equals(type))

        return mChunks[i];

    return null;

  }

}



class PNGChunk {

  private byte[] mType;



  private byte[] mData;



  public PNGChunk(byte[] type, byte[] data) {

    mType = type;

    mData = data;

  }



  public String getTypeString() {

    try {

      return new String(mType, "UTF8");

    catch (UnsupportedEncodingException uee) {

      return "";

    }

  }



  public byte[] getData() {

    return mData;

  }



  public long getUnsignedInt(int offset) {

    long value = 0;

    for (int i = 0; i < 4; i++)

      value += (mData[offset + i0xff<< ((- i8);

    return value;

  }



  public short getUnsignedByte(int offset) {

    return (short) (mData[offset0x00ff);

  }

}

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>