blob: 44b3c2ed2ab69b595b2f75ab04027acaaaaa2e38 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @author Oleg V. Khaschansky
* @version $Revision$
*/
package java.awt.image;
import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
import org.apache.harmony.awt.internal.nls.Messages;
/**
* The BufferedImageFilter class provides filtering operations to
* the BufferedImage objects using operators which implement
* BufferedImageOp interface.
*/
public class BufferedImageFilter extends ImageFilter implements Cloneable {
/** The Constant accessor. */
private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance();
/** The op. */
private BufferedImageOp op;
/** The raster. */
private WritableRaster raster;
/** The i data. */
private int iData[];
/** The b data. */
private byte bData[];
/** The width. */
private int width;
/** The height. */
private int height;
/** The cm. */
private ColorModel cm;
/** The forced rgb. */
private boolean forcedRGB = false;
/** The transfer type. */
private int transferType = DataBuffer.TYPE_UNDEFINED;
/**
* Instantiates a new BufferedImageFilter with the specified
* BufferedImageOp operator.
*
* @param op the specified BufferedImageOp operator.
*
* @throws NullPointerException if BufferedImageOp is null.
*/
public BufferedImageFilter(BufferedImageOp op) {
if (op == null) {
throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$
}
this.op = op;
}
/**
* Gets the BufferedImageOp operator associated with this
* BufferedImageFilter object.
*
* @return the BufferedImageOp associated with this
* BufferedImageFilter object.
*/
public BufferedImageOp getBufferedImageOp() {
return op;
}
@Override
public void setDimensions(int width, int height) {
this.width = width;
this.height = height;
// Stop image consuming if no pixels expected.
if (width <= 0 || height <= 0) {
consumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
reset();
}
}
@Override
public void setColorModel(ColorModel model) {
if (this.cm != null && this.cm != model && raster != null) {
forceRGB();
} else {
this.cm = model;
}
}
@Override
public void setPixels(
int x, int y, int
w, int h,
ColorModel model, byte[] pixels,
int off, int scansize
) {
setPixels(x, y, w, h, model, pixels, off, scansize, true);
}
@Override
public void setPixels(
int x, int y,
int w, int h,
ColorModel model, int[] pixels,
int off, int scansize
) {
setPixels(x, y, w, h, model, pixels, off, scansize, false);
}
@Override
public void imageComplete(int status) {
if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) {
BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null);
bim = op.filter(bim, null);
DataBuffer dstDb = bim.getRaster().getDataBuffer();
ColorModel dstCm = bim.getColorModel();
int dstW = bim.getWidth();
int dstH = bim.getHeight();
consumer.setDimensions(dstW, dstH);
if (dstDb.getDataType() == DataBuffer.TYPE_INT) {
consumer.setColorModel(dstCm);
consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW);
} else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) {
consumer.setColorModel(dstCm);
consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW);
} else {
int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW);
dstCm = ColorModel.getRGBdefault();
consumer.setColorModel(dstCm);
consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW);
}
} else if (status == IMAGEERROR || status == IMAGEABORTED) {
reset();
}
consumer.imageComplete(status);
}
/**
* Sets the pixels.
*
* @param x the x
* @param y the y
* @param w the w
* @param h the h
* @param model the model
* @param pixels the pixels
* @param off the off
* @param scansize the scansize
* @param isByteData the is byte data
*/
private void setPixels(
int x, int y,
int w, int h,
ColorModel model, Object pixels,
int off, int scansize, boolean isByteData
) {
// Check bounds
// Need to copy only the pixels that will fit into the destination area
if (x < 0) {
w -= x;
off += x;
x = 0;
}
if (y < 0) {
h -= y;
off += y * scansize;
y = 0;
}
if (x + w > width) {
w = width - x;
}
if (y + h > height) {
h = height - y;
}
if (w <= 0 || h <= 0) {
return;
}
// Check model
if (this.cm == null) {
setColorModel(model);
} else if (model == null) {
model = this.cm;
} else if (!model.equals(this.cm)) {
forceRGB();
}
boolean canArraycopy;
// Process pixels
switch(transferType) {
case DataBuffer.TYPE_UNDEFINED: {
if (isByteData) {
transferType = DataBuffer.TYPE_BYTE;
createRaster(transferType);
//bData = new byte[width*height];
canArraycopy = !forcedRGB;
break;
}
transferType = DataBuffer.TYPE_INT;
createRaster(transferType);
//iData = new int[width*height];
canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault());
break;
} // And proceed to copy the pixels
case DataBuffer.TYPE_INT: {
if (isByteData) { // There are int data already but the new data are bytes
forceRGB();
canArraycopy = false;
break;
} else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) {
canArraycopy = true;
break;
} // Else fallback to the RGB conversion
}
case DataBuffer.TYPE_BYTE: {
if (isByteData && !forcedRGB) {
canArraycopy = true;
break;
}
// RGB conversion
canArraycopy = false;
break;
} default: {
throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$
}
}
off += x;
int maxOffset = off + h * scansize;
int dstOffset = x + y * width;
if (canArraycopy) {
Object dstArray = isByteData ? (Object) bData : (Object) iData;
for (; off < maxOffset; off += scansize, dstOffset += width) {
System.arraycopy(pixels, off, dstArray, dstOffset, w);
}
} else {
// RGB conversion
for (; off < maxOffset; off += scansize, dstOffset += width) {
int srcPos = off;
int dstPos = dstOffset;
int maxDstPos = dstOffset + w;
for (; dstPos < maxDstPos; dstPos++, srcPos++) {
iData[dstPos] = model.getRGB(
isByteData ?
((byte[])pixels)[srcPos] :
((int[])pixels)[srcPos]
);
}
}
}
}
/**
* Force rgb.
*/
private void forceRGB() {
if (!forcedRGB) {
forcedRGB = true;
int size = width*height;
int rgbData[] = new int[size];
if (bData != null) {
for (int i=0; i<size; i++) {
rgbData[i] = cm.getRGB(bData[i]);
}
} else if (iData != null) {
for (int i=0; i<size; i++) {
rgbData[i] = cm.getRGB(iData[i]);
}
}
cm = ColorModel.getRGBdefault();
DataBufferInt db = new DataBufferInt(rgbData, size);
int masks[] = new int[] {0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000};
raster = Raster.createPackedRaster(db, width, height, width, masks, null);
iData = accessor.getDataInt(db);
bData = null;
transferType = DataBuffer.TYPE_INT;
}
}
/**
* Reset.
*/
private void reset() {
width = 0;
height = 0;
forcedRGB = false;
cm = null;
iData = null;
bData = null;
transferType = DataBuffer.TYPE_UNDEFINED;
raster = null;
}
/**
* Creates the raster.
*
* @param dataType the data type
*/
private void createRaster(int dataType) {
boolean createdValidBuffer = false;
try{
raster = cm.createCompatibleWritableRaster(width, height);
int rasterType = raster.getDataBuffer().getDataType();
if (rasterType == dataType) {
switch (rasterType) {
case DataBuffer.TYPE_INT: {
iData = accessor.getDataInt(raster.getDataBuffer());
if (iData != null) {
createdValidBuffer = true;
}
break;
}
case DataBuffer.TYPE_BYTE: {
bData = accessor.getDataByte(raster.getDataBuffer());
if (bData != null) {
createdValidBuffer = true;
}
break;
}
default:
createdValidBuffer = false;
}
if(cm == ColorModel.getRGBdefault()){
forcedRGB = true;
}
} else {
createdValidBuffer = false;
}
} catch(Exception e) {
createdValidBuffer = false;
}
if (createdValidBuffer == false) {
cm = ColorModel.getRGBdefault();
raster = cm.createCompatibleWritableRaster(width, height);
iData = accessor.getDataInt(raster.getDataBuffer());
bData = null;
forcedRGB = true;
}
}
}