mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-25 06:10:44 +00:00
952 lines
32 KiB
Java
952 lines
32 KiB
Java
/*
|
|
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package sun.awt.image;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Graphics;
|
|
import java.awt.Transparency;
|
|
import java.awt.AWTException;
|
|
import java.awt.Rectangle;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.ColorModel;
|
|
import java.awt.image.DirectColorModel;
|
|
import java.awt.image.IndexColorModel;
|
|
import java.awt.image.ImageConsumer;
|
|
import java.awt.image.ImageObserver;
|
|
import sun.awt.image.ByteComponentRaster;
|
|
import sun.awt.image.IntegerComponentRaster;
|
|
import java.awt.image.Raster;
|
|
import java.awt.image.WritableRaster;
|
|
import java.awt.image.DataBuffer;
|
|
import java.awt.image.DataBufferInt;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.geom.AffineTransform;
|
|
import sun.awt.image.ImageWatched;
|
|
import java.util.Hashtable;
|
|
|
|
public class ImageRepresentation extends ImageWatched implements ImageConsumer
|
|
{
|
|
InputStreamImageSource src;
|
|
ToolkitImage image;
|
|
int tag;
|
|
|
|
long pData; // used by windows native code only -- internal state REMIND ATTN @@
|
|
|
|
int width = -1;
|
|
int height = -1;
|
|
int hints;
|
|
|
|
int availinfo;
|
|
|
|
Rectangle newbits;
|
|
|
|
BufferedImage bimage;
|
|
WritableRaster biRaster;
|
|
protected ColorModel cmodel;
|
|
ColorModel srcModel = null;
|
|
int[] srcLUT = null;
|
|
int srcLUTtransIndex = -1;
|
|
int numSrcLUT = 0;
|
|
boolean forceCMhint;
|
|
int sstride;
|
|
boolean isDefaultBI = false;
|
|
boolean isSameCM = false;
|
|
|
|
private static native void initIDs();
|
|
|
|
static {
|
|
/* ensure that the necessary native libraries are loaded */
|
|
NativeLibLoader.loadLibraries();
|
|
initIDs();
|
|
}
|
|
|
|
/**
|
|
* Create an ImageRepresentation for the given Image. The
|
|
* width and height are unknown at this point. The color
|
|
* model is a hint as to the color model to use when creating
|
|
* the buffered image. If null, the src color model will
|
|
* be used.
|
|
*/
|
|
public ImageRepresentation(ToolkitImage im, ColorModel cmodel, boolean
|
|
forceCMhint) {
|
|
image = im;
|
|
|
|
if (image.getSource() instanceof InputStreamImageSource) {
|
|
src = (InputStreamImageSource) image.getSource();
|
|
}
|
|
|
|
setColorModel(cmodel);
|
|
|
|
this.forceCMhint = forceCMhint;
|
|
}
|
|
|
|
/* REMIND: Only used for Frame.setIcon - should use ImageWatcher instead */
|
|
public synchronized void reconstruct(int flags) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
int missinginfo = flags & ~availinfo;
|
|
if ((availinfo & ImageObserver.ERROR) == 0 && missinginfo != 0) {
|
|
numWaiters++;
|
|
try {
|
|
startProduction();
|
|
missinginfo = flags & ~availinfo;
|
|
while ((availinfo & ImageObserver.ERROR) == 0 &&
|
|
missinginfo != 0)
|
|
{
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
return;
|
|
}
|
|
missinginfo = flags & ~availinfo;
|
|
}
|
|
} finally {
|
|
decrementWaiters();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setDimensions(int w, int h) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
|
|
image.setDimensions(w, h);
|
|
|
|
newInfo(image, (ImageObserver.WIDTH | ImageObserver.HEIGHT),
|
|
0, 0, w, h);
|
|
|
|
if (w <= 0 || h <= 0) {
|
|
imageComplete(ImageConsumer.IMAGEERROR);
|
|
return;
|
|
}
|
|
|
|
if (width != w || height != h) {
|
|
// dimension mismatch => trigger recreation of the buffer
|
|
bimage = null;
|
|
}
|
|
|
|
width = w;
|
|
height = h;
|
|
|
|
availinfo |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
|
|
}
|
|
|
|
public int getWidth() {
|
|
return width;
|
|
}
|
|
|
|
public int getHeight() {
|
|
return height;
|
|
}
|
|
|
|
ColorModel getColorModel() {
|
|
return cmodel;
|
|
}
|
|
|
|
BufferedImage getBufferedImage() {
|
|
return bimage;
|
|
}
|
|
|
|
/**
|
|
* Returns the BufferedImage that will be used as the representation of
|
|
* the pixel data. Subclasses can override this method to return
|
|
* platform specific subclasses of BufferedImage that may or may not be
|
|
* accelerated.
|
|
*
|
|
* It is subclass' responsibility to propagate acceleration priority
|
|
* to the newly created image.
|
|
*/
|
|
protected BufferedImage createImage(ColorModel cm,
|
|
WritableRaster raster,
|
|
boolean isRasterPremultiplied,
|
|
Hashtable<?,?> properties)
|
|
{
|
|
BufferedImage bi =
|
|
new BufferedImage(cm, raster, isRasterPremultiplied, null);
|
|
bi.setAccelerationPriority(image.getAccelerationPriority());
|
|
return bi;
|
|
}
|
|
|
|
public void setProperties(Hashtable<?,?> props) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
image.setProperties(props);
|
|
newInfo(image, ImageObserver.PROPERTIES, 0, 0, 0, 0);
|
|
}
|
|
|
|
public void setColorModel(ColorModel model) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
srcModel = model;
|
|
|
|
// Check to see if model is INT_RGB
|
|
if (model instanceof IndexColorModel) {
|
|
if (model.getTransparency() == Transparency.TRANSLUCENT) {
|
|
// REMIND:
|
|
// Probably need to composite anyway so force ARGB
|
|
cmodel = ColorModel.getRGBdefault();
|
|
srcLUT = null;
|
|
}
|
|
else {
|
|
IndexColorModel icm = (IndexColorModel) model;
|
|
numSrcLUT = icm.getMapSize();
|
|
srcLUT = new int[Math.max(numSrcLUT, 256)];
|
|
icm.getRGBs(srcLUT);
|
|
srcLUTtransIndex = icm.getTransparentPixel();
|
|
cmodel = model;
|
|
}
|
|
}
|
|
else {
|
|
if (cmodel == null) {
|
|
cmodel = model;
|
|
srcLUT = null;
|
|
}
|
|
else if (model instanceof DirectColorModel) {
|
|
// If it is INT_RGB or INT_ARGB, use the model
|
|
DirectColorModel dcm = (DirectColorModel) model;
|
|
if ((dcm.getRedMask() == 0xff0000) &&
|
|
(dcm.getGreenMask() == 0xff00) &&
|
|
(dcm.getBlueMask() == 0x00ff)) {
|
|
cmodel = model;
|
|
srcLUT = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
isSameCM = (cmodel == model);
|
|
}
|
|
|
|
void createBufferedImage() {
|
|
// REMIND: Be careful! Is this called every time there is a
|
|
// startProduction? We only want to call it if it is new or
|
|
// there is an error
|
|
isDefaultBI = false;
|
|
try {
|
|
biRaster = cmodel.createCompatibleWritableRaster(width, height);
|
|
bimage = createImage(cmodel, biRaster,
|
|
cmodel.isAlphaPremultiplied(), null);
|
|
} catch (Exception e) {
|
|
// Create a default image
|
|
cmodel = ColorModel.getRGBdefault();
|
|
biRaster = cmodel.createCompatibleWritableRaster(width, height);
|
|
bimage = createImage(cmodel, biRaster, false, null);
|
|
}
|
|
int type = bimage.getType();
|
|
|
|
if ((cmodel == ColorModel.getRGBdefault()) ||
|
|
(type == BufferedImage.TYPE_INT_RGB) ||
|
|
(type == BufferedImage.TYPE_INT_ARGB_PRE)) {
|
|
isDefaultBI = true;
|
|
}
|
|
else if (cmodel instanceof DirectColorModel) {
|
|
DirectColorModel dcm = (DirectColorModel) cmodel;
|
|
if (dcm.getRedMask() == 0xff0000 &&
|
|
dcm.getGreenMask() == 0xff00 &&
|
|
dcm.getBlueMask() == 0xff) {
|
|
isDefaultBI = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void convertToRGB() {
|
|
int w = bimage.getWidth();
|
|
int h = bimage.getHeight();
|
|
int size = w*h;
|
|
|
|
DataBufferInt dbi = new DataBufferInt(size);
|
|
// Note that stealData() requires a markDirty() afterwards
|
|
// since we modify the data in it.
|
|
int[] newpixels = SunWritableRaster.stealData(dbi, 0);
|
|
if (cmodel instanceof IndexColorModel &&
|
|
biRaster instanceof ByteComponentRaster &&
|
|
biRaster.getNumDataElements() == 1)
|
|
{
|
|
ByteComponentRaster bct = (ByteComponentRaster) biRaster;
|
|
byte[] data = bct.getDataStorage();
|
|
int coff = bct.getDataOffset(0);
|
|
for (int i=0; i < size; i++) {
|
|
newpixels[i] = srcLUT[data[coff+i]&0xff];
|
|
}
|
|
}
|
|
else {
|
|
Object srcpixels = null;
|
|
int off=0;
|
|
for (int y=0; y < h; y++) {
|
|
for (int x=0; x < w; x++) {
|
|
srcpixels=biRaster.getDataElements(x, y, srcpixels);
|
|
newpixels[off++] = cmodel.getRGB(srcpixels);
|
|
}
|
|
}
|
|
}
|
|
// We modified the data array directly above so mark it as dirty now...
|
|
SunWritableRaster.markDirty(dbi);
|
|
|
|
isSameCM = false;
|
|
cmodel = ColorModel.getRGBdefault();
|
|
|
|
int[] bandMasks = {0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0xff000000};
|
|
|
|
biRaster = Raster.createPackedRaster(dbi,w,h,w,
|
|
bandMasks,null);
|
|
|
|
bimage = createImage(cmodel, biRaster,
|
|
cmodel.isAlphaPremultiplied(), null);
|
|
srcLUT = null;
|
|
isDefaultBI = true;
|
|
}
|
|
|
|
public void setHints(int h) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
hints = h;
|
|
}
|
|
|
|
private native boolean setICMpixels(int x, int y, int w, int h, int[] lut,
|
|
byte[] pix, int off, int scansize,
|
|
IntegerComponentRaster ict);
|
|
private native boolean setDiffICM(int x, int y, int w, int h, int[] lut,
|
|
int transPix, int numLut, IndexColorModel icm,
|
|
byte[] pix, int off, int scansize,
|
|
ByteComponentRaster bct, int chanOff);
|
|
static boolean s_useNative = true;
|
|
|
|
public void setPixels(int x, int y, int w, int h,
|
|
ColorModel model,
|
|
byte[] pix, int off, int scansize) {
|
|
int lineOff=off;
|
|
int poff;
|
|
int[] newLUT=null;
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
|
|
// REMIND: What if the model doesn't fit in default color model?
|
|
synchronized (this) {
|
|
if (bimage == null) {
|
|
if (cmodel == null) {
|
|
cmodel = model;
|
|
}
|
|
createBufferedImage();
|
|
}
|
|
|
|
if (w <= 0 || h <= 0) {
|
|
return;
|
|
}
|
|
|
|
int biWidth = biRaster.getWidth();
|
|
int biHeight = biRaster.getHeight();
|
|
|
|
int x1 = x+w; // Overflow protection below
|
|
int y1 = y+h; // Overflow protection below
|
|
if (x < 0) {
|
|
off -= x;
|
|
x = 0;
|
|
} else if (x1 < 0) {
|
|
x1 = biWidth; // Must be overflow
|
|
}
|
|
if (y < 0) {
|
|
off -= y*scansize;
|
|
y = 0;
|
|
} else if (y1 < 0) {
|
|
y1 = biHeight; // Must be overflow
|
|
}
|
|
if (x1 > biWidth) {
|
|
x1 = biWidth;
|
|
}
|
|
if (y1 > biHeight) {
|
|
y1 = biHeight;
|
|
}
|
|
if (x >= x1 || y >= y1) {
|
|
return;
|
|
}
|
|
// x,y,x1,y1 are all >= 0, so w,h must be >= 0
|
|
w = x1-x;
|
|
h = y1-y;
|
|
// off is first pixel read so it must be in bounds
|
|
if (off < 0 || off >= pix.length) {
|
|
// They overflowed their own array
|
|
throw new ArrayIndexOutOfBoundsException("Data offset out of bounds.");
|
|
}
|
|
// pix.length and off are >= 0 so remainder >= 0
|
|
int remainder = pix.length - off;
|
|
if (remainder < w) {
|
|
// They overflowed their own array
|
|
throw new ArrayIndexOutOfBoundsException("Data array is too short.");
|
|
}
|
|
int num;
|
|
if (scansize < 0) {
|
|
num = (off / -scansize) + 1;
|
|
} else if (scansize > 0) {
|
|
num = ((remainder-w) / scansize) + 1;
|
|
} else {
|
|
num = h;
|
|
}
|
|
if (h > num) {
|
|
// They overflowed their own array.
|
|
throw new ArrayIndexOutOfBoundsException("Data array is too short.");
|
|
}
|
|
|
|
if (isSameCM && (cmodel != model) && (srcLUT != null) &&
|
|
(model instanceof IndexColorModel) &&
|
|
(biRaster instanceof ByteComponentRaster))
|
|
{
|
|
IndexColorModel icm = (IndexColorModel) model;
|
|
ByteComponentRaster bct = (ByteComponentRaster) biRaster;
|
|
int numlut = numSrcLUT;
|
|
if (!setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex,
|
|
numSrcLUT, icm,
|
|
pix, off, scansize, bct,
|
|
bct.getDataOffset(0))) {
|
|
convertToRGB();
|
|
}
|
|
else {
|
|
// Note that setDiffICM modified the raster directly
|
|
// so we must mark it as changed
|
|
bct.markDirty();
|
|
if (numlut != numSrcLUT) {
|
|
boolean hasAlpha = icm.hasAlpha();
|
|
if (srcLUTtransIndex != -1) {
|
|
hasAlpha = true;
|
|
}
|
|
int nbits = icm.getPixelSize();
|
|
icm = new IndexColorModel(nbits,
|
|
numSrcLUT, srcLUT,
|
|
0, hasAlpha,
|
|
srcLUTtransIndex,
|
|
(nbits > 8
|
|
? DataBuffer.TYPE_USHORT
|
|
: DataBuffer.TYPE_BYTE));
|
|
cmodel = icm;
|
|
bimage = createImage(icm, bct, false, null);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (isDefaultBI) {
|
|
int pixel;
|
|
IntegerComponentRaster iraster =
|
|
(IntegerComponentRaster) biRaster;
|
|
if (srcLUT != null && model instanceof IndexColorModel) {
|
|
if (model != srcModel) {
|
|
// Fill in the new lut
|
|
((IndexColorModel)model).getRGBs(srcLUT);
|
|
srcModel = model;
|
|
}
|
|
|
|
if (s_useNative) {
|
|
// Note that setICMpixels modifies the raster directly
|
|
// so we must mark it as changed afterwards
|
|
if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize,
|
|
iraster))
|
|
{
|
|
iraster.markDirty();
|
|
} else {
|
|
abort();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
int[] storage = new int[w*h];
|
|
int soff = 0;
|
|
// It is an IndexColorModel
|
|
for (int yoff=0; yoff < h; yoff++,
|
|
lineOff += scansize) {
|
|
poff = lineOff;
|
|
for (int i=0; i < w; i++) {
|
|
storage[soff++] = srcLUT[pix[poff++]&0xff];
|
|
}
|
|
}
|
|
iraster.setDataElements(x, y, w, h, storage);
|
|
}
|
|
}
|
|
else {
|
|
int[] storage = new int[w];
|
|
for (int yoff=y; yoff < y+h; yoff++, lineOff += scansize) {
|
|
poff = lineOff;
|
|
for (int i=0; i < w; i++) {
|
|
storage[i] = model.getRGB(pix[poff++]&0xff);
|
|
}
|
|
iraster.setDataElements(x, yoff, w, 1, storage);
|
|
}
|
|
availinfo |= ImageObserver.SOMEBITS;
|
|
}
|
|
}
|
|
else if ((cmodel == model) &&
|
|
(biRaster instanceof ByteComponentRaster) &&
|
|
(biRaster.getNumDataElements() == 1)){
|
|
ByteComponentRaster bt = (ByteComponentRaster) biRaster;
|
|
if (off == 0 && scansize == w) {
|
|
bt.putByteData(x, y, w, h, pix);
|
|
}
|
|
else {
|
|
byte[] bpix = new byte[w];
|
|
poff = off;
|
|
for (int yoff=y; yoff < y+h; yoff++) {
|
|
System.arraycopy(pix, poff, bpix, 0, w);
|
|
bt.putByteData(x, yoff, w, 1, bpix);
|
|
poff += scansize;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (int yoff=y; yoff < y+h; yoff++, lineOff += scansize) {
|
|
poff = lineOff;
|
|
for (int xoff=x; xoff < x+w; xoff++) {
|
|
bimage.setRGB(xoff, yoff,
|
|
model.getRGB(pix[poff++]&0xff));
|
|
}
|
|
}
|
|
availinfo |= ImageObserver.SOMEBITS;
|
|
}
|
|
}
|
|
|
|
if ((availinfo & ImageObserver.FRAMEBITS) == 0) {
|
|
newInfo(image, ImageObserver.SOMEBITS, x, y, w, h);
|
|
}
|
|
}
|
|
|
|
|
|
public void setPixels(int x, int y, int w, int h, ColorModel model,
|
|
int[] pix, int off, int scansize)
|
|
{
|
|
int lineOff=off;
|
|
int poff;
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
|
|
// REMIND: What if the model doesn't fit in default color model?
|
|
synchronized (this) {
|
|
if (bimage == null) {
|
|
if (cmodel == null) {
|
|
cmodel = model;
|
|
}
|
|
createBufferedImage();
|
|
}
|
|
|
|
int[] storage = new int[w];
|
|
int yoff;
|
|
int pixel;
|
|
|
|
if (cmodel instanceof IndexColorModel) {
|
|
// REMIND: Right now we don't support writing back into ICM
|
|
// images.
|
|
convertToRGB();
|
|
}
|
|
|
|
if ((model == cmodel) &&
|
|
(biRaster instanceof IntegerComponentRaster)) {
|
|
IntegerComponentRaster iraster =
|
|
(IntegerComponentRaster) biRaster;
|
|
|
|
if (off == 0 && scansize == w) {
|
|
iraster.setDataElements(x, y, w, h, pix);
|
|
}
|
|
else {
|
|
// Need to pack the data
|
|
for (yoff=y; yoff < y+h; yoff++, lineOff+=scansize) {
|
|
System.arraycopy(pix, lineOff, storage, 0, w);
|
|
iraster.setDataElements(x, yoff, w, 1, storage);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (model.getTransparency() != Transparency.OPAQUE &&
|
|
cmodel.getTransparency() == Transparency.OPAQUE) {
|
|
convertToRGB();
|
|
}
|
|
|
|
if (isDefaultBI) {
|
|
IntegerComponentRaster iraster =
|
|
(IntegerComponentRaster) biRaster;
|
|
int[] data = iraster.getDataStorage();
|
|
if (cmodel.equals(model)) {
|
|
int sstride = iraster.getScanlineStride();
|
|
int doff = y*sstride + x;
|
|
for (yoff=0; yoff < h; yoff++, lineOff += scansize) {
|
|
System.arraycopy(pix, lineOff, data, doff, w);
|
|
doff += sstride;
|
|
}
|
|
// Note: manual modification of pixels, mark the
|
|
// raster as changed
|
|
iraster.markDirty();
|
|
}
|
|
else {
|
|
for (yoff=y; yoff < y+h; yoff++, lineOff += scansize) {
|
|
poff = lineOff;
|
|
for (int i=0; i < w; i++) {
|
|
storage[i]=model.getRGB(pix[poff++]);
|
|
}
|
|
iraster.setDataElements(x, yoff, w, 1, storage);
|
|
}
|
|
}
|
|
|
|
availinfo |= ImageObserver.SOMEBITS;
|
|
}
|
|
else {
|
|
Object tmp = null;
|
|
|
|
for (yoff=y; yoff < y+h; yoff++, lineOff += scansize) {
|
|
poff = lineOff;
|
|
for (int xoff=x; xoff < x+w; xoff++) {
|
|
pixel = model.getRGB(pix[poff++]);
|
|
tmp = cmodel.getDataElements(pixel,tmp);
|
|
biRaster.setDataElements(xoff, yoff,tmp);
|
|
}
|
|
}
|
|
availinfo |= ImageObserver.SOMEBITS;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Can't do this here since we might need to transform/clip
|
|
// the region
|
|
if (((availinfo & ImageObserver.FRAMEBITS) == 0)) {
|
|
newInfo(image, ImageObserver.SOMEBITS, x, y, w, h);
|
|
}
|
|
}
|
|
|
|
public BufferedImage getOpaqueRGBImage() {
|
|
if (bimage.getType() == BufferedImage.TYPE_INT_ARGB) {
|
|
int w = bimage.getWidth();
|
|
int h = bimage.getHeight();
|
|
int size = w * h;
|
|
|
|
// Note that we steal the data array here, but only for reading...
|
|
DataBufferInt db = (DataBufferInt)biRaster.getDataBuffer();
|
|
int[] pixels = SunWritableRaster.stealData(db, 0);
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
if ((pixels[i] >>> 24) != 0xff) {
|
|
return bimage;
|
|
}
|
|
}
|
|
|
|
ColorModel opModel = new DirectColorModel(24,
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff);
|
|
|
|
int[] bandmasks = {0x00ff0000, 0x0000ff00, 0x000000ff};
|
|
WritableRaster opRaster = Raster.createPackedRaster(db, w, h, w,
|
|
bandmasks,
|
|
null);
|
|
|
|
try {
|
|
BufferedImage opImage = createImage(opModel, opRaster,
|
|
false, null);
|
|
return opImage;
|
|
} catch (Exception e) {
|
|
return bimage;
|
|
}
|
|
}
|
|
return bimage;
|
|
}
|
|
|
|
private boolean consuming = false;
|
|
|
|
public void imageComplete(int status) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
boolean done;
|
|
int info;
|
|
switch (status) {
|
|
default:
|
|
case ImageConsumer.IMAGEABORTED:
|
|
done = true;
|
|
info = ImageObserver.ABORT;
|
|
break;
|
|
case ImageConsumer.IMAGEERROR:
|
|
image.addInfo(ImageObserver.ERROR);
|
|
done = true;
|
|
info = ImageObserver.ERROR;
|
|
dispose();
|
|
break;
|
|
case ImageConsumer.STATICIMAGEDONE:
|
|
done = true;
|
|
info = ImageObserver.ALLBITS;
|
|
break;
|
|
case ImageConsumer.SINGLEFRAMEDONE:
|
|
done = false;
|
|
info = ImageObserver.FRAMEBITS;
|
|
break;
|
|
}
|
|
synchronized (this) {
|
|
if (done) {
|
|
image.getSource().removeConsumer(this);
|
|
consuming = false;
|
|
newbits = null;
|
|
|
|
if (bimage != null) {
|
|
bimage = getOpaqueRGBImage();
|
|
}
|
|
}
|
|
availinfo |= info;
|
|
notifyAll();
|
|
}
|
|
|
|
newInfo(image, info, 0, 0, width, height);
|
|
|
|
image.infoDone(status);
|
|
}
|
|
|
|
/*synchronized*/ void startProduction() {
|
|
if (!consuming) {
|
|
consuming = true;
|
|
image.getSource().startProduction(this);
|
|
}
|
|
}
|
|
|
|
private int numWaiters;
|
|
|
|
private synchronized void checkConsumption() {
|
|
if (isWatcherListEmpty() && numWaiters == 0 &&
|
|
((availinfo & ImageObserver.ALLBITS) == 0))
|
|
{
|
|
dispose();
|
|
}
|
|
}
|
|
|
|
public synchronized void notifyWatcherListEmpty() {
|
|
checkConsumption();
|
|
}
|
|
|
|
private synchronized void decrementWaiters() {
|
|
--numWaiters;
|
|
checkConsumption();
|
|
}
|
|
|
|
public boolean prepare(ImageObserver iw) {
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & ImageObserver.ERROR) != 0) {
|
|
if (iw != null) {
|
|
iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT,
|
|
-1, -1, -1, -1);
|
|
}
|
|
return false;
|
|
}
|
|
boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
if (!done) {
|
|
addWatcher(iw);
|
|
startProduction();
|
|
// Some producers deliver image data synchronously
|
|
done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
}
|
|
return done;
|
|
}
|
|
|
|
public int check(ImageObserver iw) {
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & (ImageObserver.ERROR | ImageObserver.ALLBITS)) == 0) {
|
|
addWatcher(iw);
|
|
}
|
|
|
|
return availinfo;
|
|
}
|
|
|
|
public boolean drawToBufImage(Graphics g, ToolkitImage img,
|
|
int x, int y, Color bg,
|
|
ImageObserver iw) {
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & ImageObserver.ERROR) != 0) {
|
|
if (iw != null) {
|
|
iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT,
|
|
-1, -1, -1, -1);
|
|
}
|
|
return false;
|
|
}
|
|
boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
boolean abort = ((availinfo & ImageObserver.ABORT) != 0);
|
|
|
|
if (!done && !abort) {
|
|
addWatcher(iw);
|
|
startProduction();
|
|
// Some producers deliver image data synchronously
|
|
done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
}
|
|
|
|
if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) {
|
|
g.drawImage (bimage, x, y, bg, null);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
public boolean drawToBufImage(Graphics g, ToolkitImage img,
|
|
int x, int y, int w, int h,
|
|
Color bg, ImageObserver iw) {
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & ImageObserver.ERROR) != 0) {
|
|
if (iw != null) {
|
|
iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT,
|
|
-1, -1, -1, -1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
boolean abort = ((availinfo & ImageObserver.ABORT) != 0);
|
|
|
|
if (!done && !abort) {
|
|
addWatcher(iw);
|
|
startProduction();
|
|
// Some producers deliver image data synchronously
|
|
done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
}
|
|
|
|
if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) {
|
|
g.drawImage (bimage, x, y, w, h, bg, null);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
public boolean drawToBufImage(Graphics g, ToolkitImage img,
|
|
int dx1, int dy1, int dx2, int dy2,
|
|
int sx1, int sy1, int sx2, int sy2,
|
|
Color bg, ImageObserver iw) {
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & ImageObserver.ERROR) != 0) {
|
|
if (iw != null) {
|
|
iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT,
|
|
-1, -1, -1, -1);
|
|
}
|
|
return false;
|
|
}
|
|
boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
boolean abort = ((availinfo & ImageObserver.ABORT) != 0);
|
|
|
|
if (!done && !abort) {
|
|
addWatcher(iw);
|
|
startProduction();
|
|
// Some producers deliver image data synchronously
|
|
done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
}
|
|
|
|
if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) {
|
|
g.drawImage (bimage,
|
|
dx1, dy1, dx2, dy2,
|
|
sx1, sy1, sx2, sy2,
|
|
bg, null);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
public boolean drawToBufImage(Graphics g, ToolkitImage img,
|
|
AffineTransform xform,
|
|
ImageObserver iw)
|
|
{
|
|
Graphics2D g2 = (Graphics2D) g;
|
|
|
|
if (src != null) {
|
|
src.checkSecurity(null, false);
|
|
}
|
|
if ((availinfo & ImageObserver.ERROR) != 0) {
|
|
if (iw != null) {
|
|
iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT,
|
|
-1, -1, -1, -1);
|
|
}
|
|
return false;
|
|
}
|
|
boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
boolean abort = ((availinfo & ImageObserver.ABORT) != 0);
|
|
|
|
if (!done && !abort) {
|
|
addWatcher(iw);
|
|
startProduction();
|
|
// Some producers deliver image data synchronously
|
|
done = ((availinfo & ImageObserver.ALLBITS) != 0);
|
|
}
|
|
|
|
if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) {
|
|
g2.drawImage (bimage, xform, null);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
synchronized void abort() {
|
|
image.getSource().removeConsumer(this);
|
|
consuming = false;
|
|
newbits = null;
|
|
bimage = null;
|
|
biRaster = null;
|
|
cmodel = null;
|
|
srcLUT = null;
|
|
isDefaultBI = false;
|
|
isSameCM = false;
|
|
|
|
newInfo(image, ImageObserver.ABORT, -1, -1, -1, -1);
|
|
availinfo &= ~(ImageObserver.SOMEBITS
|
|
| ImageObserver.FRAMEBITS
|
|
| ImageObserver.ALLBITS
|
|
| ImageObserver.ERROR);
|
|
}
|
|
|
|
synchronized void dispose() {
|
|
image.getSource().removeConsumer(this);
|
|
consuming = false;
|
|
newbits = null;
|
|
availinfo &= ~(ImageObserver.SOMEBITS
|
|
| ImageObserver.FRAMEBITS
|
|
| ImageObserver.ALLBITS);
|
|
}
|
|
|
|
public void setAccelerationPriority(float priority) {
|
|
if (bimage != null) {
|
|
bimage.setAccelerationPriority(priority);
|
|
}
|
|
}
|
|
}
|