📄 pngimageproducer.java
字号:
//
// Copyright (c) 1997, Jason Marshall. All Rights Reserved
//
// The author makes no representations or warranties regarding the suitability,
// reliability or stability of this code. This code is provided AS IS. The
// author shall not be liable for any damages suffered as a result of using,
// modifying or redistributing this software or any derivitives thereof.
// Permission to use, reproduce, modify and/or (re)distribute this software is
// hereby granted.
package com.oyoaha.swing.plaf.oyoaha;
/**
* @(#)PNGImageProducer.java 0.88 97/4/14 Jason Marshall
**/
import java.awt.image.*;
import java.io.*;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.zip.*;
// TODO: Need an ImageFormatException or somesuch.. instead of throwing
// IOExceptions all over the place. -JDM
/**
* ImageProducer which produces an Image from a PNG image
* Note that making this implement the Runnable interface it but one way to
* handle the problems inherent with asynchronous image production. This class
* is provided more as a proof of concept, and sample implementation of the PNG
* decoder in Java.
*
* @version 0.88 14 May 1997
* @author Jason Marshall
*/
public class PNGImageProducer implements ImageProducer, Runnable {
private int dataWidth;
private int dataHeight;
private int width = -1;
private int height = -1;
private int sigmask = 0xffff;
private ColorModel model;
private Object pixels;
private int ipixels[];
private byte bpixels[];
private Hashtable properties;
private Vector theConsumers;
private boolean multipass;
private boolean complete;
private boolean error;
// TODO: make private when inner class created -JDM
InputStream underlyingStream;
// TODO: make private when inner class created -JDM
DataInputStream inputStream;
private Thread controlThread;
private boolean infoAvailable = false;
private boolean completePasses = false;
//TODO: set from system properties -JDM
private int updateDelay = 750;
// Image decoding state variables
private boolean headerFound = false;
private int compressionMethod = -1;
private int depth = -1;
private int colorType = -1;
private int filterMethod = -1;
private int interlaceMethod = -1;
private int pass;
private byte palette[];
private boolean transparency;
// TODO: make private when innerclass created -JDM
int chunkLength;
// TODO: make private when innerclass created -JDM
int chunkType;
// TODO: make private when innerclass created -JDM
boolean needChunkInfo = true;
static final int CHUNK_bKGD = 0x624B4744; // "bKGD"
static final int CHUNK_cHRM = 0x6348524D; // "cHRM"
static final int CHUNK_gAMA = 0x67414D41; // "gAMA"
static final int CHUNK_hIST = 0x68495354; // "hIST"
static final int CHUNK_IDAT = 0x49444154; // "IDAT"
static final int CHUNK_IEND = 0x49454E44; // "IEND"
static final int CHUNK_IHDR = 0x49484452; // "IHDR"
static final int CHUNK_PLTE = 0x504C5445; // "PLTE"
static final int CHUNK_pHYs = 0x70485973; // "pHYs"
static final int CHUNK_sBIT = 0x73424954; // "sBIT"
static final int CHUNK_tEXt = 0x74455874; // "tEXt"
static final int CHUNK_tIME = 0x74494D45; // "tIME"
static final int CHUNK_tRNS = 0x74524E53; // "tIME"
static final int CHUNK_zTXt = 0x7A545874; // "zTXt"
static final int startingRow[] = { 0, 0, 0, 4, 0, 2, 0, 1 };
static final int startingCol[] = { 0, 0, 4, 0, 2, 0, 1, 0 };
static final int rowInc[] = { 1, 8, 8, 8, 4, 4, 2, 2 };
static final int colInc[] = { 1, 8, 8, 4, 4, 2, 2, 1 };
static final int blockHeight[] = { 1, 8, 8, 4, 4, 2, 2, 1 };
static final int blockWidth[] = { 1, 8, 4, 4, 2, 2, 1, 1 };
/**
*
**/
public PNGImageProducer(InputStream is) {
theConsumers = new Vector();
properties = new Hashtable();
if (!(is instanceof BufferedInputStream))
is = new BufferedInputStream(is, 1024);
underlyingStream = is;
inputStream = new DataInputStream(underlyingStream);
}
public void dispose()
{
try
{
if(underlyingStream!=null)
{
underlyingStream.close();
underlyingStream = null;
}
if(inputStream!=null)
{
inputStream.close();
inputStream = null;
}
}
catch(Exception e)
{
}
}
public synchronized void addConsumer(ImageConsumer ic) {
if (theConsumers.contains(ic)) {
return;
}
theConsumers.addElement(ic);
try {
initConsumer(ic);
sendPixels(ic, 0, 0, width, height);
if ((complete) && (isConsumer(ic))) {
if (error) {
ic.imageComplete(ImageConsumer.IMAGEERROR);
} else {
ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
}
removeConsumer(ic);
}
} catch (Exception e) {
if (isConsumer(ic)) {
ic.imageComplete(ImageConsumer.IMAGEERROR);
}
}
}
private void blockFill(int rowStart) {
int counter;
int dw = dataWidth;
int pass = this.pass;
int w = blockWidth[pass];
int sCol = startingCol[pass];
int cInc = colInc[pass];
int wInc = cInc - w;
int maxW = rowStart + dw - w;
int len;
int h = blockHeight[pass];
int maxH = rowStart + (dw * h);
int startPos = rowStart + sCol;
counter = startPos;
if (colorType == 3) {
byte bpix[] = bpixels;
byte pixel;
len = bpix.length;
for (; counter <= maxW;) {
int end = counter + w;
pixel = bpix[counter++];
for (; counter < end; counter++) {
bpix[counter] = pixel;
}
counter += wInc;
}
maxW += w;
if (counter < maxW) {
for (pixel = bpix[counter++]; counter < maxW; counter++) {
bpix[counter] = pixel;
}
}
if (len < maxH)
maxH = len;
for (counter = startPos + dw; counter < maxH; counter += dw) {
System.arraycopy(bpix, startPos, bpix, counter, dw - sCol);
}
} else {
int ipix[] = ipixels;
int pixel;
len = ipix.length;
for (; counter <= maxW;) {
int end = counter + w;
pixel = ipix[counter++];
for (; counter < end; counter++) {
ipix[counter] = pixel;
}
counter += wInc;
}
maxW += w;
if (counter < maxW) {
for (pixel = ipix[counter++]; counter < maxW; counter++) {
ipix[counter] = pixel;
}
}
if (len < maxH)
maxH = len;
for (counter = startPos + dw; counter < maxH; counter += dw) {
System.arraycopy(ipix, startPos, ipix, counter, dw - sCol);
}
}
}
private boolean filterRow(byte inbuf[], int pix[], int upix[], int rowFilter, int boff)
{
int rowWidth = pix.length;
switch (rowFilter)
{
case 0:
for (int x = 0; x < rowWidth; x++)
{
pix[x] = 0xff & inbuf[x];
}
break;
case 1:
{
int x = 0;
for ( ; x < boff; x++)
{
pix[x] = 0xff & inbuf[x];
}
for ( ; x < rowWidth; x++)
{
pix[x] = 0xff & (inbuf[x] + pix[x - boff]);
}
break;
}
case 2:
{
if (upix != null)
{
for (int x = 0; x < rowWidth; x++)
{
pix[x] = 0xff & (upix[x] + inbuf[x]);
}
}
else
{
for (int x = 0; x < rowWidth; x++)
{
pix[x] = 0xff & inbuf[x];
}
}
break;
}
case 3:
{
if (upix != null)
{
int x = 0;
for ( ; x < boff; x++)
{
int rval = upix[x];
pix[x] = 0xff & ((rval>>1) + inbuf[x]);
}
for ( ; x < rowWidth; x++)
{
int rval = upix[x] + pix[x - boff];
pix[x] = 0xff & ((rval>>1) + inbuf[x]);
}
}
else
{
int x = 0;
for ( ; x < boff; x++)
{
pix[x] = 0xff & inbuf[x];
}
for ( ; x < rowWidth; x++)
{
int rval = pix[x - boff];
pix[x] = 0xff & ((rval>>1) + inbuf[x]);
}
}
break;
}
case 4: {
if (upix != null)
{
int x = 0;
for ( ; x < boff; x++)
{
pix[x] = 0xff & (upix[x] + inbuf[x]);
}
for ( ; x < rowWidth; x++) {
int a, b, c, p, pa, pb, pc, rval;
a = pix[x - boff];
b = upix[x];
c = upix[x - boff];
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;
if ((pa <= pb) && (pa <= pc))
{
rval = a;
}
else
if (pb <= pc)
{
rval = b;
}
else
{
rval = c;
}
pix[x] = 0xff & (rval + inbuf[x]);
}
} else {
int x = 0;
for ( ; x < boff; x++) {
pix[x] = 0xff & inbuf[x];
}
for ( ; x < rowWidth; x++) {
int rval = pix[x - boff];
pix[x] = 0xff & (rval + inbuf[x]);
}
}
break;
}
default:
return false;
}
return true;
}
private void handlebKGD() throws IOException {
inputStream.skip(chunkLength);
}
private void handlecHRM() throws IOException {
inputStream.skip(chunkLength);
}
private void handleChunk() throws IOException {
if (needChunkInfo) {
chunkLength = inputStream.readInt();
chunkType = inputStream.readInt();
needChunkInfo = false;
}
// Guarantee that chunks can't overread their bounds
/*inputStream = new DataInputStream(
new MeteredInputStream(underlyingStream,
chunkLength));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -