Java/2D Graphics GUI/PNG File — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
 
м (1 версия)
 
(нет различий)

Текущая версия на 09:53, 1 июня 2010

Draw an Image and save to png

<source lang="java"> import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class WriteImageType {

 static public void main(String args[]) throws Exception {
   try {
     int width = 200, height = 200;
     // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
     // into integer pixels
     BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
     Graphics2D ig2 = bi.createGraphics();
     Font font = new Font("TimesRoman", Font.BOLD, 20);
     ig2.setFont(font);
     String message = "www.jexp.ru!";
     FontMetrics fontMetrics = ig2.getFontMetrics();
     int stringWidth = fontMetrics.stringWidth(message);
     int stringHeight = fontMetrics.getAscent();
     ig2.setPaint(Color.black);
     ig2.drawString(message, (width - stringWidth) / 2, height / 2 + stringHeight / 4);
     ImageIO.write(bi, "PNG", new File("c:\\yourImageName.PNG"));
     ImageIO.write(bi, "JPEG", new File("c:\\yourImageName.JPG"));
     ImageIO.write(bi, "gif", new File("c:\\yourImageName.GIF"));
     ImageIO.write(bi, "BMP", new File("c:\\yourImageName.BMP"));
     
   } catch (IOException ie) {
     ie.printStackTrace();
   }
 }

}



 </source>   



Encodes a java.awt.Image into PNG format

<source lang="java"> /*

* This file is part of the Echo Web Application Framework (hereinafter "Echo").
* Copyright (C) 2002-2009 NextApp, Inc.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*/

import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.IndexColorModel; import java.awt.image.PixelGrabber; import java.awt.image.Raster; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.zip.CheckedOutputStream; import java.util.zip.Checksum; import java.util.zip.CRC32; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import javax.swing.ImageIcon; /**

* Encodes a java.awt.Image into PNG format.
* For more information on the PNG specification, see the W3C PNG page at 
* .
*/

public class PngEncoder {

   /**
    * Utility class for converting Images to BufferedImages.
    */
   private static class ImageToBufferedImage {
   
       /**
        * Converts an Image to a BufferedImage.
        * If the image is already a BufferedImage, the original is returned.
        * 
        * @param image the image to convert
        * @return the image as a BufferedImage
        */
       static BufferedImage toBufferedImage(Image image) {
           if (image instanceof BufferedImage) {
               // Return image unchanged if it is already a BufferedImage.
               return (BufferedImage) image;
           }
           
           // Ensure image is loaded.
           image = new ImageIcon(image).getImage();        
           
           int type = hasAlpha(image) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
           BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
           Graphics g = bufferedImage.createGraphics();
           g.drawImage(image, 0, 0, null);
           g.dispose();
           
           return bufferedImage;
       }
       
       /**
        * Determines if an image has an alpha channel.
        * 
        * @param image the Image
        * @return true if the image has an alpha channel
        */
       static boolean hasAlpha(Image image) {
           PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
           try {
               pg.grabPixels();
           } catch (InterruptedException ex) { }
           return pg.getColorModel().hasAlpha();
       }
   }
   /** SubFilter singleton. */
   public static final Filter SUB_FILTER = new SubFilter();
   
   /** UpFilter singleton. */
   public static final Filter UP_FILTER = new UpFilter();
   
   /** AverageFilter singleton. */
   public static final Filter AVERAGE_FILTER = new AverageFilter();
   /** PaethFilter singleton. */
   public static final Filter PAETH_FILTER = new PaethFilter();
   
   /** PNG signature bytes. */
   private static final byte[] SIGNATURE = { (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, 
                                             (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a };
   
   /** Image header (IHDR) chunk header. */
   private static final byte[] IHDR = { (byte) "I", (byte) "H", (byte) "D", (byte) "R" };
   
   /** Palate (PLTE) chunk header. */
   private static final byte[] PLTE = { (byte) "P", (byte) "L", (byte) "T", (byte) "E" };
   
   /** Image Data (IDAT) chunk header. */
   private static final byte[] IDAT = { (byte) "I", (byte) "D", (byte) "A", (byte) "T" };
   
   /** End-of-file (IEND) chunk header. */
   private static final byte[] IEND = { (byte) "I", (byte) "E", (byte) "N", (byte) "D" };
   
   /** Sub filter type constant. */
   private static final int SUB_FILTER_TYPE = 1;
   /** Up filter type constant. */
   private static final int UP_FILTER_TYPE = 2;
   
   /** Average filter type constant. */
   private static final int AVERAGE_FILTER_TYPE = 3;
   /** Paeth filter type constant. */
   private static final int PAETH_FILTER_TYPE = 4;
   /** Image bit depth. */
   private static final byte BIT_DEPTH = (byte) 8;
   /** Indexed color type rendered value. */
   private static final byte COLOR_TYPE_INDEXED  = (byte) 3;
   
   /** RGB color type rendered value. */
   private static final byte COLOR_TYPE_RGB      = (byte) 2;
   
   /** RGBA color type rendered value. */
   private static final byte COLOR_TYPE_RGBA     = (byte) 6;
   /** Integer-to-integer map used for RGBA/ARGB conversion. */
   private static final int[] INT_TRANSLATOR_CHANNEL_MAP = new int[]{2, 1, 0, 3};
   
   /**
    * Writes an 32-bit integer value to the output stream.
    *
    * @param out the stream
    * @param i the value
    */
   private static void writeInt(OutputStream out, int i) 
   throws IOException {
       out.write(new byte[]{(byte) (i >> 24), 
                            (byte) ((i >> 16) & 0xff), 
                            (byte) ((i >> 8) & 0xff), 
                            (byte) (i & 0xff)});
   }
   /**
    * An interface for PNG filters.  Filters are used to modify the method in 
    * which pixels of the image are stored in ways that will achieve better
    * compression.
    */ 
   public interface Filter {
   
       /** 
        * Filters the data in a given row of the image.
        *
        * @param currentRow a byte array containing the data of the row of the
        *        image to be filtered
        * @param previousRow a byte array containing the data of the previous 
        *        row of the image to be filtered
        * @param filterOutput a byte array into which the filtered data will
        *        be placed
        */
       public void filter(byte[] filterOutput, byte[] currentRow, byte[] previousRow, int outputBpp);
       
       /**
        * Returns the PNG type code for the filter.
        */
       public int getType();
   }
   
   /**
    * An implementation of a "Sub" filter.
    */
   private static class SubFilter
   implements Filter {
   
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#filter(byte[], byte[], byte[], int)
        */
       public void filter(byte[] filterOutput, byte[] currentRow, byte[] previousRow, int outputBpp) {
           for (int index = 0; index < filterOutput.length; ++index) {
               if (index < outputBpp) {
                   filterOutput[index] = currentRow[index];
               } else {
                   filterOutput[index] = (byte) (currentRow[index] - currentRow[index - outputBpp]);
               }
           }
       }
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#getType()
        */
       public int getType() {
           return SUB_FILTER_TYPE;
       }
   }
       
   /**
    * An implementation of an "Up" filter.
    */
   private static class UpFilter
   implements Filter {
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#filter(byte[], byte[], byte[], int)
        */
       public void filter(byte[] filterOutput, byte[] currentRow, byte[] previousRow, int outputBpp) {
           for (int index = 0; index < currentRow.length; ++index) {
               filterOutput[index] = (byte) (currentRow[index] - previousRow[index]);
           }
       }
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#getType()
        */
       public int getType() {
           return UP_FILTER_TYPE;
       }
   }
   
   /**
    * An implementation of an "Average" filter.
    */
   private static class AverageFilter
   implements Filter {
       
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#filter(byte[], byte[], byte[], int)
        */
       public void filter(byte[] filterOutput, byte[] currentRow, byte[] previousRow, int outputBpp) {
           int w, n;
           
           for (int index = 0; index < filterOutput.length; ++index) {
               n = (previousRow[index] + 0x100) & 0xff;
               if (index < outputBpp) {
                   w = 0;
               } else {
                   w = (currentRow[index - outputBpp] + 0x100) & 0xff;
               }
               filterOutput[index] = (byte) (currentRow[index] - (byte) ((w + n) / 2));
           }
       }
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#getType()
        */
       public int getType() {
           return AVERAGE_FILTER_TYPE;
       }
   }
   /**
    * An implementation of a "Paeth" filter.
    */
   private static class PaethFilter
   implements Filter {
   
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#filter(byte[], byte[], byte[], int)
        */
       public void filter(byte[] filterOutput, byte[] currentRow, byte[] previousRow, int outputBpp) {
           byte pv;
           int  n, w, nw, p, pn, pw, pnw;
           
           for (int index = 0; index < filterOutput.length; ++index) {
               n = (previousRow[index] + 0x100) & 0xff;
               if (index < outputBpp) {
                   w = 0;
                   nw = 0;
               } else {
                   w = (currentRow[index - outputBpp] + 0x100) & 0xff;
                   nw = (previousRow[index - outputBpp] + 0x100) & 0xff;
               }
               
               p = w + n - nw;
               pw = Math.abs(p - w);
               pn = Math.abs(p - n);
               pnw = Math.abs(p - w);
               if (pw <= pn && pw <= pnw) {
                   pv = (byte) w;
               } else if (pn <= pnw) {
                   pv = (byte) n;
               } else {
                   pv = (byte) nw;
               }
               
               filterOutput[index] = (byte) (currentRow[index] - pv);
           }
       }
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Filter#getType()
        */
       public int getType() {
           return PAETH_FILTER_TYPE;
       }
   }
   
   /**
    * An interface for translators, which translate pixel data from a 
    * writable raster into an R/G/B/A ordering required by the PNG
    * specification.  Pixel data in the raster might be available
    * in three bytes per pixel, four bytes per pixel, or as integers.
    */
   interface Translator {
   
       /**
        * Translates a row of the image into a byte array ordered
        * properly for a PNG image.
        *
        * @param outputPixelQueue the byte array in which to store the
        *        translated pixels
        * @param row the row index of the image to translate
        */
       public void translate(byte[] outputPixelQueue, int row);
   }
   
   /**
    * Translates byte-based rasters.
    */
   private class ByteTranslator 
   implements Translator {
   
       int rowWidth = width * outputBpp;                         // size of image data in a row in bytes.
       byte[] inputPixelQueue = new byte[rowWidth + outputBpp];
       int column;
       int channel;
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Translator#translate(byte[], int)
        */
       public void translate(byte[] outputPixelQueue, int row) {
           raster.getDataElements(0, row, width, 1, inputPixelQueue);
           for (column = 0; column < width; ++column) {
               for (channel = 0; channel < outputBpp; ++channel) {
                   outputPixelQueue[column * outputBpp + channel]
                           = inputPixelQueue[column * inputBpp + channel];
               }
           }
       }
   }
   
   /**
    * Translates integer-based rasters.
    */
   private class IntTranslator
   implements Translator  {
   
       int[] inputPixelQueue = new int[width];
       int column;
       int channel;
       /**
        * @see nextapp.echo.webcontainer.util.PngEncoder.Translator#translate(byte[], int)
        */
       public void translate(byte[] outputPixelQueue, int row) {
       
           image.getRGB(0, row, width, 1, inputPixelQueue, 0, width);
           // Line below (commented out) replaces line above, almost halving time to encode, but doesn"t work with certain pixel 
           // arrangements.  Need to find method of determining pixel order (BGR vs RGB, ARGB, etc)
           //
           // raster.getDataElements(0, row, width, 1, inputPixelQueue);
           for (column = 0; column < width; ++column) {
               for (channel = 0; channel < outputBpp; ++channel) {
                   outputPixelQueue[column * outputBpp + channel]
                           = (byte) (inputPixelQueue[column] >> (INT_TRANSLATOR_CHANNEL_MAP[channel] * 8));
               }
           }
       }
   }
   
   /** The image being encoded. */
   private BufferedImage image;
   
   /** The PNG encoding filter to be used. */
   private Filter filter;
   
   /** The the deflater compression level. */
   private int compressionLevel;
   
   /** The pixel width of the image. */
   private int width;
   
   /** The pixel height of the image. */
   private int height;
   
   /** The image Raster transfer type. */
   private int transferType;
   
   /** The image Raster data. */
   private Raster raster;
   
   /** The source image bits-per-pixel. */
   private int inputBpp;
   
   /** The encoded image bits-per-pixel. */
   private int outputBpp;
   
   /** The Translator being used for encoding. */
   private Translator translator;
   
   /**
    * Creates a PNG encoder for an image.
    *
    * @param image the image to be encoded
    * @param encodeAlpha true if the image"s alpha channel should be encoded
    * @param filter The filter to be applied to the image data, one of the 
    *        following values:
*
    *
  • SUB_FILTER
  • *
  • UP_FILTER
  • *
  • AVERAGE_FILTER
  • *
  • PAETH_FILTER
  • *
    *        If a null value is specified, no filtering will be performed.
    * @param compressionLevel the deflater compression level that will be used
    *        for compressing the image data:  Valid values range from 0 to 9.
    *        Higher values result in smaller files and therefore decrease
    *        network traffic, but require more CPU time to encode.  The normal
    *        compromise value is 3.
    */
   public PngEncoder(Image image, boolean encodeAlpha, Filter filter, int compressionLevel) {
       super();
       
       this.image = ImageToBufferedImage.toBufferedImage(image);
       this.filter = filter;
       this.rupressionLevel = compressionLevel;
       
       width = this.image.getWidth(null);
       height = this.image.getHeight(null);
       raster = this.image.getRaster();
       transferType = raster.getTransferType();
       // Establish storage information
       int dataBytes = raster.getNumDataElements();
       if (transferType == DataBuffer.TYPE_BYTE && dataBytes == 4) {
           outputBpp = encodeAlpha ? 4 : 3;
           inputBpp = 4;
           translator = new ByteTranslator();
       } else if (transferType == DataBuffer.TYPE_BYTE && dataBytes == 3) {
           outputBpp = 3;
           inputBpp = 3;
           encodeAlpha = false;
           translator = new ByteTranslator();
       } else if (transferType == DataBuffer.TYPE_INT && dataBytes == 1) {
           outputBpp = encodeAlpha ? 4 : 3;
           inputBpp = 4;
           translator = new IntTranslator();
       } else if (transferType == DataBuffer.TYPE_BYTE && dataBytes == 1) {
           throw new UnsupportedOperationException("Encoding indexed-color images not yet supported.");
       } else {
           throw new IllegalArgumentException(
                   "Cannot determine appropriate bits-per-pixel for provided image.");
       }
   }
   
   /**
    * Encodes the image.
    *
    * @param out an OutputStream to which the encoded image will be
    *            written
    * @throws IOException if a problem is encountered writing the output
    */
   public synchronized void encode(OutputStream out) 
   throws IOException {
       Checksum csum = new CRC32();
       out = new CheckedOutputStream(out, csum);
   
       out.write(SIGNATURE);
       writeIhdrChunk(out, csum);
       if (outputBpp == 1) {
           writePlteChunk(out, csum);
       }
       
       writeIdatChunks(out, csum);
       
       writeIendChunk(out, csum);
   }
   
   /**
    * Writes the IDAT (Image data) chunks to the output stream.
    *
    * @param out the OutputStream to write the chunk to
    * @param csum the Checksum that is updated as data is written
    *             to the passed-in OutputStream
    * @throws IOException if a problem is encountered writing the output
    */
   private void writeIdatChunks(OutputStream out, Checksum csum)
   throws IOException {
       int rowWidth = width * outputBpp;                         // size of image data in a row in bytes.
       int row = 0;
               
       Deflater deflater = new Deflater(compressionLevel);
       ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
       DeflaterOutputStream defOut = new DeflaterOutputStream(byteOut, deflater);
       byte[] filteredPixelQueue = new byte[rowWidth];
       // Output Pixel Queues
       byte[][] outputPixelQueue = new byte[2][rowWidth];
       Arrays.fill(outputPixelQueue[1], (byte) 0);
       int outputPixelQueueRow = 0;
       int outputPixelQueuePrevRow = 1;
       while (row < height) {
           if (filter == null) {
               defOut.write(0);
               translator.translate(outputPixelQueue[outputPixelQueueRow], row);
               defOut.write(outputPixelQueue[outputPixelQueueRow], 0, rowWidth);
           } else {
               defOut.write(filter.getType());
               translator.translate(outputPixelQueue[outputPixelQueueRow], row);
               filter.filter(filteredPixelQueue, outputPixelQueue[outputPixelQueueRow], 
                       outputPixelQueue[outputPixelQueuePrevRow], outputBpp);
               defOut.write(filteredPixelQueue, 0, rowWidth);
           }
           
           ++row;
           outputPixelQueueRow = row & 1;
           outputPixelQueuePrevRow = outputPixelQueueRow ^ 1;
       }
       defOut.finish();
       byteOut.close();
       
       writeInt(out, byteOut.size());
       csum.reset();
       out.write(IDAT);
       byteOut.writeTo(out);
       writeInt(out, (int) csum.getValue());
   }
   
   /**
    * Writes the IEND (End-of-file) chunk to the output stream.
    *
    * @param out the OutputStream to write the chunk to
    * @param csum the Checksum that is updated as data is written
    *             to the passed-in OutputStream
    * @throws IOException if a problem is encountered writing the output
    */
   private void writeIendChunk(OutputStream out, Checksum csum)
   throws IOException {
       writeInt(out, 0);
       csum.reset();
       out.write(IEND);
       writeInt(out, (int) csum.getValue());
   }
   
   /**
    * writes the IHDR (Image Header) chunk to the output stream
    *
    * @param out the OutputStream to write the chunk to
    * @param csum the Checksum that is updated as data is written
    *             to the passed-in OutputStream
    * @throws IOException if a problem is encountered writing the output
    */ 
   private void writeIhdrChunk(OutputStream out, Checksum csum) 
   throws IOException {
       writeInt(out, 13); // Chunk Size
       csum.reset();
       out.write(IHDR);
       writeInt(out, width);
       writeInt(out, height);
       out.write(BIT_DEPTH);
       switch (outputBpp) {
       case 1:
           out.write(COLOR_TYPE_INDEXED);
           break;
       case 3:
           out.write(COLOR_TYPE_RGB);
           break;
       case 4:
           out.write(COLOR_TYPE_RGBA);
           break;
       default:
           throw new IllegalStateException("Invalid bytes per pixel");
       }
       out.write(0); // Compression Method
       out.write(0); // Filter Method
       out.write(0); // Interlace
       writeInt(out, (int) csum.getValue());
   }
   
   /**
    * Writes the PLTE (Palate) chunk to the output stream.
    *
    * @param out the OutputStream to write the chunk to
    * @param csum the Checksum that is updated as data is written
    *             to the passed-in OutputStream
    * @throws IOException if a problem is encountered writing the output
    */
   private void writePlteChunk(OutputStream out, Checksum csum) 
   throws IOException {
       IndexColorModel icm = (IndexColorModel) image.getColorModel();
       
       writeInt(out, 768); // Chunk Size
       csum.reset();
       out.write(PLTE);
       
       byte[] reds = new byte[256];
       icm.getReds(reds);
       
       byte[] greens = new byte[256];
       icm.getGreens(greens);
       
       byte[] blues = new byte[256];
       icm.getBlues(blues);
       
       for (int index = 0; index < 256; ++index) {
           out.write(reds[index]);
           out.write(greens[index]);
           out.write(blues[index]);
       }
               
       writeInt(out, (int) csum.getValue());
   }

}


 </source>   



PNG Decoder

<source lang="java"> /*

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s): Alexandre Iline.
*
* The Original Software is the Jemmy library.
* The Initial Developer of the Original Software is Alexandre Iline.
* All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
*
*
* $Id$ $Revision$ $Date$
*
*/

import java.awt.AWTException; import java.awt.Color; import java.awt.ruponent; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.CRC32; import java.util.zip.DataFormatException; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.Inflater; /**

* Allows to load PNG graphical file.
* @author Alexandre Iline
*/

public class PNGDecoder extends Object {

   InputStream in;
   /**
    * Constructs a PNGDecoder object.
    * @param in input stream to read PNG image from.
    */    
   public PNGDecoder(InputStream in) {
       this.in = in;
   }
   byte read() throws IOException {
       byte b = (byte)in.read();
       return(b);
   }
   int readInt() throws IOException {
       byte b[] = read(4);
       return(((b[0]&0xff)<<24) +
              ((b[1]&0xff)<<16) +
              ((b[2]&0xff)<<8) +
              ((b[3]&0xff)));
   }
   byte[] read(int count) throws IOException {
       byte[] result = new byte[count];
       for(int i = 0; i < count; i++) {
           result[i] = read();
       }
       return(result);
   }
   boolean compare(byte[] b1, byte[] b2) {
       if(b1.length != b2.length) {
           return(false);
       }
       for(int i = 0; i < b1.length; i++) {
           if(b1[i] != b2[i]) {
               return(false);
           }
       }
       return(true);
   }
   void checkEquality(byte[] b1, byte[] b2) {
       if(!compare(b1, b2)) {
           throw(new RuntimeException("Format error"));
       }
   }
   /**
    * Decodes image from an input stream passed into constructor.
    * @return a BufferedImage object
    * @throws IOException
    */
   public BufferedImage decode() throws IOException {
       byte[] id = read(12);
       checkEquality(id, new byte[] {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13});
       byte[] ihdr = read(4);
       checkEquality(ihdr, "IHDR".getBytes());
       int width = readInt();
       int height = readInt();
       BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
       byte[] head = read(5);
       int mode;
       if(compare(head, new byte[]{1, 0, 0, 0, 0})) {
           mode = PNGEncoder.BW_MODE;
       } else if(compare(head, new byte[]{8, 0, 0, 0, 0})) {
           mode = PNGEncoder.GREYSCALE_MODE;
       } else if(compare(head, new byte[]{8, 2, 0, 0, 0})) {
           mode = PNGEncoder.COLOR_MODE;
       } else {
           throw(new RuntimeException("Format error"));
       }
       readInt();//!!crc
       int size = readInt();
       byte[] idat = read(4);
       checkEquality(idat, "IDAT".getBytes());
       byte[] data = read(size);
       Inflater inflater = new Inflater();
       inflater.setInput(data, 0, size);
       int color;
       try {
           switch (mode) {
           case PNGEncoder.BW_MODE: 
               {
                   int bytes = (int)(width / 8);
                   if((width % 8) != 0) {
                       bytes++;
                   }
                   byte colorset;
                   byte[] row = new byte[bytes];
                   for (int y = 0; y < height; y++) {
                       inflater.inflate(new byte[1]);
                       inflater.inflate(row);
                       for (int x = 0; x < bytes; x++) {
                           colorset = row[x];
                           for (int sh = 0; sh < 8; sh++) {
                               if(x * 8 + sh >= width) {
                                   break;
                               }
                               if((colorset & 0x80) == 0x80) {
                                   result.setRGB(x * 8 + sh, y, Color.white.getRGB());
                               } else {
                                   result.setRGB(x * 8 + sh, y, Color.black.getRGB());
                               }
                               colorset <<= 1;
                           }
                       }
                   }
               }
               break;
           case PNGEncoder.GREYSCALE_MODE: 
               {
                   byte[] row = new byte[width];
                   for (int y = 0; y < height; y++) {
                       inflater.inflate(new byte[1]);
                       inflater.inflate(row);
                       for (int x = 0; x < width; x++) {
                           color = row[x];
                           result.setRGB(x, y, (color << 16) + (color << 8) + color);
                       }
                   }
               }
               break;
           case PNGEncoder.COLOR_MODE:
               {
                   byte[] row = new byte[width * 3];
                   for (int y = 0; y < height; y++) {
                       inflater.inflate(new byte[1]);
                       inflater.inflate(row);
                       for (int x = 0; x < width; x++) {
                           result.setRGB(x, y, 
                                         ((row[x * 3 + 0]&0xff) << 16) +
                                         ((row[x * 3 + 1]&0xff) << 8) +
                                         ((row[x * 3 + 2]&0xff)));
                       }
                   }
               }
           }
       } catch(DataFormatException e) {
           throw(new RuntimeException("ZIP error"+e));
       }
       readInt();//!!crc
       readInt();//0
       byte[] iend = read(4);
       checkEquality(iend, "IEND".getBytes());
       readInt();//!!crc
       in.close();
       return(result);
   }
   /**
    * Decodes image from file.
    * @param fileName a file to read image from
    * @return a BufferedImage instance.
    */
   public static BufferedImage decode(String fileName) {
       try {
           return(new PNGDecoder(new FileInputStream(fileName)).decode());
       } catch(IOException e) {
           throw(new RuntimeException("IOException during image reading"+ e));
       }
   }

} class PNGEncoder extends Object {

 /** black and white image mode. */    
 public static final byte BW_MODE = 0;
 /** grey scale image mode. */    
 public static final byte GREYSCALE_MODE = 1;
 /** full color image mode. */    
 public static final byte COLOR_MODE = 2;
 
 OutputStream out;
 CRC32 crc;
 byte mode;
 /** public constructor of PNGEncoder class with greyscale mode by default.
  * @param out output stream for PNG image format to write into
  */    
 public PNGEncoder(OutputStream out) {
     this(out, GREYSCALE_MODE);
 }
 /** public constructor of PNGEncoder class.
  * @param out output stream for PNG image format to write into
  * @param mode BW_MODE, GREYSCALE_MODE or COLOR_MODE
  */    
 public PNGEncoder(OutputStream out, byte mode) {
     crc=new CRC32();
     this.out = out;
     if (mode<0 || mode>2)
         throw new IllegalArgumentException("Unknown color mode");
     this.mode = mode;
 }
 void write(int i) throws IOException {
     byte b[]={(byte)((i>>24)&0xff),(byte)((i>>16)&0xff),(byte)((i>>8)&0xff),(byte)(i&0xff)};
     write(b);
 }
 void write(byte b[]) throws IOException {
     out.write(b);
     crc.update(b);
 }
 
 /** main encoding method (stays blocked till encoding is finished).
  * @param image BufferedImage to encode
  * @throws IOException IOException
  */    
 public void encode(BufferedImage image) throws IOException {
     int width = image.getWidth(null);
     int height = image.getHeight(null);
     final byte id[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13};
     write(id);
     crc.reset();
     write("IHDR".getBytes());
     write(width);
     write(height);
     byte head[]=null;
     switch (mode) {
         case BW_MODE: head=new byte[]{1, 0, 0, 0, 0}; break;
         case GREYSCALE_MODE: head=new byte[]{8, 0, 0, 0, 0}; break;
         case COLOR_MODE: head=new byte[]{8, 2, 0, 0, 0}; break;
     }                 
     write(head);
     write((int) crc.getValue());
     ByteArrayOutputStream compressed = new ByteArrayOutputStream(65536);
     BufferedOutputStream bos = new BufferedOutputStream( new DeflaterOutputStream(compressed, new Deflater(9)));
     int pixel;
     int color;
     int colorset;
     switch (mode) {
         case BW_MODE: 
             int rest=width%8;
             int bytes=width/8;
             for (int y=0;y<height;y++) {
                 bos.write(0);
                 for (int x=0;x<bytes;x++) {
                     colorset=0;
                     for (int sh=0; sh<8; sh++) {
                         pixel=image.getRGB(x*8+sh,y);
                         color=((pixel >> 16) & 0xff);
                         color+=((pixel >> 8) & 0xff);
                         color+=(pixel & 0xff);
                         colorset<<=1;
                         if (color>=3*128)
                             colorset|=1;
                     }
                     bos.write((byte)colorset);
                 }
                 if (rest>0) {
                     colorset=0;
                     for (int sh=0; sh<width%8; sh++) {
                         pixel=image.getRGB(bytes*8+sh,y);
                         color=((pixel >> 16) & 0xff);
                         color+=((pixel >> 8) & 0xff);
                         color+=(pixel & 0xff);
                         colorset<<=1;
                         if (color>=3*128)
                             colorset|=1;
                     }
                     colorset<<=8-rest;
                     bos.write((byte)colorset);
                 }
             }
             break;
         case GREYSCALE_MODE: 
             for (int y=0;y<height;y++) {
                 bos.write(0);
                 for (int x=0;x<width;x++) {
                     pixel=image.getRGB(x,y);
                     color=((pixel >> 16) & 0xff);
                     color+=((pixel >> 8) & 0xff);
                     color+=(pixel & 0xff);
                     bos.write((byte)(color/3));
                 }
             }
             break;
          case COLOR_MODE:
             for (int y=0;y<height;y++) {
                 bos.write(0);
                 for (int x=0;x<width;x++) {
                     pixel=image.getRGB(x,y);
                     bos.write((byte)((pixel >> 16) & 0xff));
                     bos.write((byte)((pixel >> 8) & 0xff));
                     bos.write((byte)(pixel & 0xff));
                 }
             }
             break;
     }
     bos.close();
     write(compressed.size());
     crc.reset();
     write("IDAT".getBytes());
     write(compressed.toByteArray());
     write((int) crc.getValue()); 
     write(0);
     crc.reset();
     write("IEND".getBytes());
     write((int) crc.getValue()); 
     out.close();
 }
 /** Static method performing screen capture into PNG image format file with given fileName.
  * @param rect Rectangle of screen to be captured
  * @param fileName file name for screen capture PNG image file */    
 public static void captureScreen(Rectangle rect, String fileName) {
     captureScreen(rect, fileName, GREYSCALE_MODE);
 }
 /** Static method performing screen capture into PNG image format file with given fileName.
  * @param rect Rectangle of screen to be captured
  * @param mode image color mode
  * @param fileName file name for screen capture PNG image file */    
 public static void captureScreen(Rectangle rect, String fileName, byte mode) {
     try {
         BufferedImage capture=new Robot().createScreenCapture(rect);
         BufferedOutputStream file=new BufferedOutputStream(new FileOutputStream(fileName));
         PNGEncoder encoder=new PNGEncoder(file, mode);
         encoder.encode(capture);
     } catch (AWTException awte) {
         awte.printStackTrace();
     } catch (IOException ioe) {
         ioe.printStackTrace();
     }
 }
  /** Static method performing one component screen capture into PNG image format file with given fileName.
   * @param comp Component to be captured
   * @param fileName String image target filename */    
 public static void captureScreen(Component comp, String fileName) {
     captureScreen(comp, fileName, GREYSCALE_MODE);
 }
 
 /** Static method performing one component screen capture into PNG image format file with given fileName.
  * @param comp Component to be captured
  * @param fileName String image target filename
  * @param mode image color mode */    
 public static void captureScreen(Component comp, String fileName, byte mode) {

captureScreen(new Rectangle(comp.getLocationOnScreen(),

         comp.getSize()),
       fileName, mode);
 }
 
 /** Static method performing whole screen capture into PNG image format file with given fileName.
  * @param fileName String image target filename */    
 public static void captureScreen(String fileName) {
     captureScreen(fileName, GREYSCALE_MODE);
 }
 
 /** Static method performing whole screen capture into PNG image format file with given fileName.
  * @param fileName String image target filename
  * @param mode image color mode */    
 public static void captureScreen(String fileName, byte mode) {

captureScreen(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()), fileName, mode);

 }

}

 </source>   



PNG Encoder

<source lang="java"> /*

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s): Alexandre Iline.
*
* The Original Software is the Jemmy library.
* The Initial Developer of the Original Software is Alexandre Iline.
* All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
*
*
* $Id$ $Revision$ $Date$
*
*/

import java.awt.AWTException; import java.awt.ruponent; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.zip.CRC32; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.Inflater; /** This class allows to encode BufferedImage into B/W, greyscale or true color PNG

* image format with maximum compression.
* It also provides complete functionality for capturing full screen, part of * screen or single component, encoding and saving captured image info PNG file. * @author Adam Sotona * @version 1.0 */

public class PNGEncoder extends Object {

   /** black and white image mode. */    
   public static final byte BW_MODE = 0;
   /** grey scale image mode. */    
   public static final byte GREYSCALE_MODE = 1;
   /** full color image mode. */    
   public static final byte COLOR_MODE = 2;
   
   OutputStream out;
   CRC32 crc;
   byte mode;
   /** public constructor of PNGEncoder class with greyscale mode by default.
    * @param out output stream for PNG image format to write into
    */    
   public PNGEncoder(OutputStream out) {
       this(out, GREYSCALE_MODE);
   }
   /** public constructor of PNGEncoder class.
    * @param out output stream for PNG image format to write into
    * @param mode BW_MODE, GREYSCALE_MODE or COLOR_MODE
    */    
   public PNGEncoder(OutputStream out, byte mode) {
       crc=new CRC32();
       this.out = out;
       if (mode<0 || mode>2)
           throw new IllegalArgumentException("Unknown color mode");
       this.mode = mode;
   }
   void write(int i) throws IOException {
       byte b[]={(byte)((i>>24)&0xff),(byte)((i>>16)&0xff),(byte)((i>>8)&0xff),(byte)(i&0xff)};
       write(b);
   }
   void write(byte b[]) throws IOException {
       out.write(b);
       crc.update(b);
   }
   
   /** main encoding method (stays blocked till encoding is finished).
    * @param image BufferedImage to encode
    * @throws IOException IOException
    */    
   public void encode(BufferedImage image) throws IOException {
       int width = image.getWidth(null);
       int height = image.getHeight(null);
       final byte id[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13};
       write(id);
       crc.reset();
       write("IHDR".getBytes());
       write(width);
       write(height);
       byte head[]=null;
       switch (mode) {
           case BW_MODE: head=new byte[]{1, 0, 0, 0, 0}; break;
           case GREYSCALE_MODE: head=new byte[]{8, 0, 0, 0, 0}; break;
           case COLOR_MODE: head=new byte[]{8, 2, 0, 0, 0}; break;
       }                 
       write(head);
       write((int) crc.getValue());
       ByteArrayOutputStream compressed = new ByteArrayOutputStream(65536);
       BufferedOutputStream bos = new BufferedOutputStream( new DeflaterOutputStream(compressed, new Deflater(9)));
       int pixel;
       int color;
       int colorset;
       switch (mode) {
           case BW_MODE: 
               int rest=width%8;
               int bytes=width/8;
               for (int y=0;y<height;y++) {
                   bos.write(0);
                   for (int x=0;x<bytes;x++) {
                       colorset=0;
                       for (int sh=0; sh<8; sh++) {
                           pixel=image.getRGB(x*8+sh,y);
                           color=((pixel >> 16) & 0xff);
                           color+=((pixel >> 8) & 0xff);
                           color+=(pixel & 0xff);
                           colorset<<=1;
                           if (color>=3*128)
                               colorset|=1;
                       }
                       bos.write((byte)colorset);
                   }
                   if (rest>0) {
                       colorset=0;
                       for (int sh=0; sh<width%8; sh++) {
                           pixel=image.getRGB(bytes*8+sh,y);
                           color=((pixel >> 16) & 0xff);
                           color+=((pixel >> 8) & 0xff);
                           color+=(pixel & 0xff);
                           colorset<<=1;
                           if (color>=3*128)
                               colorset|=1;
                       }
                       colorset<<=8-rest;
                       bos.write((byte)colorset);
                   }
               }
               break;
           case GREYSCALE_MODE: 
               for (int y=0;y<height;y++) {
                   bos.write(0);
                   for (int x=0;x<width;x++) {
                       pixel=image.getRGB(x,y);
                       color=((pixel >> 16) & 0xff);
                       color+=((pixel >> 8) & 0xff);
                       color+=(pixel & 0xff);
                       bos.write((byte)(color/3));
                   }
               }
               break;
            case COLOR_MODE:
               for (int y=0;y<height;y++) {
                   bos.write(0);
                   for (int x=0;x<width;x++) {
                       pixel=image.getRGB(x,y);
                       bos.write((byte)((pixel >> 16) & 0xff));
                       bos.write((byte)((pixel >> 8) & 0xff));
                       bos.write((byte)(pixel & 0xff));
                   }
               }
               break;
       }
       bos.close();
       write(compressed.size());
       crc.reset();
       write("IDAT".getBytes());
       write(compressed.toByteArray());
       write((int) crc.getValue()); 
       write(0);
       crc.reset();
       write("IEND".getBytes());
       write((int) crc.getValue()); 
       out.close();
   }
   /** Static method performing screen capture into PNG image format file with given fileName.
    * @param rect Rectangle of screen to be captured
    * @param fileName file name for screen capture PNG image file */    
   public static void captureScreen(Rectangle rect, String fileName) {
       captureScreen(rect, fileName, GREYSCALE_MODE);
   }
   /** Static method performing screen capture into PNG image format file with given fileName.
    * @param rect Rectangle of screen to be captured
    * @param mode image color mode
    * @param fileName file name for screen capture PNG image file */    
   public static void captureScreen(Rectangle rect, String fileName, byte mode) {
       try {
           BufferedImage capture=new Robot().createScreenCapture(rect);
           BufferedOutputStream file=new BufferedOutputStream(new FileOutputStream(fileName));
           PNGEncoder encoder=new PNGEncoder(file, mode);
           encoder.encode(capture);
       } catch (AWTException awte) {
           awte.printStackTrace();
       } catch (IOException ioe) {
           ioe.printStackTrace();
       }
   }
    /** Static method performing one component screen capture into PNG image format file with given fileName.
     * @param comp Component to be captured
     * @param fileName String image target filename */    
   public static void captureScreen(Component comp, String fileName) {
       captureScreen(comp, fileName, GREYSCALE_MODE);
   }
   
   /** Static method performing one component screen capture into PNG image format file with given fileName.
    * @param comp Component to be captured
    * @param fileName String image target filename
    * @param mode image color mode */    
   public static void captureScreen(Component comp, String fileName, byte mode) {
 captureScreen(new Rectangle(comp.getLocationOnScreen(),
           comp.getSize()),
         fileName, mode);
   }
   
   /** Static method performing whole screen capture into PNG image format file with given fileName.
    * @param fileName String image target filename */    
   public static void captureScreen(String fileName) {
       captureScreen(fileName, GREYSCALE_MODE);
   }
   
   /** Static method performing whole screen capture into PNG image format file with given fileName.
    * @param fileName String image target filename
    * @param mode image color mode */    
   public static void captureScreen(String fileName, byte mode) {
 captureScreen(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()), fileName, mode);
   }

}

 </source>   



PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file

<source lang="java">

import java.awt.Image; import java.awt.image.ImageObserver; import java.awt.image.PixelGrabber; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.CRC32; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; /**

* PngEncoder takes a Java Image object and creates a byte string which can be
* saved as a PNG file.  The Image is presumed to use the DirectColorModel.
*
*

Thanks to Jay Denny at KeyPoint Software * http://www.keypoint.ru/ * who let me develop this code on company time.

*
*

You may contact me with (probably very-much-needed) improvements, * comments, and bug fixes at:

*
*

david@catcode.ru

*
*

This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version.

*
*

This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details.

*
*

You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. A copy of the GNU LGPL may be found at * http://www.gnu.org/copyleft/lesser.html

*
* @author J. David Eisenberg
* @version 1.5, 19 Oct 2003
*
* CHANGES:
* --------
* 19-Nov-2002 : CODING STYLE CHANGES ONLY (by David Gilbert for Object
*               Refinery Limited);
* 19-Sep-2003 : Fix for platforms using EBCDIC (contributed by Paulo Soares);
* 19-Oct-2003 : Change private fields to protected fields so that
*               PngEncoderB can inherit them (JDE)
*               Fixed bug with calculation of nRows
* 15-Aug-2008 : Added scrunch.end() in writeImageData() method - see
*               JFreeChart bug report 2037930 (David Gilbert);
*/

public class PngEncoder {

   /** Constant specifying that alpha channel should be encoded. */
   public static final boolean ENCODE_ALPHA = true;
   /** Constant specifying that alpha channel should not be encoded. */
   public static final boolean NO_ALPHA = false;
   /** Constants for filter (NONE). */
   public static final int FILTER_NONE = 0;
   /** Constants for filter (SUB). */
   public static final int FILTER_SUB = 1;
   /** Constants for filter (UP). */
   public static final int FILTER_UP = 2;
   /** Constants for filter (LAST). */
   public static final int FILTER_LAST = 2;
   /** IHDR tag. */
   protected static final byte[] IHDR = {73, 72, 68, 82};
   /** IDAT tag. */
   protected static final byte[] IDAT = {73, 68, 65, 84};
   /** IEND tag. */
   protected static final byte[] IEND = {73, 69, 78, 68};
   /** PHYS tag. */
   protected static final byte[] PHYS = {(byte)"p", (byte)"H", (byte)"Y",
       (byte)"s"};
   /** The png bytes. */
   protected byte[] pngBytes;
   /** The prior row. */
   protected byte[] priorRow;
   /** The left bytes. */
   protected byte[] leftBytes;
   /** The image. */
   protected Image image;
   /** The width. */
   protected int width;
   /** The height. */
   protected int height;
   /** The byte position. */
   protected int bytePos;
   /** The maximum position. */
   protected int maxPos;
   /** CRC. */
   protected CRC32 crc = new CRC32();
   /** The CRC value. */
   protected long crcValue;
   /** Encode alpha? */
   protected boolean encodeAlpha;
   /** The filter type. */
   protected int filter;
   /** The bytes-per-pixel. */
   protected int bytesPerPixel;
   /** The physical pixel dimension : number of pixels per inch on the X axis. */
   private int xDpi = 0;
   /** The physical pixel dimension : number of pixels per inch on the Y axis. */
   private int yDpi = 0;
   /** Used for conversion of DPI to Pixels per Meter. */
   static private float INCH_IN_METER_UNIT = 0.0254f;
   /**
    * The compression level (1 = best speed, 9 = best compression,
    * 0 = no compression).
    */
   protected int compressionLevel;
   /**
    * Class constructor.
    */
   public PngEncoder() {
       this(null, false, FILTER_NONE, 0);
   }
   /**
    * Class constructor specifying Image to encode, with no alpha channel
    * encoding.
    *
    * @param image A Java Image object which uses the DirectColorModel
    * @see java.awt.Image
    */
   public PngEncoder(Image image) {
       this(image, false, FILTER_NONE, 0);
   }
   /**
    * Class constructor specifying Image to encode, and whether to encode
    * alpha.
    *
    * @param image A Java Image object which uses the DirectColorModel
    * @param encodeAlpha Encode the alpha channel? false=no; true=yes
    * @see java.awt.Image
    */
   public PngEncoder(Image image, boolean encodeAlpha) {
       this(image, encodeAlpha, FILTER_NONE, 0);
   }
   /**
    * Class constructor specifying Image to encode, whether to encode alpha,
    * and filter to use.
    *
    * @param image A Java Image object which uses the DirectColorModel
    * @param encodeAlpha Encode the alpha channel? false=no; true=yes
    * @param whichFilter 0=none, 1=sub, 2=up
    * @see java.awt.Image
    */
   public PngEncoder(Image image, boolean encodeAlpha, int whichFilter) {
       this(image, encodeAlpha, whichFilter, 0);
   }
   /**
    * Class constructor specifying Image source to encode, whether to encode
    * alpha, filter to use, and compression level.
    *
    * @param image A Java Image object
    * @param encodeAlpha Encode the alpha channel? false=no; true=yes
    * @param whichFilter 0=none, 1=sub, 2=up
    * @param compLevel 0..9 (1 = best speed, 9 = best compression, 0 = no
    *        compression)
    * @see java.awt.Image
    */
   public PngEncoder(Image image, boolean encodeAlpha, int whichFilter,
           int compLevel) {
       this.image = image;
       this.encodeAlpha = encodeAlpha;
       setFilter(whichFilter);
       if (compLevel >= 0 && compLevel <= 9) {
           this.rupressionLevel = compLevel;
       }
   }
   /**
    * Set the image to be encoded.
    *
    * @param image A Java Image object which uses the DirectColorModel
    * @see java.awt.Image
    * @see java.awt.image.DirectColorModel
    */
   public void setImage(Image image) {
       this.image = image;
       this.pngBytes = null;
   }
   /**
    * Returns the image to be encoded.
    *
    * @return The image.
    */
   public Image getImage() {
     return this.image;
   }
 /**
    * Creates an array of bytes that is the PNG equivalent of the current
    * image, specifying whether to encode alpha or not.
    *
    * @param encodeAlpha boolean false=no alpha, true=encode alpha
    * @return an array of bytes, or null if there was a problem
    */
   public byte[] pngEncode(boolean encodeAlpha) {
       byte[]  pngIdBytes = {-119, 80, 78, 71, 13, 10, 26, 10};
       if (this.image == null) {
           return null;
       }
       this.width = this.image.getWidth(null);
       this.height = this.image.getHeight(null);
       /*
        * start with an array that is big enough to hold all the pixels
        * (plus filter bytes), and an extra 200 bytes for header info
        */
       this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];
       /*
        * keep track of largest byte written to the array
        */
       this.maxPos = 0;
       this.bytePos = writeBytes(pngIdBytes, 0);
       //hdrPos = bytePos;
       writeHeader();
       writeResolution();
       //dataPos = bytePos;
       if (writeImageData()) {
           writeEnd();
           this.pngBytes = resizeByteArray(this.pngBytes, this.maxPos);
       }
       else {
           this.pngBytes = null;
       }
       return this.pngBytes;
   }
   /**
    * Creates an array of bytes that is the PNG equivalent of the current
    * image.  Alpha encoding is determined by its setting in the constructor.
    *
    * @return an array of bytes, or null if there was a problem
    */
   public byte[] pngEncode() {
       return pngEncode(this.encodeAlpha);
   }
   /**
    * Set the alpha encoding on or off.
    *
    * @param encodeAlpha  false=no, true=yes
    */
   public void setEncodeAlpha(boolean encodeAlpha) {
       this.encodeAlpha = encodeAlpha;
   }
   /**
    * Retrieve alpha encoding status.
    *
    * @return boolean false=no, true=yes
    */
   public boolean getEncodeAlpha() {
       return this.encodeAlpha;
   }
   /**
    * Set the filter to use.
    *
    * @param whichFilter from constant list
    */
   public void setFilter(int whichFilter) {
       this.filter = FILTER_NONE;
       if (whichFilter <= FILTER_LAST) {
           this.filter = whichFilter;
       }
   }
   /**
    * Retrieve filtering scheme.
    *
    * @return int (see constant list)
    */
   public int getFilter() {
       return this.filter;
   }
   /**
    * Set the compression level to use.
    *
    * @param level the compression level (1 = best speed, 9 = best compression,
    *        0 = no compression)
    */
   public void setCompressionLevel(int level) {
       if (level >= 0 && level <= 9) {
           this.rupressionLevel = level;
       }
   }
   /**
    * Retrieve compression level.
    *
    * @return int (1 = best speed, 9 = best compression, 0 = no compression)
    */
   public int getCompressionLevel() {
       return this.rupressionLevel;
   }
   /**
    * Increase or decrease the length of a byte array.
    *
    * @param array The original array.
    * @param newLength The length you wish the new array to have.
    * @return Array of newly desired length. If shorter than the
    *         original, the trailing elements are truncated.
    */
   protected byte[] resizeByteArray(byte[] array, int newLength) {
       byte[]  newArray = new byte[newLength];
       int     oldLength = array.length;
       System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength));
       return newArray;
   }
   /**
    * Write an array of bytes into the pngBytes array.
    * Note: This routine has the side effect of updating
    * maxPos, the largest element written in the array.
    * The array is resized by 1000 bytes or the length
    * of the data to be written, whichever is larger.
    *
    * @param data The data to be written into pngBytes.
    * @param offset The starting point to write to.
    * @return The next place to be written to in the pngBytes array.
    */
   protected int writeBytes(byte[] data, int offset) {
       this.maxPos = Math.max(this.maxPos, offset + data.length);
       if (data.length + offset > this.pngBytes.length) {
           this.pngBytes = resizeByteArray(this.pngBytes, this.pngBytes.length
                   + Math.max(1000, data.length));
       }
       System.arraycopy(data, 0, this.pngBytes, offset, data.length);
       return offset + data.length;
   }
   /**
    * Write an array of bytes into the pngBytes array, specifying number of
    * bytes to write. Note: This routine has the side effect of updating
    * maxPos, the largest element written in the array.
    * The array is resized by 1000 bytes or the length
    * of the data to be written, whichever is larger.
    *
    * @param data The data to be written into pngBytes.
    * @param nBytes The number of bytes to be written.
    * @param offset The starting point to write to.
    * @return The next place to be written to in the pngBytes array.
    */
   protected int writeBytes(byte[] data, int nBytes, int offset) {
       this.maxPos = Math.max(this.maxPos, offset + nBytes);
       if (nBytes + offset > this.pngBytes.length) {
           this.pngBytes = resizeByteArray(this.pngBytes, this.pngBytes.length
                   + Math.max(1000, nBytes));
       }
       System.arraycopy(data, 0, this.pngBytes, offset, nBytes);
       return offset + nBytes;
   }
   /**
    * Write a two-byte integer into the pngBytes array at a given position.
    *
    * @param n The integer to be written into pngBytes.
    * @param offset The starting point to write to.
    * @return The next place to be written to in the pngBytes array.
    */
   protected int writeInt2(int n, int offset) {
       byte[] temp = {(byte) ((n >> 8) & 0xff), (byte) (n & 0xff)};
       return writeBytes(temp, offset);
   }
   /**
    * Write a four-byte integer into the pngBytes array at a given position.
    *
    * @param n The integer to be written into pngBytes.
    * @param offset The starting point to write to.
    * @return The next place to be written to in the pngBytes array.
    */
   protected int writeInt4(int n, int offset) {
       byte[] temp = {(byte) ((n >> 24) & 0xff),
                      (byte) ((n >> 16) & 0xff),
                      (byte) ((n >> 8) & 0xff),
                      (byte) (n & 0xff)};
       return writeBytes(temp, offset);
   }
   /**
    * Write a single byte into the pngBytes array at a given position.
    *
    * @param b The integer to be written into pngBytes.
    * @param offset The starting point to write to.
    * @return The next place to be written to in the pngBytes array.
    */
   protected int writeByte(int b, int offset) {
       byte[] temp = {(byte) b};
       return writeBytes(temp, offset);
   }
   /**
    * Write a PNG "IHDR" chunk into the pngBytes array.
    */
   protected void writeHeader() {
       int startPos = this.bytePos = writeInt4(13, this.bytePos);
       this.bytePos = writeBytes(IHDR, this.bytePos);
       this.width = this.image.getWidth(null);
       this.height = this.image.getHeight(null);
       this.bytePos = writeInt4(this.width, this.bytePos);
       this.bytePos = writeInt4(this.height, this.bytePos);
       this.bytePos = writeByte(8, this.bytePos); // bit depth
       this.bytePos = writeByte((this.encodeAlpha) ? 6 : 2, this.bytePos);
           // direct model
       this.bytePos = writeByte(0, this.bytePos); // compression method
       this.bytePos = writeByte(0, this.bytePos); // filter method
       this.bytePos = writeByte(0, this.bytePos); // no interlace
       this.crc.reset();
       this.crc.update(this.pngBytes, startPos, this.bytePos - startPos);
       this.crcValue = this.crc.getValue();
       this.bytePos = writeInt4((int) this.crcValue, this.bytePos);
   }
   /**
    * Perform "sub" filtering on the given row.
    * Uses temporary array leftBytes to store the original values
    * of the previous pixels.  The array is 16 bytes long, which
    * will easily hold two-byte samples plus two-byte alpha.
    *
    * @param pixels The array holding the scan lines being built
    * @param startPos Starting position within pixels of bytes to be filtered.
    * @param width Width of a scanline in pixels.
    */
   protected void filterSub(byte[] pixels, int startPos, int width) {
       int offset = this.bytesPerPixel;
       int actualStart = startPos + offset;
       int nBytes = width * this.bytesPerPixel;
       int leftInsert = offset;
       int leftExtract = 0;
       for (int i = actualStart; i < startPos + nBytes; i++) {
           this.leftBytes[leftInsert] =  pixels[i];
           pixels[i] = (byte) ((pixels[i] - this.leftBytes[leftExtract])
                    % 256);
           leftInsert = (leftInsert + 1) % 0x0f;
           leftExtract = (leftExtract + 1) % 0x0f;
       }
   }
   /**
    * Perform "up" filtering on the given row.
    * Side effect: refills the prior row with current row
    *
    * @param pixels The array holding the scan lines being built
    * @param startPos Starting position within pixels of bytes to be filtered.
    * @param width Width of a scanline in pixels.
    */
   protected void filterUp(byte[] pixels, int startPos, int width) {
       final int nBytes = width * this.bytesPerPixel;
       for (int i = 0; i < nBytes; i++) {
           final byte currentByte = pixels[startPos + i];
           pixels[startPos + i] = (byte) ((pixels[startPos  + i]
                   - this.priorRow[i]) % 256);
           this.priorRow[i] = currentByte;
       }
   }
   /**
    * Write the image data into the pngBytes array.
    * This will write one or more PNG "IDAT" chunks. In order
    * to conserve memory, this method grabs as many rows as will
    * fit into 32K bytes, or the whole image; whichever is less.
    *
    *
    * @return true if no errors; false if error grabbing pixels
    */
   protected boolean writeImageData() {
       int rowsLeft = this.height;  // number of rows remaining to write
       int startRow = 0;       // starting row to process this time through
       int nRows;              // how many rows to grab at a time
       byte[] scanLines;       // the scan lines to be compressed
       int scanPos;            // where we are in the scan lines
       int startPos;           // where this line"s actual pixels start (used
                               // for filtering)
       byte[] compressedLines; // the resultant compressed lines
       int nCompressed;        // how big is the compressed area?
       //int depth;              // color depth ( handle only 8 or 32 )
       PixelGrabber pg;
       this.bytesPerPixel = (this.encodeAlpha) ? 4 : 3;
       Deflater scrunch = new Deflater(this.rupressionLevel);
       ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
       DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes,
               scrunch);
       try {
           while (rowsLeft > 0) {
               nRows = Math.min(32767 / (this.width
                       * (this.bytesPerPixel + 1)), rowsLeft);
               nRows = Math.max(nRows, 1);
               int[] pixels = new int[this.width * nRows];
               pg = new PixelGrabber(this.image, 0, startRow,
                       this.width, nRows, pixels, 0, this.width);
               try {
                   pg.grabPixels();
               }
               catch (Exception e) {
                   System.err.println("interrupted waiting for pixels!");
                   return false;
               }
               if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
                   System.err.println("image fetch aborted or errored");
                   return false;
               }
               /*
                * Create a data chunk. scanLines adds "nRows" for
                * the filter bytes.
                */
               scanLines = new byte[this.width * nRows * this.bytesPerPixel
                                    + nRows];
               if (this.filter == FILTER_SUB) {
                   this.leftBytes = new byte[16];
               }
               if (this.filter == FILTER_UP) {
                   this.priorRow = new byte[this.width * this.bytesPerPixel];
               }
               scanPos = 0;
               startPos = 1;
               for (int i = 0; i < this.width * nRows; i++) {
                   if (i % this.width == 0) {
                       scanLines[scanPos++] = (byte) this.filter;
                       startPos = scanPos;
                   }
                   scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
                   scanLines[scanPos++] = (byte) ((pixels[i] >>  8) & 0xff);
                   scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
                   if (this.encodeAlpha) {
                       scanLines[scanPos++] = (byte) ((pixels[i] >> 24)
                               & 0xff);
                   }
                   if ((i % this.width == this.width - 1)
                           && (this.filter != FILTER_NONE)) {
                       if (this.filter == FILTER_SUB) {
                           filterSub(scanLines, startPos, this.width);
                       }
                       if (this.filter == FILTER_UP) {
                           filterUp(scanLines, startPos, this.width);
                       }
                   }
               }
               /*
                * Write these lines to the output area
                */
               compBytes.write(scanLines, 0, scanPos);
               startRow += nRows;
               rowsLeft -= nRows;
           }
           compBytes.close();
           /*
            * Write the compressed bytes
            */
           compressedLines = outBytes.toByteArray();
           nCompressed = compressedLines.length;
           this.crc.reset();
           this.bytePos = writeInt4(nCompressed, this.bytePos);
           this.bytePos = writeBytes(IDAT, this.bytePos);
           this.crc.update(IDAT);
           this.bytePos = writeBytes(compressedLines, nCompressed,
                   this.bytePos);
           this.crc.update(compressedLines, 0, nCompressed);
           this.crcValue = this.crc.getValue();
           this.bytePos = writeInt4((int) this.crcValue, this.bytePos);
           scrunch.finish();
           scrunch.end();
           return true;
       }
       catch (IOException e) {
           System.err.println(e.toString());
           return false;
       }
   }
   /**
    * Write a PNG "IEND" chunk into the pngBytes array.
    */
   protected void writeEnd() {
       this.bytePos = writeInt4(0, this.bytePos);
       this.bytePos = writeBytes(IEND, this.bytePos);
       this.crc.reset();
       this.crc.update(IEND);
       this.crcValue = this.crc.getValue();
       this.bytePos = writeInt4((int) this.crcValue, this.bytePos);
   }
   /**
    * Set the DPI for the X axis.
    *
    * @param xDpi  The number of dots per inch
    */
   public void setXDpi(int xDpi) {
       this.xDpi = Math.round(xDpi / INCH_IN_METER_UNIT);
   }
   /**
    * Get the DPI for the X axis.
    *
    * @return The number of dots per inch
    */
   public int getXDpi() {
       return Math.round(this.xDpi * INCH_IN_METER_UNIT);
   }
   /**
    * Set the DPI for the Y axis.
    *
    * @param yDpi  The number of dots per inch
    */
   public void setYDpi(int yDpi) {
       this.yDpi = Math.round(yDpi / INCH_IN_METER_UNIT);
   }
   /**
    * Get the DPI for the Y axis.
    *
    * @return The number of dots per inch
    */
   public int getYDpi() {
       return Math.round(this.yDpi * INCH_IN_METER_UNIT);
   }
   /**
    * Set the DPI resolution.
    *
    * @param xDpi  The number of dots per inch for the X axis.
    * @param yDpi  The number of dots per inch for the Y axis.
    */
   public void setDpi(int xDpi, int yDpi) {
       this.xDpi = Math.round(xDpi / INCH_IN_METER_UNIT);
       this.yDpi = Math.round(yDpi / INCH_IN_METER_UNIT);
   }
   /**
    * Write a PNG "pHYs" chunk into the pngBytes array.
    */
   protected void writeResolution() {
       if (this.xDpi > 0 && this.yDpi > 0) {
           final int startPos = this.bytePos = writeInt4(9, this.bytePos);
           this.bytePos = writeBytes(PHYS, this.bytePos);
           this.bytePos = writeInt4(this.xDpi, this.bytePos);
           this.bytePos = writeInt4(this.yDpi, this.bytePos);
           this.bytePos = writeByte(1, this.bytePos); // unit is the meter.
           this.crc.reset();
           this.crc.update(this.pngBytes, startPos, this.bytePos - startPos);
           this.crcValue = this.crc.getValue();
           this.bytePos = writeInt4((int) this.crcValue, this.bytePos);
       }
   }

}


 </source>   



PNG file format decoder

<source lang="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[] args) throws 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 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);
 }

} 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, 0, false);
   }
   System.out.println("Unsupported color type: " + colorType);
   return null;
 }
 public WritableRaster getRaster() {
   int width = (int) getWidth();
   int height = (int) getHeight();
   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 = (int) getWidth();
     int height = (int) getHeight();
     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 * 8 / 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 + i] & 0xff) << ((3 - i) * 8);
   return value;
 }
 public short getUnsignedByte(int offset) {
   return (short) (mData[offset] & 0x00ff);
 }

}



 </source>   



Saving a Generated Graphic to a PNG or JPEG File

<source lang="java"> import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.File; import javax.imageio.ImageIO; public class Main {

 public static void main(String[] argv) throws Exception {
   int width = 100;
   int height = 100;
   BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
   Graphics2D g2d = bufferedImage.createGraphics();
   g2d.setColor(Color.white);
   g2d.fillRect(0, 0, width, height);
   g2d.setColor(Color.black);
   g2d.fillOval(0, 0, width, height);
   g2d.dispose();
   RenderedImage rendImage = bufferedImage;
   File file = new File("newimage.png");
   ImageIO.write(rendImage, "png", file);
   file = new File("newimage.jpg");
   ImageIO.write(rendImage, "jpg", file);
 }

}



 </source>