alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (PNGImageDecoder.java)

This example Java source code file (PNGImageDecoder.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

alpha, awt, chromaticities, color, colormodel, gray, ihdrchunk, image, inputstream, ioexception, palette, pltechunk, pngexception, pngfilterinputstream, pngimagedecoder, string, util, zip

The PNGImageDecoder.java Java example source code

/*
 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.awt.image;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.awt.image.*;
import java.awt.Color;

/** PNG - Portable Network Graphics - image file reader.
    See <a href=http://www.ietf.org/rfc/rfc2083.txt>RFC2083 for details. */

/* this is changed
public class PNGImageDecoder extends FilterInputStream implements Runnable
{ */

public class PNGImageDecoder extends ImageDecoder
{
    private static final int GRAY=0;
    private static final int PALETTE=1;
    private static final int COLOR=2;
    private static final int ALPHA=4;

    private static final int bKGDChunk = 0x624B4744;
    private static final int cHRMChunk = 0x6348524D;
    private static final int gAMAChunk = 0x67414D41;
    private static final int hISTChunk = 0x68495354;
    private static final int IDATChunk = 0x49444154;
    private static final int IENDChunk = 0x49454E44;
    private static final int IHDRChunk = 0x49484452;
    private static final int PLTEChunk = 0x504C5445;
    private static final int pHYsChunk = 0x70485973;
    private static final int sBITChunk = 0x73424954;
    private static final int tEXtChunk = 0x74455874;
    private static final int tIMEChunk = 0x74494D45;
    private static final int tRNSChunk = 0x74524E53;
    private static final int zTXtChunk = 0x7A545874;

    private int width;
    private int height;
    private int bitDepth;
    private int colorType;
    private int compressionMethod;
    private int filterMethod;
    private int interlaceMethod;
    private int gamma = 100000;
    private java.util.Hashtable properties;
  /* this is not needed
    ImageConsumer target;
    */
    private ColorModel cm;
    private byte[] red_map, green_map, blue_map, alpha_map;
    private int transparentPixel = -1;
    private byte[]  transparentPixel_16 = null; // we need 6 bytes to store 16bpp value
    private static ColorModel greyModels[] = new ColorModel[4];
  /* this is not needed
     PNGImageDecoder next;
     */

    private void property(String key,Object value) {
        if(value==null) return;
        if(properties==null) properties=new java.util.Hashtable();
        properties.put(key,value);
    }
    private void property(String key,float value) {
        property(key,new Float(value));
    }
    private final void pngassert(boolean b) throws IOException {
        if(!b) {
            PNGException e = new PNGException("Broken file");
            e.printStackTrace();
            throw e;
        }
    }
    protected boolean handleChunk(int key, byte[] buf, int st, int len)
        throws IOException {
        switch(key) {
            case bKGDChunk:
                Color c = null;
                switch(colorType) {
                    case COLOR:
                    case COLOR|ALPHA:
                        pngassert(len==6);
                        c = new Color(buf[st]&0xff,buf[st+2]&0xff,buf[st+4]&0xff);
                        break;
                    case COLOR|PALETTE:
                    case COLOR|PALETTE|ALPHA:
                        pngassert(len==1);
                        int ix = buf[st]&0xFF;
                        pngassert(red_map!=null && ix<red_map.length);
                        c = new Color(red_map[ix]&0xff,green_map[ix]&0xff,blue_map[ix]&0xff);
                        break;
                    case GRAY:
                    case GRAY|ALPHA:
                        pngassert(len==2);
                        int t = buf[st]&0xFF;
                        c = new Color(t,t,t);
                        break;
                }
                if(c!=null) property("background",c);
                break;
            case cHRMChunk:
                property("chromaticities",
                    new Chromaticities(
                        getInt(st),
                        getInt(st+4),
                        getInt(st+8),
                        getInt(st+12),
                        getInt(st+16),
                        getInt(st+20),
                        getInt(st+24),
                        getInt(st+28)));
                break;
            case gAMAChunk:
                if(len!=4) throw new PNGException("bogus gAMA");
                gamma = getInt(st);
                if(gamma!=100000) property("gamma",gamma/100000.0f);
                break;
            case hISTChunk: break;
            case IDATChunk: return false;
            case IENDChunk: break;
            case IHDRChunk:
                if(len!=13
                    ||(width = getInt(st))==0
                    ||(height = getInt(st+4))==0
                    ) throw new PNGException("bogus IHDR");
                bitDepth = getByte(st+8);
                colorType = getByte(st+9);
                compressionMethod = getByte(st+10);
                filterMethod = getByte(st+11);
                interlaceMethod = getByte(st+12);
                /* this is not needed
                  if(target!=null) target.setDimensions(width,height);
                  */
                break;
            case PLTEChunk:
                {   int tsize = len/3;
                    red_map = new byte[tsize];
                    green_map = new byte[tsize];
                    blue_map = new byte[tsize];
                    for(int i=0,j=st; i<tsize; i++, j+=3) {
                        red_map[i] = buf[j];
                        green_map[i] = buf[j+1];
                        blue_map[i] = buf[j+2];
                    }
                }
                break;
            case pHYsChunk: break;
            case sBITChunk: break;
            case tEXtChunk:
                int klen = 0;
                while(klen<len && buf[st+klen]!=0) klen++;
                if(klen<len) {
                    String tkey = new String(buf,st,klen);
                    String tvalue = new String(buf,st+klen+1,len-klen-1);
                    property(tkey,tvalue);
                }
                break;
            case tIMEChunk:
                property("modtime",new GregorianCalendar(
                    getShort(st+0),
                    getByte(st+2)-1,
                    getByte(st+3),
                    getByte(st+4),
                    getByte(st+5),
                    getByte(st+6)).getTime());
                break;
            case tRNSChunk:
                switch(colorType) {
                    case PALETTE|COLOR:
                    case PALETTE|COLOR|ALPHA:
                        int alen = len;
                        if(red_map!=null) alen = red_map.length;
                        alpha_map = new byte[alen];
                        System.arraycopy(buf,st,alpha_map,0,len<alen ? len : alen);
                        while (--alen>=len) alpha_map[alen] = (byte)0xFF;
                        break;
                    case COLOR: // doesn't deal with 16 bit colors properly
                    case COLOR|ALPHA: // doesn't deal with 16 bit colors properly
                        pngassert(len==6);
                        if (bitDepth == 16) {
                            transparentPixel_16 = new byte[6];
                            for (int i = 0; i < 6; i++) {
                                transparentPixel_16[i] = (byte)getByte(st + i);
                            }
                        } else {
                            transparentPixel =
                                      ((getShort(st + 0)&0xFF)<<16)
                                    | ((getShort(st + 2)&0xFF)<< 8)
                                    | ((getShort(st + 4)&0xFF)    );
                        }
                        break;
                    case GRAY:  // doesn't deal with 16 bit colors properly
                    case GRAY|ALPHA:  // doesn't deal with 16 bit colors properly
                        pngassert(len==2);
                        /* REMIND: Discarding the LSB for 16 bit depth here
                         * means that the all pixels which match the MSB
                         * will be treated as transparent.
                         */
                        int t = getShort(st);
                        t = 0xFF & ((bitDepth == 16) ? (t >> 8) : t);
                        transparentPixel = (t<<16) | (t<< 8) | t;
                        break;
                }
                break;
            case zTXtChunk: break;
        }
        return true;
    }
    public class PNGException extends IOException {
        PNGException(String s) { super(s); }
    }
  /* this is changed
     public void run() {
     */
  public void produceImage() throws IOException, ImageFormatException {
    /* this is not needed
       ImageConsumer t = target;
       if(t!=null) try {
       */
    try {
            for(int i=0; i<signature.length; i++)
              if((signature[i]&0xFF)!=underlyingInputStream.read())
                throw new PNGException("Chunk signature mismatch");

            InputStream is = new BufferedInputStream(new InflaterInputStream(inputStream,new Inflater()));

            getData();

            byte[] bPixels = null;
            int[] wPixels = null;
            int pixSize = width;
            int rowStride;
            int logDepth = 0;
            switch(bitDepth) {
                case  1: logDepth = 0; break;
                case  2: logDepth = 1; break;
                case  4: logDepth = 2; break;
                case  8: logDepth = 3; break;
                case 16: logDepth = 4; break;
                default: throw new PNGException("invalid depth");
            }
            if(interlaceMethod!=0) {pixSize *= height;rowStride=width;}
            else rowStride = 0;
            int combinedType = colorType|(bitDepth<<3);
            int bitMask = (1<<(bitDepth>=8?8:bitDepth))-1;
            //Figure out the color model
            switch(colorType) {
                case COLOR|PALETTE:
                case COLOR|PALETTE|ALPHA:
                    if(red_map==null) throw new PNGException("palette expected");
                    if(alpha_map==null)
                        cm = new IndexColorModel(bitDepth,red_map.length,
                            red_map,green_map,blue_map);
                    else
                        cm = new IndexColorModel(bitDepth,red_map.length,
                            red_map,green_map,blue_map,alpha_map);
                    bPixels = new byte[pixSize];
                    break;
                case GRAY:
                    {   int llog = logDepth>=4 ? 3 : logDepth;
                        if((cm=greyModels[llog]) == null) {
                            int size = 1<<(1<3;
            int pass, passLimit;
            if(interlaceMethod==0) { pass = -1; passLimit = 0; }
            else { pass = 0; passLimit = 7; }
            // These loops are far from being tuned.  They're this way to make them easy to
            // debug.  Tuning comes later.
            /* code changed. target not needed here
               while(++pass<=passLimit && (t=target)!=null) {
               */
            while(++pass<=passLimit) {
                int row = startingRow[pass];
                int rowInc = rowIncrement[pass];
                int colInc = colIncrement[pass];
                int bWidth = blockWidth[pass];
                int bHeight = blockHeight[pass];
                int sCol = startingCol[pass];
                int rowPixelWidth = (width-sCol+(colInc-1))/colInc;
                int rowByteWidth = ((rowPixelWidth*bitsPerPixel)+7)>>3;
                if(rowByteWidth==0) continue;
                int pixelBufferInc = interlaceMethod==0 ? rowInc*width : 0;
                int rowOffset = rowStride*row;
                boolean firstRow = true;

                byte[] rowByteBuffer = new byte[rowByteWidth];
                byte[] prevRowByteBuffer = new byte[rowByteWidth];
                /* code changed. target not needed here
                   while (row < height && (t=target)!=null) {
                   */
                while (row < height) {
                    int rowFilter = is.read();
                    for (int rowFillPos=0;rowFillPos<rowByteWidth; ) {
                        int n = is.read(rowByteBuffer,rowFillPos,rowByteWidth-rowFillPos);
                        if(n<=0) throw new PNGException("missing data");
                        rowFillPos+=n;
                    }
                    filterRow(rowByteBuffer,
                              firstRow ? null : prevRowByteBuffer,
                              rowFilter, rowByteWidth, bytesPerPixel);
                    int col = sCol;
                    int spos=0;
                    int pixel = 0;
                    while (col < width) {
                        if(wPixels !=null) {
                            switch(combinedType) {
                                case COLOR|ALPHA|(8<<3):
                                    wPixels[col+rowOffset] =
                                          ((rowByteBuffer[spos  ]&0xFF)<<16)
                                        | ((rowByteBuffer[spos+1]&0xFF)<< 8)
                                        | ((rowByteBuffer[spos+2]&0xFF)    )
                                        | ((rowByteBuffer[spos+3]&0xFF)<<24);
                                    spos+=4;
                                    break;
                                case COLOR|ALPHA|(16<<3):
                                    wPixels[col+rowOffset] =
                                          ((rowByteBuffer[spos  ]&0xFF)<<16)
                                        | ((rowByteBuffer[spos+2]&0xFF)<< 8)
                                        | ((rowByteBuffer[spos+4]&0xFF)    )
                                        | ((rowByteBuffer[spos+6]&0xFF)<<24);
                                    spos+=8;
                                    break;
                                case COLOR|(8<<3):
                                    pixel =
                                          ((rowByteBuffer[spos  ]&0xFF)<<16)
                                        | ((rowByteBuffer[spos+1]&0xFF)<< 8)
                                        | ((rowByteBuffer[spos+2]&0xFF)    );
                                    if (pixel != transparentPixel) {
                                        pixel |= 0xff000000;
                                    }
                                    wPixels[col+rowOffset] = pixel;
                                    spos+=3;
                                    break;
                                case COLOR|(16<<3):
                                    pixel =
                                              ((rowByteBuffer[spos  ]&0xFF)<<16)
                                            | ((rowByteBuffer[spos+2]&0xFF)<< 8)
                                            | ((rowByteBuffer[spos+4]&0xFF)    );

                                    boolean isTransparent = (transparentPixel_16 != null);
                                    for (int i = 0; isTransparent && (i < 6); i++) {
                                        isTransparent &=
                                                (rowByteBuffer[spos + i] & 0xFF) == (transparentPixel_16[i] & 0xFF);
                                    }
                                    if (!isTransparent)  {
                                        pixel |= 0xff000000;
                                    }
                                    wPixels[col+rowOffset] = pixel;
                                    spos+=6;
                                    break;
                                case GRAY|ALPHA|(8<<3):
                                    { int tx = rowByteBuffer[spos]&0xFF;
                                      wPixels[col+rowOffset] =
                                          (tx<<16)|(tx<<8)|tx
                                        |((rowByteBuffer[spos+1]&0xFF)<<24); }
                                    spos+=2;
                                    break;
                                case GRAY|ALPHA|(16<<3):
                                    { int tx = rowByteBuffer[spos]&0xFF;
                                      wPixels[col+rowOffset] =
                                          (tx<<16)|(tx<<8)|tx
                                        |((rowByteBuffer[spos+2]&0xFF)<<24); }
                                    spos+=4;
                                    break;
                                default: throw new PNGException("illegal type/depth");
                            }
                        } else switch(bitDepth) {
                            case 1:
                                bPixels[col+rowOffset] =
                                    (byte)((rowByteBuffer[spos>>3]>>(7-(spos&7)))&1);
                                spos++;
                                break;
                            case 2:
                                bPixels[col+rowOffset] =
                                    (byte)((rowByteBuffer[spos>>2]>>((3-(spos&3))*2))&3);
                                spos++;
                                break;
                            case 4:
                                bPixels[col+rowOffset] =
                                    (byte)((rowByteBuffer[spos>>1]>>((1-(spos&1))*4))&15);
                                spos++;
                                break;
                            case 8: bPixels[col+rowOffset] = rowByteBuffer[spos++];
                                break;
                            case 16: bPixels[col+rowOffset] = rowByteBuffer[spos]; spos+=2;
                                break;
                            default: throw new PNGException("illegal type/depth");
                        }
                        /*visit (row, col,
                            min (bHeight, height - row),
                            min (bWidth, width - col)); */
                        col += colInc;
                    }
                    if(interlaceMethod==0)
                      if(wPixels!=null) {
                        /* code changed. target not needed here
                          t.setPixels(0,row,width,1,cm,wPixels,0,width);
                          */
                       // code added to make it work with ImageDecoder arch
                        sendPixels(0,row,width,1,wPixels,0,width);
                        // end of adding
                      }
                      else {
                        /* code changed. target not needed here
                           t.setPixels(0,row,width,1,cm,bPixels,0,width);
                           */
                        // code added to make it work with ImageDecoder arch
                        sendPixels(0,row,width,1,bPixels,0,width);
                        //end of adding
                      }
                    row += rowInc;
                    rowOffset += rowInc*rowStride;
                    byte[] T = rowByteBuffer;
                    rowByteBuffer = prevRowByteBuffer;
                    prevRowByteBuffer = T;
                    firstRow = false;
                }
                if(interlaceMethod!=0)
                  if(wPixels!=null) {
                    /* code changed. target not needed here
                       t.setPixels(0,0,width,height,cm,wPixels,0,width);
                       */
                    // code added to make it work with ImageDecoder arch
                      sendPixels(0,0,width,height,wPixels,0,width);
                      //end of adding
                  }
                  else {
                     /* code changed. target not needed here
                        t.setPixels(0,0,width,height,cm,bPixels,0,width);
                        */
                    // code added to make it work with ImageDecoder arch
                      sendPixels(0,0,width,height,bPixels,0,width);
                      //end of adding
                  }
            }

   /* Here, the function "visit(row,column,height,width)" obtains the
      next transmitted pixel and paints a rectangle of the specified
      height and width, whose upper-left corner is at the specified row
      and column, using the color indicated by the pixel.  Note that row
      and column are measured from 0,0 at the upper left corner. */

            /* code not needed, don't deal with target
             if((t=target)!=null) {
               if(properties!=null) t.setProperties(properties);
                 t.imageComplete(ImageConsumer.STATICIMAGEDONE);
                 */

              imageComplete(ImageConsumer.STATICIMAGEDONE, true);

              /* code not needed }
               is.close();
               */
        } catch(IOException e) {
            if(!aborted) {
                /* code not needed
                   if((t=target)!=null) {
                   PNGEncoder.prChunk(e.toString(),inbuf,pos,limit-pos,true);
                */
                property("error", e);
                /* code not needed
                   t.setProperties(properties);
                   t.imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE);
                */
                imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE, true);
                throw e;
            }
        } finally {
          try { close(); } catch(Throwable e){}
          /* code not needed
             target = null;
             endTurn();
             */
        }
    }

    private boolean sendPixels(int x, int y, int w, int h, int[] pixels,
                               int offset, int pixlength) {
        int count = setPixels(x, y, w, h, cm,
                              pixels, offset, pixlength);
        if (count <= 0) {
            aborted = true;
        }
        return !aborted;
    }
    private boolean sendPixels(int x, int y, int w, int h, byte[] pixels,
                               int offset, int pixlength) {
        int count = setPixels(x, y, w, h, cm,
                              pixels, offset, pixlength);
        if (count <= 0) {
            aborted = true;
        }
        return !aborted;
    }

    private void filterRow(byte rowByteBuffer[], byte[] prevRow,
                           int rowFilter, int rowByteWidth, int bytesPerSample)
        throws IOException {
        int x = 0;
        switch (rowFilter) {
          case 0:
            break;
          case 1:
            for (x = bytesPerSample; x < rowByteWidth; x++)
                rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
            break;
          case 2:
            if (prevRow != null)
                for ( ; x < rowByteWidth; x++)
                    rowByteBuffer[x] += prevRow[x];
            break;
          case 3:
            if (prevRow != null) {
                for ( ; x < bytesPerSample; x++)
                    rowByteBuffer[x] += (0xff & prevRow[x])>>1;
                for ( ; x < rowByteWidth; x++)
                    rowByteBuffer[x] += ((prevRow[x]&0xFF) + (rowByteBuffer[x - bytesPerSample]&0xFF))>>1;
            } else
                for (x = bytesPerSample; x < rowByteWidth; x++)
                    rowByteBuffer[x] += (rowByteBuffer[x - bytesPerSample]&0xFF)>>1;
            break;
          case 4:
            if (prevRow != null) {
                for ( ; x < bytesPerSample; x++)
                    rowByteBuffer[x] += prevRow[x];
                for ( ; x < rowByteWidth; x++) {
                    int a, b, c, p, pa, pb, pc, rval;
                    a = rowByteBuffer[x - bytesPerSample]&0xFF;
                    b = prevRow[x]&0xFF;
                    c = prevRow[x - bytesPerSample]&0xFF;
                    p = a + b - c;
                    pa = p > a ? p - a : a - p;
                    pb = p > b ? p - b : b - p;
                    pc = p > c ? p - c : c - p;
                    rowByteBuffer[x] += (pa <= pb) && (pa <= pc) ? a : pb <= pc ? b : c;
                }
            } else
                for (x = bytesPerSample; x < rowByteWidth; x++)
                    rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
            break;
          default:
            throw new PNGException("Illegal filter");
        }
    }
    private static final byte[] startingRow =  { 0, 0, 0, 4, 0, 2, 0, 1 };
    private static final byte[] startingCol =  { 0, 0, 4, 0, 2, 0, 1, 0 };
    private static final byte[] rowIncrement = { 1, 8, 8, 8, 4, 4, 2, 2 };
    private static final byte[] colIncrement = { 1, 8, 8, 4, 4, 2, 2, 1 };
    private static final byte[] blockHeight =  { 1, 8, 8, 4, 4, 2, 2, 1 };
    private static final byte[] blockWidth =   { 1, 8, 4, 4, 2, 2, 1, 1 };

    //abstract public class ChunkReader extends FilterInputStream {
  int pos, limit;
    int chunkStart;
   int chunkKey, chunkLength, chunkCRC;
    boolean seenEOF;

    private static final byte[] signature = { (byte) 137, (byte) 80, (byte) 78,
        (byte) 71, (byte) 13, (byte) 10, (byte) 26, (byte) 10 };

  PNGFilterInputStream inputStream;
  InputStream underlyingInputStream;

  /* code changed
    public PNGImageDecoder(InputStream in, ImageConsumer t) throws IOException {
    */
  public PNGImageDecoder(InputStreamImageSource src, InputStream input) throws IOException {
    // code added
    super(src, input);
    inputStream = new PNGFilterInputStream(this, input);
    underlyingInputStream = inputStream.underlyingInputStream;
    // end of adding
    /* code changed
       super(in);
       target = t;
       waitTurn();
       new Thread(this).start();
       */
    }
  /* code changed to make it work with ImageDecoder architecture
    static int ThreadLimit = 10;
    private synchronized static void waitTurn() {
        try {
            while(ThreadLimit<=0) PNGImageDecoder.class.wait(1000);
        } catch(InterruptedException e){}
        ThreadLimit--;
    }
    private synchronized static void endTurn() {
        if(ThreadLimit<=0) PNGImageDecoder.class.notify();
        ThreadLimit++;
    }
    */
    byte[] inbuf = new byte[4096];
    private void fill() throws IOException {
        if(!seenEOF) {
            if(pos>0 && pos<limit) {
                System.arraycopy(inbuf,pos,inbuf,0,limit-pos);
                limit = limit-pos;
                pos = 0;
            } else if(pos>=limit) {
                pos = 0; limit = 0;
            }
            int bsize = inbuf.length;
            while(limit<bsize) {
                int n = underlyingInputStream.read(inbuf,limit,bsize-limit);
                if(n<=0) { seenEOF=true; break; }
                limit += n;
            }
        }
    }
    private boolean need(int n) throws IOException {
        if(limit-pos>=n) return true;
        fill();
        if(limit-pos>=n) return true;
        if(seenEOF) return false;
        byte nin[] = new byte[n+100];
        System.arraycopy(inbuf,pos,nin,0,limit-pos);
        limit = limit-pos;
        pos = 0;
        inbuf = nin;
        fill();
        return limit-pos>=n;
    }
    private final int getInt(int pos) {
        return ((inbuf[pos  ]&0xFF)<<24)
             | ((inbuf[pos+1]&0xFF)<<16)
             | ((inbuf[pos+2]&0xFF)<< 8)
             | ((inbuf[pos+3]&0xFF)    );
    }
    private final int getShort(int pos) {
        return (short)(((inbuf[pos  ]&0xFF)<<8)
                     | ((inbuf[pos+1]&0xFF)   ));
    }
    private final int getByte(int pos) {
        return inbuf[pos]&0xFF;
    }
    private final boolean getChunk() throws IOException {
        chunkLength = 0;
        if (!need(8)) return false;
        chunkLength = getInt(pos);
        chunkKey = getInt(pos+4);
        if(chunkLength<0) throw new PNGException("bogus length: "+chunkLength);
        if (!need(chunkLength+12)) return false;
        chunkCRC = getInt(pos+8+chunkLength);
        chunkStart = pos+8;
        int calcCRC = crc(inbuf,pos+4,chunkLength+4);
        if(chunkCRC!=calcCRC && checkCRC) throw new PNGException("crc corruption");
        pos+=chunkLength+12;
        return true;
    }
    private void readAll() throws IOException {
        while(getChunk()) handleChunk(chunkKey,inbuf,chunkStart,chunkLength);
    }
    boolean getData() throws IOException {
        while(chunkLength==0 && getChunk())
            if(handleChunk(chunkKey,inbuf,chunkStart,chunkLength))
                chunkLength = 0;
        return chunkLength>0;
    }
    //abstract protected boolean handleChunk(int key, byte[] buf, int st, int len)
    //    throws IOException;
    private static boolean checkCRC = true;
    public static boolean getCheckCRC() { return checkCRC; }
    public static void setCheckCRC(boolean c) { checkCRC = c; }

    protected void wrc(int c) {
        c = c&0xFF;
        if(c<=' '||c>'z') c = '?';
        System.out.write(c);
    }
    protected void wrk(int n) {
        wrc(n>>24);
        wrc(n>>16);
        wrc(n>>8);
        wrc(n);
    }
    public void print() {
        wrk(chunkKey);
        System.out.print(" "+chunkLength+"\n");
    }

    /* Table of CRCs of all 8-bit messages. */
    private static final int[] crc_table = new int[256];

    /* Make the table for a fast CRC. */
    static {
        for (int n = 0; n < 256; n++) {
            int c = n;
            for (int k = 0; k < 8; k++)
                if ((c & 1) != 0)
                    c = 0xedb88320 ^ (c >>> 1);
                else
                    c = c >>> 1;
            crc_table[n] = c;
        }
    }

    /* Update a running CRC with the bytes buf[0..len-1]--the CRC
    should be initialized to all 1's, and the transmitted value
    is the 1's complement of the final running CRC (see the
    crc() routine below)). */

    static private int update_crc(int crc, byte[] buf, int offset, int len) {
        int c = crc;
        while (--len>=0)
            c = crc_table[(c ^ buf[offset++]) & 0xff] ^ (c >>> 8);
        return c;
    }

    /* Return the CRC of the bytes buf[0..len-1]. */
    static private int crc(byte[] buf, int offset, int len) {
        return update_crc(0xffffffff, buf, offset, len) ^ 0xffffffff;
    }
    public static class Chromaticities {
        public float whiteX, whiteY, redX, redY, greenX, greenY, blueX, blueY;
        Chromaticities(int wx, int wy, int rx, int ry, int gx, int gy, int bx, int by) {
            whiteX = wx/100000.0f;
            whiteY = wy/100000.0f;
            redX = rx/100000.0f;
            redY = ry/100000.0f;
            greenX = gx/100000.0f;
            greenY = gy/100000.0f;
            blueX = bx/100000.0f;
            blueY = by/100000.0f;
        }
        public String toString() {
            return "Chromaticities(white="+whiteX+","+whiteY+";red="+
                redX+","+redY+";green="+
                greenX+","+greenY+";blue="+
                blueX+","+blueY+")";
        }
    }
}

// the following class are added to make it work with ImageDecoder architecture

class PNGFilterInputStream extends FilterInputStream {
  PNGImageDecoder owner;
  public InputStream underlyingInputStream;
  public PNGFilterInputStream(PNGImageDecoder owner, InputStream is) {
    super(is);
    underlyingInputStream = in;
    this.owner = owner;
  }

    public int available() throws IOException {
        return owner.limit-owner.pos+in.available();}
    public boolean markSupported() { return false; }
    public int read() throws IOException {
        if(owner.chunkLength<=0) if(!owner.getData()) return -1;
        owner.chunkLength--;
        return owner.inbuf[owner.chunkStart++]&0xFF;
    }
    public int read(byte[] b) throws IOException{return read(b,0,b.length);}
    public int read(byte[] b, int st, int len) throws IOException {
        if(owner.chunkLength<=0) if(!owner.getData()) return -1;
        if(owner.chunkLength<len) len = owner.chunkLength;
        System.arraycopy(owner.inbuf,owner.chunkStart,b,st,len);
        owner.chunkLength-=len;
        owner.chunkStart+=len;
        return len;
    }
  public long skip(long n) throws IOException {
        int i;
        for(i = 0; i<n && read()>=0; i++);
        return i;
    }


}

Other Java examples (source code examples)

Here is a short list of links related to this Java PNGImageDecoder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.