0N/A/*
3261N/A * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.awt.image;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/Aimport java.util.zip.*;
0N/Aimport java.awt.image.*;
0N/Aimport java.awt.Color;
0N/A
0N/A/** PNG - Portable Network Graphics - image file reader.
2507N/A See <a href=http://www.ietf.org/rfc/rfc2083.txt>RFC2083</a> for details. */
0N/A
0N/A/* this is changed
0N/Apublic class PNGImageDecoder extends FilterInputStream implements Runnable
0N/A{ */
0N/A
0N/Apublic class PNGImageDecoder extends ImageDecoder
0N/A{
0N/A private static final int GRAY=0;
0N/A private static final int PALETTE=1;
0N/A private static final int COLOR=2;
0N/A private static final int ALPHA=4;
0N/A
0N/A private static final int bKGDChunk = 0x624B4744;
0N/A private static final int cHRMChunk = 0x6348524D;
0N/A private static final int gAMAChunk = 0x67414D41;
0N/A private static final int hISTChunk = 0x68495354;
0N/A private static final int IDATChunk = 0x49444154;
0N/A private static final int IENDChunk = 0x49454E44;
0N/A private static final int IHDRChunk = 0x49484452;
0N/A private static final int PLTEChunk = 0x504C5445;
0N/A private static final int pHYsChunk = 0x70485973;
0N/A private static final int sBITChunk = 0x73424954;
0N/A private static final int tEXtChunk = 0x74455874;
0N/A private static final int tIMEChunk = 0x74494D45;
0N/A private static final int tRNSChunk = 0x74524E53;
0N/A private static final int zTXtChunk = 0x7A545874;
0N/A
0N/A private int width;
0N/A private int height;
0N/A private int bitDepth;
0N/A private int colorType;
0N/A private int compressionMethod;
0N/A private int filterMethod;
0N/A private int interlaceMethod;
0N/A private int gamma = 100000;
0N/A private java.util.Hashtable properties;
0N/A /* this is not needed
0N/A ImageConsumer target;
0N/A */
0N/A private ColorModel cm;
0N/A private byte[] red_map, green_map, blue_map, alpha_map;
0N/A private int transparentPixel = -1;
0N/A private byte[] transparentPixel_16 = null; // we need 6 bytes to store 16bpp value
0N/A private static ColorModel greyModels[] = new ColorModel[4];
0N/A /* this is not needed
0N/A PNGImageDecoder next;
0N/A */
0N/A
0N/A private void property(String key,Object value) {
0N/A if(value==null) return;
0N/A if(properties==null) properties=new java.util.Hashtable();
0N/A properties.put(key,value);
0N/A }
0N/A private void property(String key,float value) {
0N/A property(key,new Float(value));
0N/A }
0N/A private final void pngassert(boolean b) throws IOException {
0N/A if(!b) {
0N/A PNGException e = new PNGException("Broken file");
0N/A e.printStackTrace();
0N/A throw e;
0N/A }
0N/A }
0N/A protected boolean handleChunk(int key, byte[] buf, int st, int len)
0N/A throws IOException {
0N/A switch(key) {
0N/A case bKGDChunk:
0N/A Color c = null;
0N/A switch(colorType) {
0N/A case COLOR:
0N/A case COLOR|ALPHA:
0N/A pngassert(len==6);
0N/A c = new Color(buf[st]&0xff,buf[st+2]&0xff,buf[st+4]&0xff);
0N/A break;
0N/A case COLOR|PALETTE:
0N/A case COLOR|PALETTE|ALPHA:
0N/A pngassert(len==1);
0N/A int ix = buf[st]&0xFF;
0N/A pngassert(red_map!=null && ix<red_map.length);
0N/A c = new Color(red_map[ix]&0xff,green_map[ix]&0xff,blue_map[ix]&0xff);
0N/A break;
0N/A case GRAY:
0N/A case GRAY|ALPHA:
0N/A pngassert(len==2);
0N/A int t = buf[st]&0xFF;
0N/A c = new Color(t,t,t);
0N/A break;
0N/A }
0N/A if(c!=null) property("background",c);
0N/A break;
0N/A case cHRMChunk:
0N/A property("chromaticities",
0N/A new Chromaticities(
0N/A getInt(st),
0N/A getInt(st+4),
0N/A getInt(st+8),
0N/A getInt(st+12),
0N/A getInt(st+16),
0N/A getInt(st+20),
0N/A getInt(st+24),
0N/A getInt(st+28)));
0N/A break;
0N/A case gAMAChunk:
0N/A if(len!=4) throw new PNGException("bogus gAMA");
0N/A gamma = getInt(st);
0N/A if(gamma!=100000) property("gamma",gamma/100000.0f);
0N/A break;
0N/A case hISTChunk: break;
0N/A case IDATChunk: return false;
0N/A case IENDChunk: break;
0N/A case IHDRChunk:
0N/A if(len!=13
0N/A ||(width = getInt(st))==0
0N/A ||(height = getInt(st+4))==0
0N/A ) throw new PNGException("bogus IHDR");
0N/A bitDepth = getByte(st+8);
0N/A colorType = getByte(st+9);
0N/A compressionMethod = getByte(st+10);
0N/A filterMethod = getByte(st+11);
0N/A interlaceMethod = getByte(st+12);
0N/A /* this is not needed
0N/A if(target!=null) target.setDimensions(width,height);
0N/A */
0N/A break;
0N/A case PLTEChunk:
0N/A { int tsize = len/3;
0N/A red_map = new byte[tsize];
0N/A green_map = new byte[tsize];
0N/A blue_map = new byte[tsize];
0N/A for(int i=0,j=st; i<tsize; i++, j+=3) {
0N/A red_map[i] = buf[j];
0N/A green_map[i] = buf[j+1];
0N/A blue_map[i] = buf[j+2];
0N/A }
0N/A }
0N/A break;
0N/A case pHYsChunk: break;
0N/A case sBITChunk: break;
0N/A case tEXtChunk:
0N/A int klen = 0;
0N/A while(klen<len && buf[st+klen]!=0) klen++;
0N/A if(klen<len) {
0N/A String tkey = new String(buf,st,klen);
0N/A String tvalue = new String(buf,st+klen+1,len-klen-1);
0N/A property(tkey,tvalue);
0N/A }
0N/A break;
0N/A case tIMEChunk:
0N/A property("modtime",new GregorianCalendar(
0N/A getShort(st+0),
0N/A getByte(st+2)-1,
0N/A getByte(st+3),
0N/A getByte(st+4),
0N/A getByte(st+5),
0N/A getByte(st+6)).getTime());
0N/A break;
0N/A case tRNSChunk:
0N/A switch(colorType) {
0N/A case PALETTE|COLOR:
0N/A case PALETTE|COLOR|ALPHA:
0N/A int alen = len;
0N/A if(red_map!=null) alen = red_map.length;
0N/A alpha_map = new byte[alen];
0N/A System.arraycopy(buf,st,alpha_map,0,len<alen ? len : alen);
0N/A while (--alen>=len) alpha_map[alen] = (byte)0xFF;
0N/A break;
0N/A case COLOR: // doesn't deal with 16 bit colors properly
0N/A case COLOR|ALPHA: // doesn't deal with 16 bit colors properly
0N/A pngassert(len==6);
0N/A if (bitDepth == 16) {
0N/A transparentPixel_16 = new byte[6];
0N/A for (int i = 0; i < 6; i++) {
0N/A transparentPixel_16[i] = (byte)getByte(st + i);
0N/A }
0N/A } else {
0N/A transparentPixel =
0N/A ((getShort(st + 0)&0xFF)<<16)
0N/A | ((getShort(st + 2)&0xFF)<< 8)
0N/A | ((getShort(st + 4)&0xFF) );
0N/A }
0N/A break;
0N/A case GRAY: // doesn't deal with 16 bit colors properly
0N/A case GRAY|ALPHA: // doesn't deal with 16 bit colors properly
0N/A pngassert(len==2);
0N/A /* REMIND: Discarding the LSB for 16 bit depth here
0N/A * means that the all pixels which match the MSB
0N/A * will be treated as transparent.
0N/A */
0N/A int t = getShort(st);
0N/A t = 0xFF & ((bitDepth == 16) ? (t >> 8) : t);
0N/A transparentPixel = (t<<16) | (t<< 8) | t;
0N/A break;
0N/A }
0N/A break;
0N/A case zTXtChunk: break;
0N/A }
0N/A return true;
0N/A }
0N/A public class PNGException extends IOException {
0N/A PNGException(String s) { super(s); }
0N/A }
0N/A /* this is changed
0N/A public void run() {
0N/A */
0N/A public void produceImage() throws IOException, ImageFormatException {
0N/A /* this is not needed
0N/A ImageConsumer t = target;
0N/A if(t!=null) try {
0N/A */
0N/A try {
0N/A for(int i=0; i<signature.length; i++)
0N/A if((signature[i]&0xFF)!=underlyingInputStream.read())
0N/A throw new PNGException("Chunk signature mismatch");
0N/A
0N/A InputStream is = new BufferedInputStream(new InflaterInputStream(inputStream,new Inflater()));
0N/A
0N/A getData();
0N/A
0N/A byte[] bPixels = null;
0N/A int[] wPixels = null;
0N/A int pixSize = width;
0N/A int rowStride;
0N/A int logDepth = 0;
0N/A switch(bitDepth) {
0N/A case 1: logDepth = 0; break;
0N/A case 2: logDepth = 1; break;
0N/A case 4: logDepth = 2; break;
0N/A case 8: logDepth = 3; break;
0N/A case 16: logDepth = 4; break;
0N/A default: throw new PNGException("invalid depth");
0N/A }
0N/A if(interlaceMethod!=0) {pixSize *= height;rowStride=width;}
0N/A else rowStride = 0;
0N/A int combinedType = colorType|(bitDepth<<3);
0N/A int bitMask = (1<<(bitDepth>=8?8:bitDepth))-1;
0N/A //Figure out the color model
0N/A switch(colorType) {
0N/A case COLOR|PALETTE:
0N/A case COLOR|PALETTE|ALPHA:
0N/A if(red_map==null) throw new PNGException("palette expected");
0N/A if(alpha_map==null)
0N/A cm = new IndexColorModel(bitDepth,red_map.length,
0N/A red_map,green_map,blue_map);
0N/A else
0N/A cm = new IndexColorModel(bitDepth,red_map.length,
0N/A red_map,green_map,blue_map,alpha_map);
0N/A bPixels = new byte[pixSize];
0N/A break;
0N/A case GRAY:
0N/A { int llog = logDepth>=4 ? 3 : logDepth;
0N/A if((cm=greyModels[llog]) == null) {
0N/A int size = 1<<(1<<llog);
0N/A
0N/A byte ramp[] = new byte[size];
0N/A for(int i = 0; i<size; i++) ramp[i] = (byte)(255*i/(size-1));
0N/A
0N/A if (transparentPixel == -1) {
0N/A cm = new IndexColorModel(bitDepth,ramp.length,ramp,ramp,ramp);
0N/A } else {
0N/A cm = new IndexColorModel(bitDepth,ramp.length,ramp,ramp,ramp,
0N/A (transparentPixel & 0xFF));
0N/A }
0N/A greyModels[llog] = cm;
0N/A }
0N/A }
0N/A bPixels = new byte[pixSize];
0N/A break;
0N/A case COLOR:
0N/A case COLOR|ALPHA:
0N/A case GRAY|ALPHA:
0N/A cm = ColorModel.getRGBdefault();
0N/A wPixels = new int[pixSize];
0N/A break;
0N/A default:
0N/A throw new PNGException("invalid color type");
0N/A }
0N/A /* this is going to be set in the pixel store
0N/A t.setColorModel(cm);
0N/A t.setHints(interlaceMethod !=0
0N/A ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
0N/A : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
0N/A ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
0N/A */
0N/A // code added to make it work with ImageDecoder architecture
0N/A setDimensions(width, height);
0N/A setColorModel(cm);
0N/A int flags = (interlaceMethod !=0
0N/A ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
0N/A : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
0N/A ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
0N/A setHints(flags);
0N/A headerComplete();
0N/A // end of adding
0N/A
0N/A int samplesPerPixel = ((colorType&PALETTE)!=0 ? 1
0N/A : ((colorType&COLOR)!=0 ? 3 : 1)+((colorType&ALPHA)!=0?1:0));
0N/A int bitsPerPixel = samplesPerPixel*bitDepth;
0N/A int bytesPerPixel = (bitsPerPixel+7)>>3;
0N/A int pass, passLimit;
0N/A if(interlaceMethod==0) { pass = -1; passLimit = 0; }
0N/A else { pass = 0; passLimit = 7; }
0N/A // These loops are far from being tuned. They're this way to make them easy to
0N/A // debug. Tuning comes later.
0N/A /* code changed. target not needed here
0N/A while(++pass<=passLimit && (t=target)!=null) {
0N/A */
0N/A while(++pass<=passLimit) {
0N/A int row = startingRow[pass];
0N/A int rowInc = rowIncrement[pass];
0N/A int colInc = colIncrement[pass];
0N/A int bWidth = blockWidth[pass];
0N/A int bHeight = blockHeight[pass];
0N/A int sCol = startingCol[pass];
0N/A int rowPixelWidth = (width-sCol+(colInc-1))/colInc;
0N/A int rowByteWidth = ((rowPixelWidth*bitsPerPixel)+7)>>3;
0N/A if(rowByteWidth==0) continue;
0N/A int pixelBufferInc = interlaceMethod==0 ? rowInc*width : 0;
0N/A int rowOffset = rowStride*row;
0N/A boolean firstRow = true;
0N/A
0N/A byte[] rowByteBuffer = new byte[rowByteWidth];
0N/A byte[] prevRowByteBuffer = new byte[rowByteWidth];
0N/A /* code changed. target not needed here
0N/A while (row < height && (t=target)!=null) {
0N/A */
0N/A while (row < height) {
0N/A int rowFilter = is.read();
0N/A for (int rowFillPos=0;rowFillPos<rowByteWidth; ) {
0N/A int n = is.read(rowByteBuffer,rowFillPos,rowByteWidth-rowFillPos);
0N/A if(n<=0) throw new PNGException("missing data");
0N/A rowFillPos+=n;
0N/A }
0N/A filterRow(rowByteBuffer,
0N/A firstRow ? null : prevRowByteBuffer,
0N/A rowFilter, rowByteWidth, bytesPerPixel);
0N/A int col = sCol;
0N/A int spos=0;
0N/A int pixel = 0;
0N/A while (col < width) {
0N/A if(wPixels !=null) {
0N/A switch(combinedType) {
0N/A case COLOR|ALPHA|(8<<3):
0N/A wPixels[col+rowOffset] =
0N/A ((rowByteBuffer[spos ]&0xFF)<<16)
0N/A | ((rowByteBuffer[spos+1]&0xFF)<< 8)
0N/A | ((rowByteBuffer[spos+2]&0xFF) )
0N/A | ((rowByteBuffer[spos+3]&0xFF)<<24);
0N/A spos+=4;
0N/A break;
0N/A case COLOR|ALPHA|(16<<3):
0N/A wPixels[col+rowOffset] =
0N/A ((rowByteBuffer[spos ]&0xFF)<<16)
0N/A | ((rowByteBuffer[spos+2]&0xFF)<< 8)
0N/A | ((rowByteBuffer[spos+4]&0xFF) )
0N/A | ((rowByteBuffer[spos+6]&0xFF)<<24);
0N/A spos+=8;
0N/A break;
0N/A case COLOR|(8<<3):
0N/A pixel =
0N/A ((rowByteBuffer[spos ]&0xFF)<<16)
0N/A | ((rowByteBuffer[spos+1]&0xFF)<< 8)
0N/A | ((rowByteBuffer[spos+2]&0xFF) );
0N/A if (pixel != transparentPixel) {
0N/A pixel |= 0xff000000;
0N/A }
0N/A wPixels[col+rowOffset] = pixel;
0N/A spos+=3;
0N/A break;
0N/A case COLOR|(16<<3):
0N/A pixel =
0N/A ((rowByteBuffer[spos ]&0xFF)<<16)
0N/A | ((rowByteBuffer[spos+2]&0xFF)<< 8)
0N/A | ((rowByteBuffer[spos+4]&0xFF) );
0N/A
0N/A boolean isTransparent = (transparentPixel_16 != null);
0N/A for (int i = 0; isTransparent && (i < 6); i++) {
0N/A isTransparent &=
0N/A (rowByteBuffer[spos + i] & 0xFF) == (transparentPixel_16[i] & 0xFF);
0N/A }
0N/A if (!isTransparent) {
0N/A pixel |= 0xff000000;
0N/A }
0N/A wPixels[col+rowOffset] = pixel;
0N/A spos+=6;
0N/A break;
0N/A case GRAY|ALPHA|(8<<3):
0N/A { int tx = rowByteBuffer[spos]&0xFF;
0N/A wPixels[col+rowOffset] =
0N/A (tx<<16)|(tx<<8)|tx
0N/A |((rowByteBuffer[spos+1]&0xFF)<<24); }
0N/A spos+=2;
0N/A break;
0N/A case GRAY|ALPHA|(16<<3):
0N/A { int tx = rowByteBuffer[spos]&0xFF;
0N/A wPixels[col+rowOffset] =
0N/A (tx<<16)|(tx<<8)|tx
0N/A |((rowByteBuffer[spos+2]&0xFF)<<24); }
0N/A spos+=4;
0N/A break;
0N/A default: throw new PNGException("illegal type/depth");
0N/A }
0N/A } else switch(bitDepth) {
0N/A case 1:
0N/A bPixels[col+rowOffset] =
0N/A (byte)((rowByteBuffer[spos>>3]>>(7-(spos&7)))&1);
0N/A spos++;
0N/A break;
0N/A case 2:
0N/A bPixels[col+rowOffset] =
0N/A (byte)((rowByteBuffer[spos>>2]>>((3-(spos&3))*2))&3);
0N/A spos++;
0N/A break;
0N/A case 4:
0N/A bPixels[col+rowOffset] =
0N/A (byte)((rowByteBuffer[spos>>1]>>((1-(spos&1))*4))&15);
0N/A spos++;
0N/A break;
0N/A case 8: bPixels[col+rowOffset] = rowByteBuffer[spos++];
0N/A break;
0N/A case 16: bPixels[col+rowOffset] = rowByteBuffer[spos]; spos+=2;
0N/A break;
0N/A default: throw new PNGException("illegal type/depth");
0N/A }
0N/A /*visit (row, col,
0N/A min (bHeight, height - row),
0N/A min (bWidth, width - col)); */
0N/A col += colInc;
0N/A }
0N/A if(interlaceMethod==0)
0N/A if(wPixels!=null) {
0N/A /* code changed. target not needed here
0N/A t.setPixels(0,row,width,1,cm,wPixels,0,width);
0N/A */
0N/A // code added to make it work with ImageDecoder arch
0N/A sendPixels(0,row,width,1,wPixels,0,width);
0N/A // end of adding
0N/A }
0N/A else {
0N/A /* code changed. target not needed here
0N/A t.setPixels(0,row,width,1,cm,bPixels,0,width);
0N/A */
0N/A // code added to make it work with ImageDecoder arch
0N/A sendPixels(0,row,width,1,bPixels,0,width);
0N/A //end of adding
0N/A }
0N/A row += rowInc;
0N/A rowOffset += rowInc*rowStride;
0N/A byte[] T = rowByteBuffer;
0N/A rowByteBuffer = prevRowByteBuffer;
0N/A prevRowByteBuffer = T;
0N/A firstRow = false;
0N/A }
0N/A if(interlaceMethod!=0)
0N/A if(wPixels!=null) {
0N/A /* code changed. target not needed here
0N/A t.setPixels(0,0,width,height,cm,wPixels,0,width);
0N/A */
0N/A // code added to make it work with ImageDecoder arch
0N/A sendPixels(0,0,width,height,wPixels,0,width);
0N/A //end of adding
0N/A }
0N/A else {
0N/A /* code changed. target not needed here
0N/A t.setPixels(0,0,width,height,cm,bPixels,0,width);
0N/A */
0N/A // code added to make it work with ImageDecoder arch
0N/A sendPixels(0,0,width,height,bPixels,0,width);
0N/A //end of adding
0N/A }
0N/A }
0N/A
0N/A /* Here, the function "visit(row,column,height,width)" obtains the
0N/A next transmitted pixel and paints a rectangle of the specified
0N/A height and width, whose upper-left corner is at the specified row
0N/A and column, using the color indicated by the pixel. Note that row
0N/A and column are measured from 0,0 at the upper left corner. */
0N/A
0N/A /* code not needed, don't deal with target
0N/A if((t=target)!=null) {
0N/A if(properties!=null) t.setProperties(properties);
0N/A t.imageComplete(ImageConsumer.STATICIMAGEDONE);
0N/A */
0N/A
0N/A imageComplete(ImageConsumer.STATICIMAGEDONE, true);
0N/A
0N/A /* code not needed }
0N/A is.close();
0N/A */
0N/A } catch(IOException e) {
0N/A if(!aborted) {
0N/A /* code not needed
0N/A if((t=target)!=null) {
0N/A PNGEncoder.prChunk(e.toString(),inbuf,pos,limit-pos,true);
0N/A */
0N/A property("error", e);
0N/A /* code not needed
0N/A t.setProperties(properties);
0N/A t.imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE);
0N/A */
0N/A imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE, true);
0N/A throw e;
0N/A }
0N/A } finally {
0N/A try { close(); } catch(Throwable e){}
0N/A /* code not needed
0N/A target = null;
0N/A endTurn();
0N/A */
0N/A }
0N/A }
0N/A
0N/A private boolean sendPixels(int x, int y, int w, int h, int[] pixels,
0N/A int offset, int pixlength) {
0N/A int count = setPixels(x, y, w, h, cm,
0N/A pixels, offset, pixlength);
0N/A if (count <= 0) {
0N/A aborted = true;
0N/A }
0N/A return !aborted;
0N/A }
0N/A private boolean sendPixels(int x, int y, int w, int h, byte[] pixels,
0N/A int offset, int pixlength) {
0N/A int count = setPixels(x, y, w, h, cm,
0N/A pixels, offset, pixlength);
0N/A if (count <= 0) {
0N/A aborted = true;
0N/A }
0N/A return !aborted;
0N/A }
0N/A
0N/A private void filterRow(byte rowByteBuffer[], byte[] prevRow,
0N/A int rowFilter, int rowByteWidth, int bytesPerSample)
0N/A throws IOException {
0N/A int x = 0;
0N/A switch (rowFilter) {
0N/A case 0:
0N/A break;
0N/A case 1:
0N/A for (x = bytesPerSample; x < rowByteWidth; x++)
0N/A rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
0N/A break;
0N/A case 2:
0N/A if (prevRow != null)
0N/A for ( ; x < rowByteWidth; x++)
0N/A rowByteBuffer[x] += prevRow[x];
0N/A break;
0N/A case 3:
0N/A if (prevRow != null) {
0N/A for ( ; x < bytesPerSample; x++)
0N/A rowByteBuffer[x] += (0xff & prevRow[x])>>1;
0N/A for ( ; x < rowByteWidth; x++)
0N/A rowByteBuffer[x] += ((prevRow[x]&0xFF) + (rowByteBuffer[x - bytesPerSample]&0xFF))>>1;
0N/A } else
0N/A for (x = bytesPerSample; x < rowByteWidth; x++)
0N/A rowByteBuffer[x] += (rowByteBuffer[x - bytesPerSample]&0xFF)>>1;
0N/A break;
0N/A case 4:
0N/A if (prevRow != null) {
0N/A for ( ; x < bytesPerSample; x++)
0N/A rowByteBuffer[x] += prevRow[x];
0N/A for ( ; x < rowByteWidth; x++) {
0N/A int a, b, c, p, pa, pb, pc, rval;
0N/A a = rowByteBuffer[x - bytesPerSample]&0xFF;
0N/A b = prevRow[x]&0xFF;
0N/A c = prevRow[x - bytesPerSample]&0xFF;
0N/A p = a + b - c;
0N/A pa = p > a ? p - a : a - p;
0N/A pb = p > b ? p - b : b - p;
0N/A pc = p > c ? p - c : c - p;
0N/A rowByteBuffer[x] += (pa <= pb) && (pa <= pc) ? a : pb <= pc ? b : c;
0N/A }
0N/A } else
0N/A for (x = bytesPerSample; x < rowByteWidth; x++)
0N/A rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
0N/A break;
0N/A default:
0N/A throw new PNGException("Illegal filter");
0N/A }
0N/A }
0N/A private static final byte[] startingRow = { 0, 0, 0, 4, 0, 2, 0, 1 };
0N/A private static final byte[] startingCol = { 0, 0, 4, 0, 2, 0, 1, 0 };
0N/A private static final byte[] rowIncrement = { 1, 8, 8, 8, 4, 4, 2, 2 };
0N/A private static final byte[] colIncrement = { 1, 8, 8, 4, 4, 2, 2, 1 };
0N/A private static final byte[] blockHeight = { 1, 8, 8, 4, 4, 2, 2, 1 };
0N/A private static final byte[] blockWidth = { 1, 8, 4, 4, 2, 2, 1, 1 };
0N/A
0N/A //abstract public class ChunkReader extends FilterInputStream {
0N/A int pos, limit;
0N/A int chunkStart;
0N/A int chunkKey, chunkLength, chunkCRC;
0N/A boolean seenEOF;
0N/A
0N/A private static final byte[] signature = { (byte) 137, (byte) 80, (byte) 78,
0N/A (byte) 71, (byte) 13, (byte) 10, (byte) 26, (byte) 10 };
0N/A
0N/A PNGFilterInputStream inputStream;
0N/A InputStream underlyingInputStream;
0N/A
0N/A /* code changed
0N/A public PNGImageDecoder(InputStream in, ImageConsumer t) throws IOException {
0N/A */
0N/A public PNGImageDecoder(InputStreamImageSource src, InputStream input) throws IOException {
0N/A // code added
0N/A super(src, input);
0N/A inputStream = new PNGFilterInputStream(this, input);
0N/A underlyingInputStream = inputStream.underlyingInputStream;
0N/A // end of adding
0N/A /* code changed
0N/A super(in);
0N/A target = t;
0N/A waitTurn();
0N/A new Thread(this).start();
0N/A */
0N/A }
0N/A /* code changed to make it work with ImageDecoder architecture
0N/A static int ThreadLimit = 10;
0N/A private synchronized static void waitTurn() {
0N/A try {
0N/A while(ThreadLimit<=0) PNGImageDecoder.class.wait(1000);
0N/A } catch(InterruptedException e){}
0N/A ThreadLimit--;
0N/A }
0N/A private synchronized static void endTurn() {
0N/A if(ThreadLimit<=0) PNGImageDecoder.class.notify();
0N/A ThreadLimit++;
0N/A }
0N/A */
0N/A byte[] inbuf = new byte[4096];
0N/A private void fill() throws IOException {
0N/A if(!seenEOF) {
0N/A if(pos>0 && pos<limit) {
0N/A System.arraycopy(inbuf,pos,inbuf,0,limit-pos);
0N/A limit = limit-pos;
0N/A pos = 0;
0N/A } else if(pos>=limit) {
0N/A pos = 0; limit = 0;
0N/A }
0N/A int bsize = inbuf.length;
0N/A while(limit<bsize) {
0N/A int n = underlyingInputStream.read(inbuf,limit,bsize-limit);
0N/A if(n<=0) { seenEOF=true; break; }
0N/A limit += n;
0N/A }
0N/A }
0N/A }
0N/A private boolean need(int n) throws IOException {
0N/A if(limit-pos>=n) return true;
0N/A fill();
0N/A if(limit-pos>=n) return true;
0N/A if(seenEOF) return false;
0N/A byte nin[] = new byte[n+100];
0N/A System.arraycopy(inbuf,pos,nin,0,limit-pos);
0N/A limit = limit-pos;
0N/A pos = 0;
0N/A inbuf = nin;
0N/A fill();
0N/A return limit-pos>=n;
0N/A }
0N/A private final int getInt(int pos) {
0N/A return ((inbuf[pos ]&0xFF)<<24)
0N/A | ((inbuf[pos+1]&0xFF)<<16)
0N/A | ((inbuf[pos+2]&0xFF)<< 8)
0N/A | ((inbuf[pos+3]&0xFF) );
0N/A }
0N/A private final int getShort(int pos) {
0N/A return (short)(((inbuf[pos ]&0xFF)<<8)
0N/A | ((inbuf[pos+1]&0xFF) ));
0N/A }
0N/A private final int getByte(int pos) {
0N/A return inbuf[pos]&0xFF;
0N/A }
0N/A private final boolean getChunk() throws IOException {
0N/A chunkLength = 0;
0N/A if (!need(8)) return false;
0N/A chunkLength = getInt(pos);
0N/A chunkKey = getInt(pos+4);
0N/A if(chunkLength<0) throw new PNGException("bogus length: "+chunkLength);
0N/A if (!need(chunkLength+12)) return false;
0N/A chunkCRC = getInt(pos+8+chunkLength);
0N/A chunkStart = pos+8;
0N/A int calcCRC = crc(inbuf,pos+4,chunkLength+4);
0N/A if(chunkCRC!=calcCRC && checkCRC) throw new PNGException("crc corruption");
0N/A pos+=chunkLength+12;
0N/A return true;
0N/A }
0N/A private void readAll() throws IOException {
0N/A while(getChunk()) handleChunk(chunkKey,inbuf,chunkStart,chunkLength);
0N/A }
0N/A boolean getData() throws IOException {
0N/A while(chunkLength==0 && getChunk())
0N/A if(handleChunk(chunkKey,inbuf,chunkStart,chunkLength))
0N/A chunkLength = 0;
0N/A return chunkLength>0;
0N/A }
0N/A //abstract protected boolean handleChunk(int key, byte[] buf, int st, int len)
0N/A // throws IOException;
0N/A private static boolean checkCRC = true;
0N/A public static boolean getCheckCRC() { return checkCRC; }
0N/A public static void setCheckCRC(boolean c) { checkCRC = c; }
0N/A
0N/A protected void wrc(int c) {
0N/A c = c&0xFF;
0N/A if(c<=' '||c>'z') c = '?';
0N/A System.out.write(c);
0N/A }
0N/A protected void wrk(int n) {
0N/A wrc(n>>24);
0N/A wrc(n>>16);
0N/A wrc(n>>8);
0N/A wrc(n);
0N/A }
0N/A public void print() {
0N/A wrk(chunkKey);
0N/A System.out.print(" "+chunkLength+"\n");
0N/A }
0N/A
0N/A /* Table of CRCs of all 8-bit messages. */
0N/A private static final int[] crc_table = new int[256];
0N/A
0N/A /* Make the table for a fast CRC. */
0N/A static {
0N/A for (int n = 0; n < 256; n++) {
0N/A int c = n;
0N/A for (int k = 0; k < 8; k++)
0N/A if ((c & 1) != 0)
0N/A c = 0xedb88320 ^ (c >>> 1);
0N/A else
0N/A c = c >>> 1;
0N/A crc_table[n] = c;
0N/A }
0N/A }
0N/A
0N/A /* Update a running CRC with the bytes buf[0..len-1]--the CRC
0N/A should be initialized to all 1's, and the transmitted value
0N/A is the 1's complement of the final running CRC (see the
0N/A crc() routine below)). */
0N/A
0N/A static private int update_crc(int crc, byte[] buf, int offset, int len) {
0N/A int c = crc;
0N/A while (--len>=0)
0N/A c = crc_table[(c ^ buf[offset++]) & 0xff] ^ (c >>> 8);
0N/A return c;
0N/A }
0N/A
0N/A /* Return the CRC of the bytes buf[0..len-1]. */
0N/A static private int crc(byte[] buf, int offset, int len) {
0N/A return update_crc(0xffffffff, buf, offset, len) ^ 0xffffffff;
0N/A }
0N/A public static class Chromaticities {
0N/A public float whiteX, whiteY, redX, redY, greenX, greenY, blueX, blueY;
0N/A Chromaticities(int wx, int wy, int rx, int ry, int gx, int gy, int bx, int by) {
0N/A whiteX = wx/100000.0f;
0N/A whiteY = wy/100000.0f;
0N/A redX = rx/100000.0f;
0N/A redY = ry/100000.0f;
0N/A greenX = gx/100000.0f;
0N/A greenY = gy/100000.0f;
0N/A blueX = bx/100000.0f;
0N/A blueY = by/100000.0f;
0N/A }
0N/A public String toString() {
0N/A return "Chromaticities(white="+whiteX+","+whiteY+";red="+
0N/A redX+","+redY+";green="+
0N/A greenX+","+greenY+";blue="+
0N/A blueX+","+blueY+")";
0N/A }
0N/A }
0N/A}
0N/A
0N/A// the following class are added to make it work with ImageDecoder architecture
0N/A
0N/Aclass PNGFilterInputStream extends FilterInputStream {
0N/A PNGImageDecoder owner;
0N/A public InputStream underlyingInputStream;
0N/A public PNGFilterInputStream(PNGImageDecoder owner, InputStream is) {
0N/A super(is);
0N/A underlyingInputStream = in;
0N/A this.owner = owner;
0N/A }
0N/A
0N/A public int available() throws IOException {
0N/A return owner.limit-owner.pos+in.available();}
0N/A public boolean markSupported() { return false; }
0N/A public int read() throws IOException {
0N/A if(owner.chunkLength<=0) if(!owner.getData()) return -1;
0N/A owner.chunkLength--;
0N/A return owner.inbuf[owner.chunkStart++]&0xFF;
0N/A }
0N/A public int read(byte[] b) throws IOException{return read(b,0,b.length);}
0N/A public int read(byte[] b, int st, int len) throws IOException {
0N/A if(owner.chunkLength<=0) if(!owner.getData()) return -1;
0N/A if(owner.chunkLength<len) len = owner.chunkLength;
0N/A System.arraycopy(owner.inbuf,owner.chunkStart,b,st,len);
0N/A owner.chunkLength-=len;
0N/A owner.chunkStart+=len;
0N/A return len;
0N/A }
0N/A public long skip(long n) throws IOException {
0N/A int i;
0N/A for(i = 0; i<n && read()>=0; i++);
0N/A return i;
0N/A }
0N/A
0N/A
0N/A}