/* 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 << llog); byte ramp[] = new byte[size]; for (int i = 0; i < size; i++) ramp[i] = (byte) (255 * i / (size - 1)); if (transparentPixel == -1) { cm = new IndexColorModel(bitDepth, ramp.length, ramp, ramp, ramp); } else { cm = new IndexColorModel( bitDepth, ramp.length, ramp, ramp, ramp, (transparentPixel & 0xFF)); } greyModels[llog] = cm; } } bPixels = new byte[pixSize]; break; case COLOR: case COLOR | ALPHA: case GRAY | ALPHA: cm = ColorModel.getRGBdefault(); wPixels = new int[pixSize]; break; default: throw new PNGException("invalid color type"); } /* this is going to be set in the pixel store t.setColorModel(cm); t.setHints(interlaceMethod !=0 ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME); */ // code added to make it work with ImageDecoder architecture setDimensions(width, height); setColorModel(cm); int flags = (interlaceMethod != 0 ? ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES : ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME); setHints(flags); headerComplete(); // end of adding int samplesPerPixel = ((colorType & PALETTE) != 0 ? 1 : ((colorType & COLOR) != 0 ? 3 : 1) + ((colorType & ALPHA) != 0 ? 1 : 0)); int bitsPerPixel = samplesPerPixel * bitDepth; int bytesPerPixel = (bitsPerPixel + 7) >> 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 void property(String key, float value) { property(key, new Float(value)); }
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; }