📄 pngimageproducer.java
字号:
private void insertPixels(int pix[], int offset, int samples) {
switch (colorType) {
case 0:
case 4: {
insertGreyPixels(pix, offset, samples);
break;
}
case 2: {
int j = 0;
int ipix[] = ipixels;
int cInc = colInc[pass];
if (depth == 8) {
for (j = 0; j < samples; offset += cInc) {
ipix[offset] = (pix[j++]<<16) | (pix[j++]<<8) | pix[j++];
}
} else {
samples = samples<<1;
for (j = 0; j < samples; j += 2, offset += cInc) {
ipix[offset] = (pix[j]<<16) | (pix[j+=2]<<8) | pix[j+=2];
}
}
break;
}
case 3: {
insertPalettedPixels(pix, offset, samples);
break;
}
case 6: {
int j = 0;
int ipix[] = ipixels;
int cInc = colInc[pass];
if (depth == 8) {
for (j = 0; j < samples; offset += cInc) {
ipix[offset] = (pix[j++]<<16) | (pix[j++]<<8) | pix[j++] |
(pix[j++]<<24);
}
} else {
samples = samples<<1;
for (j = 0; j < samples; j += 2, offset += cInc) {
ipix[offset] = (pix[j]<<16) | (pix[j+=2]<<8) | pix[j+=2] |
(pix[j+=2]<<24);
}
}
break;
}
default:
break;
}
}
/**
* This method determines if a given ImageConsumer object
* is currently registered with this ImageProducer as one
* of its consumers.
* @see ImageConsumer
*/
public synchronized boolean isConsumer(ImageConsumer ic) {
return theConsumers.contains(ic);
}
/**
* Read Image data in off of a compression stream
**/
private void readImageData() throws IOException {
long time = System.currentTimeMillis();
InputStream dataStream = new SequenceInputStream(
new IDATEnumeration(this));
DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new InflaterInputStream(dataStream,
new Inflater())));
int bps, filterOffset;
switch (colorType) {
case 0:
case 3:
bps = depth;
break;
case 2:
bps = 3 * depth;
break;
case 4:
bps = depth<<1;
break;
case 6:
bps = depth<<2;
break;
default:
// should never happen
throw new IOException("Unknown color type encountered.");
}
filterOffset = (bps + 7)>>3;
for (pass = (multipass ? 1 : 0); pass < 8; pass++) {
int pass = this.pass;
int rInc = rowInc[pass];
int cInc = colInc[pass];
int sCol = startingCol[pass];
int val = ((dataWidth - sCol + cInc - 1) / cInc);
int samples = val * filterOffset;
int rowSize = (val * bps)>>3;
int sRow = startingRow[pass];
if ((dataHeight <= sRow) || (rowSize == 0))
continue;
int sInc = rInc * dataWidth;
byte inbuf[] = new byte[rowSize];
int pix[] = new int[rowSize];
int upix[] = null;
int temp[] = new int[rowSize];
// next Y value and number of rows to report to sendPixels
int nextY = sRow;
int rows = 0;
int rowStart = sRow * dataWidth;
for (int y = sRow; y < dataHeight; y += rInc, rowStart += sInc) {
rows += rInc;
int rowFilter = dis.read();
dis.readFully(inbuf);
if (!filterRow(inbuf, pix, upix, rowFilter, filterOffset)) {
throw new IOException("Unknown filter type: " + rowFilter);
}
insertPixels(pix, rowStart + sCol, samples);
if (multipass && (pass < 6)) {
blockFill(rowStart);
}
upix = pix;
pix = temp;
temp = upix;
if (!completePasses) {
long newTime = System.currentTimeMillis();
if ((newTime - time) > updateDelay) {
sendPixels(0, nextY, width, rows);
rows = 0;
nextY = y + rInc;
time = newTime;
}
}
Thread.yield();
}
if (!multipass)
break;
if (completePasses || (rows > 0)) {
sendPixels(0, 0, width, height);
time = System.currentTimeMillis();
}
}
while(dis.read() != -1)
System.err.println("Leftover data encountered.");
}
/**
* Remove an ImageConsumer from the list of consumers interested in
* data for this image.
* @see ImageConsumer
*/
public synchronized void removeConsumer(ImageConsumer ic) {
theConsumers.removeElement(ic);
}
/**
* Requests that a given ImageConsumer have the image data delivered
* one more time in top-down, left-right order.
* @see ImageConsumer
*/
public void requestTopDownLeftRightResend(ImageConsumer ic) {
// Ignored. The data is either single frame and already in TDLR
// format or it is multi-frame and TDLR resends aren't critical.
}
/**
* Primary processing of Image data.
**/
public void run() {
try {
// Verify signature
handleSignature();
while (!complete && !error) {
handleChunk();
}
} catch (Exception e) {
System.err.println("PNGImageProducer: " + e);
e.printStackTrace(System.err);
error = true;
}
synchronized (this) {
for (int c = 0; c < theConsumers.size(); c++) {
ImageConsumer ic = (ImageConsumer) theConsumers.elementAt(c);
if (error) {
ic.imageComplete(ImageConsumer.IMAGEERROR);
} else {
ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
}
}
}
}
private synchronized void sendPixels(int x, int y, int w, int h) {
int off = dataWidth * y + x;
Enumeration enum = theConsumers.elements();
while (enum.hasMoreElements()) {
ImageConsumer ic = (ImageConsumer) enum.nextElement();
if ((pixels != null) && (isConsumer(ic))) {
if (pixels instanceof byte[]) {
ic.setPixels(x, y, w, h, model, bpixels, off, dataWidth);
} else {
ic.setPixels(x, y, w, h, model, ipixels, off, dataWidth);
}
}
}
}
private void sendPixels(ImageConsumer ic, int x, int y, int w, int h) {
int off = dataWidth * y + x;
if ((pixels != null) && (isConsumer(ic))) {
if (pixels instanceof byte[]) {
ic.setPixels(x, y, w, h, model, bpixels, off, dataWidth);
} else {
ic.setPixels(x, y, w, h, model, ipixels, off, dataWidth);
}
}
}
private void setColorModel() throws IOException {
int mask = 0;
switch (depth) {
case 1:
mask = 0x1;
break;
case 2:
mask = 0x3;
break;
case 4:
mask = 0xf;
break;
case 8:
case 16:
mask = 0xff;
break;
}
int count = width * height;
switch (colorType) {
case 3:
if (palette == null)
throw new IOException("No palette located");
bpixels = new byte[count];
pixels = bpixels;
if (transparency) {
model = new IndexColorModel(depth, palette.length/4, palette,
0, true);
} else {
model = new IndexColorModel(depth, palette.length/3, palette,
0, false);
}
break;
case 0:
ipixels = new int[count];
pixels = ipixels;
if (depth < 8) {
model = new DirectColorModel(depth, mask, mask, mask);
} else {
model = new DirectColorModel(8, mask, mask, mask);
}
break;
case 2:
ipixels = new int[count];
pixels = ipixels;
model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
break;
case 4:
int smask;
if (depth < 8) {
smask = mask << depth;
model = new DirectColorModel(depth * 2, smask, smask, smask,
mask);
} else {
smask = mask << 8;
model = new DirectColorModel(16, smask, smask, smask, mask);
}
ipixels = new int[count];
pixels = ipixels;
break;
case 6:
ipixels = new int[count];
pixels = ipixels;
model = ColorModel.getRGBdefault();
break;
default:
throw new IOException("Image has unknown color type");
}
}
private void start() {
if (controlThread == null) {
synchronized (this) {
controlThread = new Thread(this);
try {
controlThread.setPriority(Thread.NORM_PRIORITY - 2);
} catch (Exception e) {}
controlThread.start();
}
}
}
/**
* Adds an ImageConsumer to the list of consumers interested in
* data for this image, and immediately start delivery of the
* image data through the ImageConsumer interface.
* @see ImageConsumer
*/
public void startProduction(ImageConsumer ic) {
addConsumer(ic);
start();
}
}
/**
* Support class, used to eat the IDAT headers dividing up the deflated stream
**/
class IDATEnumeration implements Enumeration {
InputStream underlyingStream;
PNGImageProducer owner;
boolean firstStream = true;
public IDATEnumeration(PNGImageProducer owner) {
this.owner = owner;
this.underlyingStream = owner.underlyingStream;
}
public Object nextElement() {
firstStream = false;
return new MeteredInputStream(underlyingStream, owner.chunkLength);
}
public boolean hasMoreElements() {
DataInputStream dis = new DataInputStream(underlyingStream);
if (!firstStream) {
try {
int crc = dis.readInt();
owner.needChunkInfo = false;
owner.chunkLength = dis.readInt();
owner.chunkType = dis.readInt();
} catch (IOException ioe) {
return false;
}
}
if (owner.chunkType == PNGImageProducer.CHUNK_IDAT) {
return true;
}
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -