History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/awt/image/PNGImageDecoder.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/awt/image/PNGImageDecoder.java+840−0
@@ -0,0 +1,840 @@
1+/*
2+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.awt.image;
27+
28+import java.io.*;
29+import java.util.*;
30+import java.util.zip.*;
31+import java.awt.image.*;
32+import java.awt.Color;
33+
34+/** PNG - Portable Network Graphics - image file reader.
35+ See <a href=http://www.ietf.org/rfc/rfc2083.txt>RFC2083</a> for details. */
36+
37+/* this is changed
38+public class PNGImageDecoder extends FilterInputStream implements Runnable
39+{ */
40+
41+public class PNGImageDecoder extends ImageDecoder
42+{
43+ private static final int GRAY=0;
44+ private static final int PALETTE=1;
45+ private static final int COLOR=2;
46+ private static final int ALPHA=4;
47+
48+ private static final int bKGDChunk = 0x624B4744;
49+ private static final int cHRMChunk = 0x6348524D;
50+ private static final int gAMAChunk = 0x67414D41;
51+ private static final int hISTChunk = 0x68495354;
52+ private static final int IDATChunk = 0x49444154;
53+ private static final int IENDChunk = 0x49454E44;
54+ private static final int IHDRChunk = 0x49484452;
55+ private static final int PLTEChunk = 0x504C5445;
56+ private static final int pHYsChunk = 0x70485973;
57+ private static final int sBITChunk = 0x73424954;
58+ private static final int tEXtChunk = 0x74455874;
59+ private static final int tIMEChunk = 0x74494D45;
60+ private static final int tRNSChunk = 0x74524E53;
61+ private static final int zTXtChunk = 0x7A545874;
62+
63+ private int width;
64+ private int height;
65+ private int bitDepth;
66+ private int colorType;
67+ private int compressionMethod;
68+ private int filterMethod;
69+ private int interlaceMethod;
70+ private int gamma = 100000;
71+ private java.util.Hashtable properties;
72+ /* this is not needed
73+ ImageConsumer target;
74+ */
75+ private ColorModel cm;
76+ private byte[] red_map, green_map, blue_map, alpha_map;
77+ private int transparentPixel = -1;
78+ private byte[] transparentPixel_16 = null; // we need 6 bytes to store 16bpp value
79+ private static ColorModel greyModels[] = new ColorModel[4];
80+ /* this is not needed
81+ PNGImageDecoder next;
82+ */
83+
84+ private void property(String key,Object value) {
85+ if(value==null) return;
86+ if(properties==null) properties=new java.util.Hashtable();
87+ properties.put(key,value);
88+ }
89+ private void property(String key,float value) {
90+ property(key,new Float(value));
91+ }
92+ private final void pngassert(boolean b) throws IOException {
93+ if(!b) {
94+ PNGException e = new PNGException("Broken file");
95+ e.printStackTrace();
96+ throw e;
97+ }
98+ }
99+ protected boolean handleChunk(int key, byte[] buf, int st, int len)
100+ throws IOException {
101+ switch(key) {
102+ case bKGDChunk:
103+ Color c = null;
104+ switch(colorType) {
105+ case COLOR:
106+ case COLOR|ALPHA:
107+ pngassert(len==6);
108+ c = new Color(buf[st]&0xff,buf[st+2]&0xff,buf[st+4]&0xff);
109+ break;
110+ case COLOR|PALETTE:
111+ case COLOR|PALETTE|ALPHA:
112+ pngassert(len==1);
113+ int ix = buf[st]&0xFF;
114+ pngassert(red_map!=null && ix<red_map.length);
115+ c = new Color(red_map[ix]&0xff,green_map[ix]&0xff,blue_map[ix]&0xff);
116+ break;
117+ case GRAY:
118+ case GRAY|ALPHA:
119+ pngassert(len==2);
120+ int t = buf[st]&0xFF;
121+ c = new Color(t,t,t);
122+ break;
123+ }
124+ if(c!=null) property("background",c);
125+ break;
126+ case cHRMChunk:
127+ property("chromaticities",
128+ new Chromaticities(
129+ getInt(st),
130+ getInt(st+4),
131+ getInt(st+8),
132+ getInt(st+12),
133+ getInt(st+16),
134+ getInt(st+20),
135+ getInt(st+24),
136+ getInt(st+28)));
137+ break;
138+ case gAMAChunk:
139+ if(len!=4) throw new PNGException("bogus gAMA");
140+ gamma = getInt(st);
141+ if(gamma!=100000) property("gamma",gamma/100000.0f);
142+ break;
143+ case hISTChunk: break;
144+ case IDATChunk: return false;
145+ case IENDChunk: break;
146+ case IHDRChunk:
147+ if(len!=13
148+ ||(width = getInt(st))==0
149+ ||(height = getInt(st+4))==0
150+ ) throw new PNGException("bogus IHDR");
151+ bitDepth = getByte(st+8);
152+ colorType = getByte(st+9);
153+ compressionMethod = getByte(st+10);
154+ filterMethod = getByte(st+11);
155+ interlaceMethod = getByte(st+12);
156+ /* this is not needed
157+ if(target!=null) target.setDimensions(width,height);
158+ */
159+ break;
160+ case PLTEChunk:
161+ { int tsize = len/3;
162+ red_map = new byte[tsize];
163+ green_map = new byte[tsize];
164+ blue_map = new byte[tsize];
165+ for(int i=0,j=st; i<tsize; i++, j+=3) {
166+ red_map[i] = buf[j];
167+ green_map[i] = buf[j+1];
168+ blue_map[i] = buf[j+2];
169+ }
170+ }
171+ break;
172+ case pHYsChunk: break;
173+ case sBITChunk: break;
174+ case tEXtChunk:
175+ int klen = 0;
176+ while(klen<len && buf[st+klen]!=0) klen++;
177+ if(klen<len) {
178+ String tkey = new String(buf,st,klen);
179+ String tvalue = new String(buf,st+klen+1,len-klen-1);
180+ property(tkey,tvalue);
181+ }
182+ break;
183+ case tIMEChunk:
184+ property("modtime",new GregorianCalendar(
185+ getShort(st+0),
186+ getByte(st+2)-1,
187+ getByte(st+3),
188+ getByte(st+4),
189+ getByte(st+5),
190+ getByte(st+6)).getTime());
191+ break;
192+ case tRNSChunk:
193+ switch(colorType) {
194+ case PALETTE|COLOR:
195+ case PALETTE|COLOR|ALPHA:
196+ int alen = len;
197+ if(red_map!=null) alen = red_map.length;
198+ alpha_map = new byte[alen];
199+ System.arraycopy(buf,st,alpha_map,0,len<alen ? len : alen);
200+ while (--alen>=len) alpha_map[alen] = (byte)0xFF;
201+ break;
202+ case COLOR: // doesn't deal with 16 bit colors properly
203+ case COLOR|ALPHA: // doesn't deal with 16 bit colors properly
204+ pngassert(len==6);
205+ if (bitDepth == 16) {
206+ transparentPixel_16 = new byte[6];
207+ for (int i = 0; i < 6; i++) {
208+ transparentPixel_16[i] = (byte)getByte(st + i);
209+ }
210+ } else {
211+ transparentPixel =
212+ ((getShort(st + 0)&0xFF)<<16)
213+ | ((getShort(st + 2)&0xFF)<< 8)
214+ | ((getShort(st + 4)&0xFF) );
215+ }
216+ break;
217+ case GRAY: // doesn't deal with 16 bit colors properly
218+ case GRAY|ALPHA: // doesn't deal with 16 bit colors properly
219+ pngassert(len==2);
220+ /* REMIND: Discarding the LSB for 16 bit depth here
221+ * means that the all pixels which match the MSB
222+ * will be treated as transparent.
223+ */
224+ int t = getShort(st);
225+ t = 0xFF & ((bitDepth == 16) ? (t >> 8) : t);
226+ transparentPixel = (t<<16) | (t<< 8) | t;
227+ break;
228+ }
229+ break;
230+ case zTXtChunk: break;
231+ }
232+ return true;
233+ }
234+ public class PNGException extends IOException {
235+ PNGException(String s) { super(s); }
236+ }
237+ /* this is changed
238+ public void run() {
239+ */
240+ public void produceImage() throws IOException, ImageFormatException {
241+ /* this is not needed
242+ ImageConsumer t = target;
243+ if(t!=null) try {
244+ */
245+ try {
246+ for(int i=0; i<signature.length; i++)
247+ if((signature[i]&0xFF)!=underlyingInputStream.read())
248+ throw new PNGException("Chunk signature mismatch");
249+
250+ InputStream is = new BufferedInputStream(new InflaterInputStream(inputStream,new Inflater()));
251+
252+ getData();
253+
254+ byte[] bPixels = null;
255+ int[] wPixels = null;
256+ int pixSize = width;
257+ int rowStride;
258+ int logDepth = 0;
259+ switch(bitDepth) {
260+ case 1: logDepth = 0; break;
261+ case 2: logDepth = 1; break;
262+ case 4: logDepth = 2; break;
263+ case 8: logDepth = 3; break;
264+ case 16: logDepth = 4; break;
265+ default: throw new PNGException("invalid depth");
266+ }
267+ if(interlaceMethod!=0) {pixSize *= height;rowStride=width;}
268+ else rowStride = 0;
269+ int combinedType = colorType|(bitDepth<<3);
270+ int bitMask = (1<<(bitDepth>=8?8:bitDepth))-1;
271+ //Figure out the color model
272+ switch(colorType) {
273+ case COLOR|PALETTE:
274+ case COLOR|PALETTE|ALPHA:
275+ if(red_map==null) throw new PNGException("palette expected");
276+ if(alpha_map==null)
277+ cm = new IndexColorModel(bitDepth,red_map.length,
278+ red_map,green_map,blue_map);
279+ else
280+ cm = new IndexColorModel(bitDepth,red_map.length,
281+ red_map,green_map,blue_map,alpha_map);
282+ bPixels = new byte[pixSize];
283+ break;
284+ case GRAY:
285+ { int llog = logDepth>=4 ? 3 : logDepth;
286+ if((cm=greyModels[llog]) == null) {
287+ int size = 1<<(1<<llog);
288+
289+ byte ramp[] = new byte[size];
290+ for(int i = 0; i<size; i++) ramp[i] = (byte)(255*i/(size-1));
291+
292+ if (transparentPixel == -1) {
293+ cm = new IndexColorModel(bitDepth,ramp.length,ramp,ramp,ramp);
294+ } else {
295+ cm = new IndexColorModel(bitDepth,ramp.length,ramp,ramp,ramp,
296+ (transparentPixel & 0xFF));
297+ }
298+ greyModels[llog] = cm;
299+ }
300+ }
301+ bPixels = new byte[pixSize];
302+ break;
303+ case COLOR:
304+ case COLOR|ALPHA:
305+ case GRAY|ALPHA:
306+ cm = ColorModel.getRGBdefault();
307+ wPixels = new int[pixSize];
308+ break;
309+ default:
310+ throw new PNGException("invalid color type");
311+ }
312+ /* this is going to be set in the pixel store
313+ t.setColorModel(cm);
314+ t.setHints(interlaceMethod !=0
315+ ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
316+ : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
317+ ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
318+ */
319+ // code added to make it work with ImageDecoder architecture
320+ setDimensions(width, height);
321+ setColorModel(cm);
322+ int flags = (interlaceMethod !=0
323+ ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
324+ : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
325+ ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
326+ setHints(flags);
327+ headerComplete();
328+ // end of adding
329+
330+ int samplesPerPixel = ((colorType&PALETTE)!=0 ? 1
331+ : ((colorType&COLOR)!=0 ? 3 : 1)+((colorType&ALPHA)!=0?1:0));
332+ int bitsPerPixel = samplesPerPixel*bitDepth;
333+ int bytesPerPixel = (bitsPerPixel+7)>>3;
334+ int pass, passLimit;
335+ if(interlaceMethod==0) { pass = -1; passLimit = 0; }
336+ else { pass = 0; passLimit = 7; }
337+ // These loops are far from being tuned. They're this way to make them easy to
338+ // debug. Tuning comes later.
339+ /* code changed. target not needed here
340+ while(++pass<=passLimit && (t=target)!=null) {
341+ */
342+ while(++pass<=passLimit) {
343+ int row = startingRow[pass];
344+ int rowInc = rowIncrement[pass];
345+ int colInc = colIncrement[pass];
346+ int bWidth = blockWidth[pass];
347+ int bHeight = blockHeight[pass];
348+ int sCol = startingCol[pass];
349+ int rowPixelWidth = (width-sCol+(colInc-1))/colInc;
350+ int rowByteWidth = ((rowPixelWidth*bitsPerPixel)+7)>>3;
351+ if(rowByteWidth==0) continue;
352+ int pixelBufferInc = interlaceMethod==0 ? rowInc*width : 0;
353+ int rowOffset = rowStride*row;
354+ boolean firstRow = true;
355+
356+ byte[] rowByteBuffer = new byte[rowByteWidth];
357+ byte[] prevRowByteBuffer = new byte[rowByteWidth];
358+ /* code changed. target not needed here
359+ while (row < height && (t=target)!=null) {
360+ */
361+ while (row < height) {
362+ int rowFilter = is.read();
363+ for (int rowFillPos=0;rowFillPos<rowByteWidth; ) {
364+ int n = is.read(rowByteBuffer,rowFillPos,rowByteWidth-rowFillPos);
365+ if(n<=0) throw new PNGException("missing data");
366+ rowFillPos+=n;
367+ }
368+ filterRow(rowByteBuffer,
369+ firstRow ? null : prevRowByteBuffer,
370+ rowFilter, rowByteWidth, bytesPerPixel);
371+ int col = sCol;
372+ int spos=0;
373+ int pixel = 0;
374+ while (col < width) {
375+ if(wPixels !=null) {
376+ switch(combinedType) {
377+ case COLOR|ALPHA|(8<<3):
378+ wPixels[col+rowOffset] =
379+ ((rowByteBuffer[spos ]&0xFF)<<16)
380+ | ((rowByteBuffer[spos+1]&0xFF)<< 8)
381+ | ((rowByteBuffer[spos+2]&0xFF) )
382+ | ((rowByteBuffer[spos+3]&0xFF)<<24);
383+ spos+=4;
384+ break;
385+ case COLOR|ALPHA|(16<<3):
386+ wPixels[col+rowOffset] =
387+ ((rowByteBuffer[spos ]&0xFF)<<16)
388+ | ((rowByteBuffer[spos+2]&0xFF)<< 8)
389+ | ((rowByteBuffer[spos+4]&0xFF) )
390+ | ((rowByteBuffer[spos+6]&0xFF)<<24);
391+ spos+=8;
392+ break;
393+ case COLOR|(8<<3):
394+ pixel =
395+ ((rowByteBuffer[spos ]&0xFF)<<16)
396+ | ((rowByteBuffer[spos+1]&0xFF)<< 8)
397+ | ((rowByteBuffer[spos+2]&0xFF) );
398+ if (pixel != transparentPixel) {
399+ pixel |= 0xff000000;
400+ }
401+ wPixels[col+rowOffset] = pixel;
402+ spos+=3;
403+ break;
404+ case COLOR|(16<<3):
405+ pixel =
406+ ((rowByteBuffer[spos ]&0xFF)<<16)
407+ | ((rowByteBuffer[spos+2]&0xFF)<< 8)
408+ | ((rowByteBuffer[spos+4]&0xFF) );
409+
410+ boolean isTransparent = (transparentPixel_16 != null);
411+ for (int i = 0; isTransparent && (i < 6); i++) {
412+ isTransparent &=
413+ (rowByteBuffer[spos + i] & 0xFF) == (transparentPixel_16[i] & 0xFF);
414+ }
415+ if (!isTransparent) {
416+ pixel |= 0xff000000;
417+ }
418+ wPixels[col+rowOffset] = pixel;
419+ spos+=6;
420+ break;
421+ case GRAY|ALPHA|(8<<3):
422+ { int tx = rowByteBuffer[spos]&0xFF;
423+ wPixels[col+rowOffset] =
424+ (tx<<16)|(tx<<8)|tx
425+ |((rowByteBuffer[spos+1]&0xFF)<<24); }
426+ spos+=2;
427+ break;
428+ case GRAY|ALPHA|(16<<3):
429+ { int tx = rowByteBuffer[spos]&0xFF;
430+ wPixels[col+rowOffset] =
431+ (tx<<16)|(tx<<8)|tx
432+ |((rowByteBuffer[spos+2]&0xFF)<<24); }
433+ spos+=4;
434+ break;
435+ default: throw new PNGException("illegal type/depth");
436+ }
437+ } else switch(bitDepth) {
438+ case 1:
439+ bPixels[col+rowOffset] =
440+ (byte)((rowByteBuffer[spos>>3]>>(7-(spos&7)))&1);
441+ spos++;
442+ break;
443+ case 2:
444+ bPixels[col+rowOffset] =
445+ (byte)((rowByteBuffer[spos>>2]>>((3-(spos&3))*2))&3);
446+ spos++;
447+ break;
448+ case 4:
449+ bPixels[col+rowOffset] =
450+ (byte)((rowByteBuffer[spos>>1]>>((1-(spos&1))*4))&15);
451+ spos++;
452+ break;
453+ case 8: bPixels[col+rowOffset] = rowByteBuffer[spos++];
454+ break;
455+ case 16: bPixels[col+rowOffset] = rowByteBuffer[spos]; spos+=2;
456+ break;
457+ default: throw new PNGException("illegal type/depth");
458+ }
459+ /*visit (row, col,
460+ min (bHeight, height - row),
461+ min (bWidth, width - col)); */
462+ col += colInc;
463+ }
464+ if(interlaceMethod==0)
465+ if(wPixels!=null) {
466+ /* code changed. target not needed here
467+ t.setPixels(0,row,width,1,cm,wPixels,0,width);
468+ */
469+ // code added to make it work with ImageDecoder arch
470+ sendPixels(0,row,width,1,wPixels,0,width);
471+ // end of adding
472+ }
473+ else {
474+ /* code changed. target not needed here
475+ t.setPixels(0,row,width,1,cm,bPixels,0,width);
476+ */
477+ // code added to make it work with ImageDecoder arch
478+ sendPixels(0,row,width,1,bPixels,0,width);
479+ //end of adding
480+ }
481+ row += rowInc;
482+ rowOffset += rowInc*rowStride;
483+ byte[] T = rowByteBuffer;
484+ rowByteBuffer = prevRowByteBuffer;
485+ prevRowByteBuffer = T;
486+ firstRow = false;
487+ }
488+ if(interlaceMethod!=0)
489+ if(wPixels!=null) {
490+ /* code changed. target not needed here
491+ t.setPixels(0,0,width,height,cm,wPixels,0,width);
492+ */
493+ // code added to make it work with ImageDecoder arch
494+ sendPixels(0,0,width,height,wPixels,0,width);
495+ //end of adding
496+ }
497+ else {
498+ /* code changed. target not needed here
499+ t.setPixels(0,0,width,height,cm,bPixels,0,width);
500+ */
501+ // code added to make it work with ImageDecoder arch
502+ sendPixels(0,0,width,height,bPixels,0,width);
503+ //end of adding
504+ }
505+ }
506+
507+ /* Here, the function "visit(row,column,height,width)" obtains the
508+ next transmitted pixel and paints a rectangle of the specified
509+ height and width, whose upper-left corner is at the specified row
510+ and column, using the color indicated by the pixel. Note that row
511+ and column are measured from 0,0 at the upper left corner. */
512+
513+ /* code not needed, don't deal with target
514+ if((t=target)!=null) {
515+ if(properties!=null) t.setProperties(properties);
516+ t.imageComplete(ImageConsumer.STATICIMAGEDONE);
517+ */
518+
519+ imageComplete(ImageConsumer.STATICIMAGEDONE, true);
520+
521+ /* code not needed }
522+ is.close();
523+ */
524+ } catch(IOException e) {
525+ if(!aborted) {
526+ /* code not needed
527+ if((t=target)!=null) {
528+ PNGEncoder.prChunk(e.toString(),inbuf,pos,limit-pos,true);
529+ */
530+ property("error", e);
531+ /* code not needed
532+ t.setProperties(properties);
533+ t.imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE);
534+ */
535+ imageComplete(ImageConsumer.IMAGEERROR|ImageConsumer.STATICIMAGEDONE, true);
536+ throw e;
537+ }
538+ } finally {
539+ try { close(); } catch(Throwable e){}
540+ /* code not needed
541+ target = null;
542+ endTurn();
543+ */
544+ }
545+ }
546+
547+ private boolean sendPixels(int x, int y, int w, int h, int[] pixels,
548+ int offset, int pixlength) {
549+ int count = setPixels(x, y, w, h, cm,
550+ pixels, offset, pixlength);
551+ if (count <= 0) {
552+ aborted = true;
553+ }
554+ return !aborted;
555+ }
556+ private boolean sendPixels(int x, int y, int w, int h, byte[] pixels,
557+ int offset, int pixlength) {
558+ int count = setPixels(x, y, w, h, cm,
559+ pixels, offset, pixlength);
560+ if (count <= 0) {
561+ aborted = true;
562+ }
563+ return !aborted;
564+ }
565+
566+ private void filterRow(byte rowByteBuffer[], byte[] prevRow,
567+ int rowFilter, int rowByteWidth, int bytesPerSample)
568+ throws IOException {
569+ int x = 0;
570+ switch (rowFilter) {
571+ case 0:
572+ break;
573+ case 1:
574+ for (x = bytesPerSample; x < rowByteWidth; x++)
575+ rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
576+ break;
577+ case 2:
578+ if (prevRow != null)
579+ for ( ; x < rowByteWidth; x++)
580+ rowByteBuffer[x] += prevRow[x];
581+ break;
582+ case 3:
583+ if (prevRow != null) {
584+ for ( ; x < bytesPerSample; x++)
585+ rowByteBuffer[x] += (0xff & prevRow[x])>>1;
586+ for ( ; x < rowByteWidth; x++)
587+ rowByteBuffer[x] += ((prevRow[x]&0xFF) + (rowByteBuffer[x - bytesPerSample]&0xFF))>>1;
588+ } else
589+ for (x = bytesPerSample; x < rowByteWidth; x++)
590+ rowByteBuffer[x] += (rowByteBuffer[x - bytesPerSample]&0xFF)>>1;
591+ break;
592+ case 4:
593+ if (prevRow != null) {
594+ for ( ; x < bytesPerSample; x++)
595+ rowByteBuffer[x] += prevRow[x];
596+ for ( ; x < rowByteWidth; x++) {
597+ int a, b, c, p, pa, pb, pc, rval;
598+ a = rowByteBuffer[x - bytesPerSample]&0xFF;
599+ b = prevRow[x]&0xFF;
600+ c = prevRow[x - bytesPerSample]&0xFF;
601+ p = a + b - c;
602+ pa = p > a ? p - a : a - p;
603+ pb = p > b ? p - b : b - p;
604+ pc = p > c ? p - c : c - p;
605+ rowByteBuffer[x] += (pa <= pb) && (pa <= pc) ? a : pb <= pc ? b : c;
606+ }
607+ } else
608+ for (x = bytesPerSample; x < rowByteWidth; x++)
609+ rowByteBuffer[x] += rowByteBuffer[x - bytesPerSample];
610+ break;
611+ default:
612+ throw new PNGException("Illegal filter");
613+ }
614+ }
615+ private static final byte[] startingRow = { 0, 0, 0, 4, 0, 2, 0, 1 };
616+ private static final byte[] startingCol = { 0, 0, 4, 0, 2, 0, 1, 0 };
617+ private static final byte[] rowIncrement = { 1, 8, 8, 8, 4, 4, 2, 2 };
618+ private static final byte[] colIncrement = { 1, 8, 8, 4, 4, 2, 2, 1 };
619+ private static final byte[] blockHeight = { 1, 8, 8, 4, 4, 2, 2, 1 };
620+ private static final byte[] blockWidth = { 1, 8, 4, 4, 2, 2, 1, 1 };
621+
622+ //abstract public class ChunkReader extends FilterInputStream {
623+ int pos, limit;
624+ int chunkStart;
625+ int chunkKey, chunkLength, chunkCRC;
626+ boolean seenEOF;
627+
628+ private static final byte[] signature = { (byte) 137, (byte) 80, (byte) 78,
629+ (byte) 71, (byte) 13, (byte) 10, (byte) 26, (byte) 10 };
630+
631+ PNGFilterInputStream inputStream;
632+ InputStream underlyingInputStream;
633+
634+ /* code changed
635+ public PNGImageDecoder(InputStream in, ImageConsumer t) throws IOException {
636+ */
637+ public PNGImageDecoder(InputStreamImageSource src, InputStream input) throws IOException {
638+ // code added
639+ super(src, input);
640+ inputStream = new PNGFilterInputStream(this, input);
641+ underlyingInputStream = inputStream.underlyingInputStream;
642+ // end of adding
643+ /* code changed
644+ super(in);
645+ target = t;
646+ waitTurn();
647+ new Thread(this).start();
648+ */
649+ }
650+ /* code changed to make it work with ImageDecoder architecture
651+ static int ThreadLimit = 10;
652+ private synchronized static void waitTurn() {
653+ try {
654+ while(ThreadLimit<=0) PNGImageDecoder.class.wait(1000);
655+ } catch(InterruptedException e){}
656+ ThreadLimit--;
657+ }
658+ private synchronized static void endTurn() {
659+ if(ThreadLimit<=0) PNGImageDecoder.class.notify();
660+ ThreadLimit++;
661+ }
662+ */
663+ byte[] inbuf = new byte[4096];
664+ private void fill() throws IOException {
665+ if(!seenEOF) {
666+ if(pos>0 && pos<limit) {
667+ System.arraycopy(inbuf,pos,inbuf,0,limit-pos);
668+ limit = limit-pos;
669+ pos = 0;
670+ } else if(pos>=limit) {
671+ pos = 0; limit = 0;
672+ }
673+ int bsize = inbuf.length;
674+ while(limit<bsize) {
675+ int n = underlyingInputStream.read(inbuf,limit,bsize-limit);
676+ if(n<=0) { seenEOF=true; break; }
677+ limit += n;
678+ }
679+ }
680+ }
681+ private boolean need(int n) throws IOException {
682+ if(limit-pos>=n) return true;
683+ fill();
684+ if(limit-pos>=n) return true;
685+ if(seenEOF) return false;
686+ byte nin[] = new byte[n+100];
687+ System.arraycopy(inbuf,pos,nin,0,limit-pos);
688+ limit = limit-pos;
689+ pos = 0;
690+ inbuf = nin;
691+ fill();
692+ return limit-pos>=n;
693+ }
694+ private final int getInt(int pos) {
695+ return ((inbuf[pos ]&0xFF)<<24)
696+ | ((inbuf[pos+1]&0xFF)<<16)
697+ | ((inbuf[pos+2]&0xFF)<< 8)
698+ | ((inbuf[pos+3]&0xFF) );
699+ }
700+ private final int getShort(int pos) {
701+ return (short)(((inbuf[pos ]&0xFF)<<8)
702+ | ((inbuf[pos+1]&0xFF) ));
703+ }
704+ private final int getByte(int pos) {
705+ return inbuf[pos]&0xFF;
706+ }
707+ private final boolean getChunk() throws IOException {
708+ chunkLength = 0;
709+ if (!need(8)) return false;
710+ chunkLength = getInt(pos);
711+ chunkKey = getInt(pos+4);
712+ if(chunkLength<0) throw new PNGException("bogus length: "+chunkLength);
713+ if (!need(chunkLength+12)) return false;
714+ chunkCRC = getInt(pos+8+chunkLength);
715+ chunkStart = pos+8;
716+ int calcCRC = crc(inbuf,pos+4,chunkLength+4);
717+ if(chunkCRC!=calcCRC && checkCRC) throw new PNGException("crc corruption");
718+ pos+=chunkLength+12;
719+ return true;
720+ }
721+ private void readAll() throws IOException {
722+ while(getChunk()) handleChunk(chunkKey,inbuf,chunkStart,chunkLength);
723+ }
724+ boolean getData() throws IOException {
725+ while(chunkLength==0 && getChunk())
726+ if(handleChunk(chunkKey,inbuf,chunkStart,chunkLength))
727+ chunkLength = 0;
728+ return chunkLength>0;
729+ }
730+ //abstract protected boolean handleChunk(int key, byte[] buf, int st, int len)
731+ // throws IOException;
732+ private static boolean checkCRC = true;
733+ public static boolean getCheckCRC() { return checkCRC; }
734+ public static void setCheckCRC(boolean c) { checkCRC = c; }
735+
736+ protected void wrc(int c) {
737+ c = c&0xFF;
738+ if(c<=' '||c>'z') c = '?';
739+ System.out.write(c);
740+ }
741+ protected void wrk(int n) {
742+ wrc(n>>24);
743+ wrc(n>>16);
744+ wrc(n>>8);
745+ wrc(n);
746+ }
747+ public void print() {
748+ wrk(chunkKey);
749+ System.out.print(" "+chunkLength+"\n");
750+ }
751+
752+ /* Table of CRCs of all 8-bit messages. */
753+ private static final int[] crc_table = new int[256];
754+
755+ /* Make the table for a fast CRC. */
756+ static {
757+ for (int n = 0; n < 256; n++) {
758+ int c = n;
759+ for (int k = 0; k < 8; k++)
760+ if ((c & 1) != 0)
761+ c = 0xedb88320 ^ (c >>> 1);
762+ else
763+ c = c >>> 1;
764+ crc_table[n] = c;
765+ }
766+ }
767+
768+ /* Update a running CRC with the bytes buf[0..len-1]--the CRC
769+ should be initialized to all 1's, and the transmitted value
770+ is the 1's complement of the final running CRC (see the
771+ crc() routine below)). */
772+
773+ static private int update_crc(int crc, byte[] buf, int offset, int len) {
774+ int c = crc;
775+ while (--len>=0)
776+ c = crc_table[(c ^ buf[offset++]) & 0xff] ^ (c >>> 8);
777+ return c;
778+ }
779+
780+ /* Return the CRC of the bytes buf[0..len-1]. */
781+ static private int crc(byte[] buf, int offset, int len) {
782+ return update_crc(0xffffffff, buf, offset, len) ^ 0xffffffff;
783+ }
784+ public static class Chromaticities {
785+ public float whiteX, whiteY, redX, redY, greenX, greenY, blueX, blueY;
786+ Chromaticities(int wx, int wy, int rx, int ry, int gx, int gy, int bx, int by) {
787+ whiteX = wx/100000.0f;
788+ whiteY = wy/100000.0f;
789+ redX = rx/100000.0f;
790+ redY = ry/100000.0f;
791+ greenX = gx/100000.0f;
792+ greenY = gy/100000.0f;
793+ blueX = bx/100000.0f;
794+ blueY = by/100000.0f;
795+ }
796+ public String toString() {
797+ return "Chromaticities(white="+whiteX+","+whiteY+";red="+
798+ redX+","+redY+";green="+
799+ greenX+","+greenY+";blue="+
800+ blueX+","+blueY+")";
801+ }
802+ }
803+}
804+
805+// the following class are added to make it work with ImageDecoder architecture
806+
807+class PNGFilterInputStream extends FilterInputStream {
808+ PNGImageDecoder owner;
809+ public InputStream underlyingInputStream;
810+ public PNGFilterInputStream(PNGImageDecoder owner, InputStream is) {
811+ super(is);
812+ underlyingInputStream = in;
813+ this.owner = owner;
814+ }
815+
816+ public int available() throws IOException {
817+ return owner.limit-owner.pos+in.available();}
818+ public boolean markSupported() { return false; }
819+ public int read() throws IOException {
820+ if(owner.chunkLength<=0) if(!owner.getData()) return -1;
821+ owner.chunkLength--;
822+ return owner.inbuf[owner.chunkStart++]&0xFF;
823+ }
824+ public int read(byte[] b) throws IOException{return read(b,0,b.length);}
825+ public int read(byte[] b, int st, int len) throws IOException {
826+ if(owner.chunkLength<=0) if(!owner.getData()) return -1;
827+ if(owner.chunkLength<len) len = owner.chunkLength;
828+ System.arraycopy(owner.inbuf,owner.chunkStart,b,st,len);
829+ owner.chunkLength-=len;
830+ owner.chunkStart+=len;
831+ return len;
832+ }
833+ public long skip(long n) throws IOException {
834+ int i;
835+ for(i = 0; i<n && read()>=0; i++);
836+ return i;
837+ }
838+
839+
840+}