/*
* Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt.image;
import java.util.
Hashtable;
import java.awt.image.
ImageConsumer;
import java.awt.image.
ImageFilter;
/**
* The <code>BufferedImageFilter</code> class subclasses an
* <code>ImageFilter</code> to provide a simple means of
* using a single-source/single-destination image operator
* ({@link BufferedImageOp}) to filter a <code>BufferedImage</code>
* in the Image Producer/Consumer/Observer
* paradigm. Examples of these image operators are: {@link ConvolveOp},
* {@link AffineTransformOp} and {@link LookupOp}.
*
* @see ImageFilter
* @see BufferedImage
* @see BufferedImageOp
*/
public class
BufferedImageFilter extends
ImageFilter implements
Cloneable {
BufferedImageOp bufferedImageOp;
ColorModel model;
int
width;
int
height;
byte[]
bytePixels;
int[]
intPixels;
/**
* Constructs a <code>BufferedImageFilter</code> with the
* specified single-source/single-destination operator.
* @param op the specified <code>BufferedImageOp</code> to
* use to filter a <code>BufferedImage</code>
* @throws NullPointerException if op is null
*/
public
BufferedImageFilter (
BufferedImageOp op) {
super();
if (
op == null) {
throw new
NullPointerException("Operation cannot be null");
}
bufferedImageOp =
op;
}
/**
* Returns the <code>BufferedImageOp</code>.
* @return the operator of this <code>BufferedImageFilter</code>.
*/
public
BufferedImageOp getBufferedImageOp() {
return
bufferedImageOp;
}
/**
* Filters the information provided in the
* {@link ImageConsumer#setDimensions(int, int) setDimensions } method
* of the {@link ImageConsumer} interface.
* <p>
* Note: This method is intended to be called by the
* {@link ImageProducer} of the <code>Image</code> whose pixels are
* being filtered. Developers using this class to retrieve pixels from
* an image should avoid calling this method directly since that
* operation could result in problems with retrieving the requested
* pixels.
* <p>
* @param width the width to which to set the width of this
* <code>BufferedImageFilter</code>
* @param height the height to which to set the height of this
* <code>BufferedImageFilter</code>
* @see ImageConsumer#setDimensions
*/
public void
setDimensions(int
width, int
height) {
if (
width <= 0 ||
height <= 0) {
imageComplete(
STATICIMAGEDONE);
return;
}
this.
width =
width;
this.
height =
height;
}
/**
* Filters the information provided in the
* {@link ImageConsumer#setColorModel(ColorModel) setColorModel} method
* of the <code>ImageConsumer</code> interface.
* <p>
* If <code>model</code> is <code>null</code>, this
* method clears the current <code>ColorModel</code> of this
* <code>BufferedImageFilter</code>.
* <p>
* Note: This method is intended to be called by the
* <code>ImageProducer</code> of the <code>Image</code>
* whose pixels are being filtered. Developers using this
* class to retrieve pixels from an image
* should avoid calling this method directly since that
* operation could result in problems with retrieving the
* requested pixels.
* @param model the {@link ColorModel} to which to set the
* <code>ColorModel</code> of this <code>BufferedImageFilter</code>
* @see ImageConsumer#setColorModel
*/
public void
setColorModel(
ColorModel model) {
this.
model =
model;
}
private void
convertToRGB() {
int
size =
width *
height;
int
newpixels[] = new int[
size];
if (
bytePixels != null) {
for (int
i = 0;
i <
size;
i++) {
newpixels[
i] = this.
model.
getRGB(
bytePixels[
i] & 0xff);
}
} else if (
intPixels != null) {
for (int
i = 0;
i <
size;
i++) {
newpixels[
i] = this.
model.
getRGB(
intPixels[
i]);
}
}
bytePixels = null;
intPixels =
newpixels;
this.
model =
ColorModel.
getRGBdefault();
}
/**
* Filters the information provided in the <code>setPixels</code>
* method of the <code>ImageConsumer</code> interface which takes
* an array of bytes.
* <p>
* Note: This method is intended to be called by the
* <code>ImageProducer</code> of the <code>Image</code> whose pixels
* are being filtered. Developers using
* this class to retrieve pixels from an image should avoid calling
* this method directly since that operation could result in problems
* with retrieving the requested pixels.
* @throws IllegalArgumentException if width or height are less than
* zero.
* @see ImageConsumer#setPixels(int, int, int, int, ColorModel, byte[],
int, int)
*/
public void
setPixels(int
x, int
y, int
w, int
h,
ColorModel model, byte
pixels[], int
off,
int
scansize) {
// Fix 4184230
if (
w < 0 ||
h < 0) {
throw new
IllegalArgumentException("Width ("+
w+
") and height ("+
h+
") must be > 0");
}
// Nothing to do
if (
w == 0 ||
h == 0) {
return;
}
if (
y < 0) {
int
diff = -
y;
if (
diff >=
h) {
return;
}
off +=
scansize *
diff;
y +=
diff;
h -=
diff;
}
if (
y +
h >
height) {
h =
height -
y;
if (
h <= 0) {
return;
}
}
if (
x < 0) {
int
diff = -
x;
if (
diff >=
w) {
return;
}
off +=
diff;
x +=
diff;
w -=
diff;
}
if (
x +
w >
width) {
w =
width -
x;
if (
w <= 0) {
return;
}
}
int
dstPtr =
y*
width +
x;
if (
intPixels == null) {
if (
bytePixels == null) {
bytePixels = new byte[
width*
height];
this.
model =
model;
} else if (this.
model !=
model) {
convertToRGB();
}
if (
bytePixels != null) {
for (int
sh =
h;
sh > 0;
sh--) {
System.
arraycopy(
pixels,
off,
bytePixels,
dstPtr,
w);
off +=
scansize;
dstPtr +=
width;
}
}
}
if (
intPixels != null) {
int
dstRem =
width -
w;
int
srcRem =
scansize -
w;
for (int
sh =
h;
sh > 0;
sh--) {
for (int
sw =
w;
sw > 0;
sw--) {
intPixels[
dstPtr++] =
model.
getRGB(
pixels[
off++]&0xff);
}
off +=
srcRem;
dstPtr +=
dstRem;
}
}
}
/**
* Filters the information provided in the <code>setPixels</code>
* method of the <code>ImageConsumer</code> interface which takes
* an array of integers.
* <p>
* Note: This method is intended to be called by the
* <code>ImageProducer</code> of the <code>Image</code> whose
* pixels are being filtered. Developers using this class to
* retrieve pixels from an image should avoid calling this method
* directly since that operation could result in problems
* with retrieving the requested pixels.
* @throws IllegalArgumentException if width or height are less than
* zero.
* @see ImageConsumer#setPixels(int, int, int, int, ColorModel, int[],
int, int)
*/
public void
setPixels(int
x, int
y, int
w, int
h,
ColorModel model, int
pixels[], int
off,
int
scansize) {
// Fix 4184230
if (
w < 0 ||
h < 0) {
throw new
IllegalArgumentException("Width ("+
w+
") and height ("+
h+
") must be > 0");
}
// Nothing to do
if (
w == 0 ||
h == 0) {
return;
}
if (
y < 0) {
int
diff = -
y;
if (
diff >=
h) {
return;
}
off +=
scansize *
diff;
y +=
diff;
h -=
diff;
}
if (
y +
h >
height) {
h =
height -
y;
if (
h <= 0) {
return;
}
}
if (
x < 0) {
int
diff = -
x;
if (
diff >=
w) {
return;
}
off +=
diff;
x +=
diff;
w -=
diff;
}
if (
x +
w >
width) {
w =
width -
x;
if (
w <= 0) {
return;
}
}
if (
intPixels == null) {
if (
bytePixels == null) {
intPixels = new int[
width *
height];
this.
model =
model;
} else {
convertToRGB();
}
}
int
dstPtr =
y*
width +
x;
if (this.
model ==
model) {
for (int
sh =
h;
sh > 0;
sh--) {
System.
arraycopy(
pixels,
off,
intPixels,
dstPtr,
w);
off +=
scansize;
dstPtr +=
width;
}
} else {
if (this.
model !=
ColorModel.
getRGBdefault()) {
convertToRGB();
}
int
dstRem =
width -
w;
int
srcRem =
scansize -
w;
for (int
sh =
h;
sh > 0;
sh--) {
for (int
sw =
w;
sw > 0;
sw--) {
intPixels[
dstPtr++] =
model.
getRGB(
pixels[
off++]);
}
off +=
srcRem;
dstPtr +=
dstRem;
}
}
}
/**
* Filters the information provided in the <code>imageComplete</code>
* method of the <code>ImageConsumer</code> interface.
* <p>
* Note: This method is intended to be called by the
* <code>ImageProducer</code> of the <code>Image</code> whose pixels
* are being filtered. Developers using
* this class to retrieve pixels from an image should avoid calling
* this method directly since that operation could result in problems
* with retrieving the requested pixels.
* @param status the status of image loading
* @throws ImagingOpException if there was a problem calling the filter
* method of the <code>BufferedImageOp</code> associated with this
* instance.
* @see ImageConsumer#imageComplete
*/
public void
imageComplete(int
status) {
WritableRaster wr;
switch(
status) {
case
IMAGEERROR:
case
IMAGEABORTED:
// reinitialize the params
model = null;
width = -1;
height = -1;
intPixels = null;
bytePixels = null;
break;
case
SINGLEFRAMEDONE:
case
STATICIMAGEDONE:
if (
width <= 0 ||
height <= 0) break;
if (
model instanceof
DirectColorModel) {
if (
intPixels == null) break;
wr =
createDCMraster();
}
else if (
model instanceof
IndexColorModel) {
int[]
bandOffsets = {0};
if (
bytePixels == null) break;
DataBufferByte db = new
DataBufferByte(
bytePixels,
width*
height);
wr =
Raster.
createInterleavedRaster(
db,
width,
height,
width,
1,
bandOffsets, null);
}
else {
convertToRGB();
if (
intPixels == null) break;
wr =
createDCMraster();
}
BufferedImage bi = new
BufferedImage(
model,
wr,
model.
isAlphaPremultiplied(),
null);
bi =
bufferedImageOp.
filter(
bi, null);
WritableRaster r =
bi.
getRaster();
ColorModel cm =
bi.
getColorModel();
int
w =
r.
getWidth();
int
h =
r.
getHeight();
consumer.
setDimensions(
w,
h);
consumer.
setColorModel(
cm);
if (
cm instanceof
DirectColorModel) {
DataBufferInt db = (
DataBufferInt)
r.
getDataBuffer();
consumer.
setPixels(0, 0,
w,
h,
cm,
db.
getData(), 0,
w);
}
else if (
cm instanceof
IndexColorModel) {
DataBufferByte db = (
DataBufferByte)
r.
getDataBuffer();
consumer.
setPixels(0, 0,
w,
h,
cm,
db.
getData(), 0,
w);
}
else {
throw new
InternalError("Unknown color model "+
cm);
}
break;
}
consumer.
imageComplete(
status);
}
private final
WritableRaster createDCMraster() {
WritableRaster wr;
DirectColorModel dcm = (
DirectColorModel)
model;
boolean
hasAlpha =
model.
hasAlpha();
int[]
bandMasks = new int[3+(
hasAlpha ? 1 : 0)];
bandMasks[0] =
dcm.
getRedMask();
bandMasks[1] =
dcm.
getGreenMask();
bandMasks[2] =
dcm.
getBlueMask();
if (
hasAlpha) {
bandMasks[3] =
dcm.
getAlphaMask();
}
DataBufferInt db = new
DataBufferInt(
intPixels,
width*
height);
wr =
Raster.
createPackedRaster(
db,
width,
height,
width,
bandMasks, null);
return
wr;
}
}