import java.util.zip.*;
/** Converts an InputStream carrying a PNG image into an ARGB int[] */
-public class PNG extends ImageDecoder {
+public class PNG {
- // Public Methods ///////////////////////////////////////////////////////////////////////////////
+ public PNG() { }
+
+ private static Queue instances = new Queue(10);
- /** returns the ARGB int[] representing the last image processed */
- public final int[] getData() { return data; }
+ public static void load(InputStream is, Picture p) {
+ PNG g = (PNG)instances.remove(false);
+ if (g == null) g = new PNG();
+ try {
+ g._load(is, p);
+ p.data = g.data;
+ } catch (Exception e) {
+ if (Log.on) Log.info(PNG.class, e);
+ return;
+ }
+ // FIXME: must reset fields
+ // if (instances.size() < 10) instances.append(g);
+ }
- /** returns the width of the last image processed */
- public final int getWidth() { return width; }
+ // Public Methods ///////////////////////////////////////////////////////////////////////////////
- /** returns the height of the last image processed */
- public final int getHeight() { return height; }
+ private Picture p;
/** process a PNG as an inputstream; returns null if there is an error
@param name A string describing the image, to be used when logging errors
*/
- public static PNG decode(InputStream is, String name) {
- try {
- return new PNG(is, name);
- } catch (Exception e) {
- if (Log.on) Log.log(PNG.class, e);
- return null;
- }
- }
-
- private PNG(InputStream is, String name) throws IOException {
- underlyingStream = is;
+ private void _load(InputStream is, Picture p) throws IOException {
+ this.p = p;
+ if (is instanceof BufferedInputStream) underlyingStream = (BufferedInputStream)is;
+ else underlyingStream = new BufferedInputStream(is);
target_offset = 0;
inputStream = new DataInputStream(underlyingStream);
// consume the header
if ((inputStream.read() != 137) || (inputStream.read() != 80) || (inputStream.read() != 78) || (inputStream.read() != 71) ||
(inputStream.read() != 13) || (inputStream.read() != 10) || (inputStream.read() != 26) || (inputStream.read() != 10)) {
- Log.log(this, "PNG: error: input file " + name + " is not a PNG file");
- data = new int[] { };
- width = height = 0;
+ Log.info(this, "PNG: error: input file is not a PNG file");
+ data = p.data = new int[] { };
+ p.width = p.height = 0;
return;
}
int crc = inputStream.readInt();
needChunkInfo = true;
}
+ p.isLoaded = true;
}
// Chunk Handlers ///////////////////////////////////////////////////////////////////////
/** handle data chunk */
private void handleIDAT() throws IOException {
- if (width == -1 || height == -1) throw new IOException("never got image width/height");
+ if (p.width == -1 || p.height == -1) throw new IOException("never got image width/height");
switch (depth) {
case 1: mask = 0x1; break;
case 2: mask = 0x3; break;
if (depth < 8) smask = mask << depth;
else smask = mask << 8;
- int count = width * height;
+ int count = p.width * p.height;
switch (colorType) {
case 0:
private void handleIHDR() throws IOException {
if (headerFound) throw new IOException("Extraneous IHDR chunk encountered.");
if (chunkLength != 13) throw new IOException("IHDR chunk length wrong: " + chunkLength);
- width = inputStream.readInt();
- height = inputStream.readInt();
+ p.width = inputStream.readInt();
+ p.height = inputStream.readInt();
depth = inputStream.read();
colorType = inputStream.read();
compressionMethod = inputStream.read();
private void handletRNS() throws IOException {
int chunkLen = chunkLength;
if (palette == null) {
- if (Log.on) Log.log(this, "warning: tRNS chunk encountered before pLTE; ignoring alpha channel");
+ if (Log.on) Log.info(this, "warning: tRNS chunk encountered before pLTE; ignoring alpha channel");
inputStream.skip(chunkLength);
return;
}
int rInc = rowInc[pass];
int cInc = colInc[pass];
int sCol = startingCol[pass];
- int val = (width - sCol + cInc - 1) / cInc;
+ int val = (p.width - sCol + cInc - 1) / cInc;
int samples = val * filterOffset;
int rowSize = (val * bps)>>3;
int sRow = startingRow[pass];
- if (height <= sRow || rowSize == 0) continue;
- int sInc = rInc * width;
+ if (p.height <= sRow || rowSize == 0) continue;
+ int sInc = rInc * p.width;
byte inbuf[] = new byte[rowSize];
int pix[] = new int[rowSize];
int upix[] = null;
int temp[] = new int[rowSize];
int nextY = sRow; // next Y value and number of rows to report to sendPixels
int rows = 0;
- int rowStart = sRow * width;
+ int rowStart = sRow * p.width;
- for (int y = sRow; y < height; y += rInc, rowStart += sInc) {
+ for (int y = sRow; y < p.height; y += rInc, rowStart += sInc) {
rows += rInc;
int rowFilter = dis.read();
dis.readFully(inbuf);
private void blockFill(int rowStart) {
int counter;
- int dw = width;
+ int dw = p.width;
int pass = this.pass;
int w = blockWidth[pass];
int sCol = startingCol[pass];
// Private Data ///////////////////////////////////////////////////////////////////////////////////////
private int target_offset = 0;
- private int width = -1;
- private int height = -1;
private int sigmask = 0xffff;
private Object pixels = null;
private int ipixels[] = null;
private boolean complete = false;
private boolean error = false;
- private int[] data = null;
+ int[] data = null;
private InputStream underlyingStream = null;
private DataInputStream inputStream = null;