blob: 8b6fcf0465054c0380f441e39e9e5bf04f543f7b [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.
*
* @since Android 1.0
*/
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;
}
}
}