src.getMinX()+src.getWidth()-1)
x1 = src.getMinX()+src.getWidth()-1;
int y1 = dst.getMinY()+dst.getHeight()-1;
if (y1 > src.getMinY()+src.getHeight()-1)
y1 = src.getMinY()+src.getHeight()-1;
int width = x1-x0+1;
int [] data = null;
for (int y = y0; y <= y1 ; y++) {
data = src.getPixels(x0,y,width,1,data);
dst.setPixels (x0,y,width,1,data);
}
}
/**
* Copies data from one raster to another. Only the region of
* overlap between src and dst is copied. Src and
* Dst must have compatible SampleModels.
*
* @param src The source of the data
* @param dst The destination for the data.
*/
public static void copyData(Raster src, WritableRaster dst) {
if (is_INT_PACK_Data(src.getSampleModel(), false) &&
is_INT_PACK_Data(dst.getSampleModel(), false)) {
copyData_INT_PACK(src, dst);
return;
}
copyData_FALLBACK(src, dst);
}
/**
* Creates a new raster that has a copy of the data in
* ras. This is highly optimized for speed. There is
* no provision for changing any aspect of the SampleModel.
*
* This method should be used when you need to change the contents
* of a Raster that you do not "own" (ie the result of a
* getData call).
* @param ras The Raster to copy.
* @return A writable copy of ras
*/
public static WritableRaster copyRaster(Raster ras) {
return copyRaster(ras, ras.getMinX(), ras.getMinY());
}
/**
* Creates a new raster that has a copy of the data in
* ras. This is highly optimized for speed. There is
* no provision for changing any aspect of the SampleModel.
* However you can specify a new location for the returned raster.
*
* This method should be used when you need to change the contents
* of a Raster that you do not "own" (ie the result of a
* getData call).
*
* @param ras The Raster to copy.
*
* @param minX The x location for the upper left corner of the
* returned WritableRaster.
*
* @param minY The y location for the upper left corner of the
* returned WritableRaster.
*
* @return A writable copy of ras
*/
public static WritableRaster copyRaster(Raster ras, int minX, int minY) {
WritableRaster ret = Raster.createWritableRaster
(ras.getSampleModel(),
new Point(0,0));
ret = ret.createWritableChild
(ras.getMinX()-ras.getSampleModelTranslateX(),
ras.getMinY()-ras.getSampleModelTranslateY(),
ras.getWidth(), ras.getHeight(),
minX, minY, null);
// Use System.arraycopy to copy the data between the two...
DataBuffer srcDB = ras.getDataBuffer();
DataBuffer retDB = ret.getDataBuffer();
if (srcDB.getDataType() != retDB.getDataType()) {
throw new IllegalArgumentException
("New DataBuffer doesn't match original");
}
int len = srcDB.getSize();
int banks = srcDB.getNumBanks();
int [] offsets = srcDB.getOffsets();
for (int b=0; b< banks; b++) {
switch (srcDB.getDataType()) {
case DataBuffer.TYPE_BYTE: {
DataBufferByte srcDBT = (DataBufferByte)srcDB;
DataBufferByte retDBT = (DataBufferByte)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
break;
}
case DataBuffer.TYPE_INT: {
DataBufferInt srcDBT = (DataBufferInt)srcDB;
DataBufferInt retDBT = (DataBufferInt)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
break;
}
case DataBuffer.TYPE_SHORT: {
DataBufferShort srcDBT = (DataBufferShort)srcDB;
DataBufferShort retDBT = (DataBufferShort)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
break;
}
case DataBuffer.TYPE_USHORT: {
DataBufferUShort srcDBT = (DataBufferUShort)srcDB;
DataBufferUShort retDBT = (DataBufferUShort)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
break;
}
}
}
return ret;
}
/**
* Coerces ras to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in ras,
* use copyRaster (above).
* @param ras The raster to make writable.
* @return A Writable version of ras (shares DataBuffer with
* ras).
*/
public static WritableRaster makeRasterWritable(Raster ras) {
return makeRasterWritable(ras, ras.getMinX(), ras.getMinY());
}
/**
* Coerces ras to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.
*
* You can specify a new location for the returned WritableRaster, this
* is especially useful for constructing BufferedImages which require
* the Raster to be at (0,0).
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in ras,
* use copyRaster (above).
*
* @param ras The raster to make writable.
*
* @param minX The x location for the upper left corner of the
* returned WritableRaster.
*
* @param minY The y location for the upper left corner of the
* returned WritableRaster.
*
* @return A Writable version of ras with it's upper left
* hand coordinate set to minX, minY (shares it's DataBuffer
* with ras).
*/
public static WritableRaster makeRasterWritable(Raster ras,
int minX, int minY) {
WritableRaster ret = Raster.createWritableRaster
(ras.getSampleModel(),
ras.getDataBuffer(),
new Point(0,0));
ret = ret.createWritableChild
(ras.getMinX()-ras.getSampleModelTranslateX(),
ras.getMinY()-ras.getSampleModelTranslateY(),
ras.getWidth(), ras.getHeight(),
minX, minY, null);
return ret;
}
/**
* Create a new ColorModel with it's alpha premultiplied state matching
* newAlphaPreMult.
* @param cm The ColorModel to change the alpha premult state of.
* @param newAlphaPreMult The new state of alpha premult.
* @return A new colorModel that has isAlphaPremultiplied()
* equal to newAlphaPreMult.
*/
public static ColorModel
coerceColorModel(ColorModel cm, boolean newAlphaPreMult) {
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
return cm;
// Easiest way to build proper colormodel for new Alpha state...
// Eventually this should switch on known ColorModel types and
// only fall back on this hack when the CM type is unknown.
WritableRaster wr = cm.createCompatibleWritableRaster(1,1);
return cm.coerceData(wr, newAlphaPreMult);
}
/**
* Coerces data within a bufferedImage to match newAlphaPreMult,
* Note that this can not change the colormodel of bi so you
*
* @param wr The raster to change the state of.
* @param cm The colormodel currently associated with data in wr.
* @param newAlphaPreMult The desired state of alpha Premult for raster.
* @return A new colormodel that matches newAlphaPreMult.
*/
public static ColorModel
coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) {
// System.out.println("CoerceData: " + cm.isAlphaPremultiplied() +
// " Out: " + newAlphaPreMult);
if (!cm.hasAlpha())
// Nothing to do no alpha channel
return cm;
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
// nothing to do alpha state matches...
return cm;
// System.out.println("CoerceData: " + wr.getSampleModel());
if (newAlphaPreMult) {
multiplyAlpha(wr);
} else {
divideAlpha(wr);
}
return coerceColorModel(cm, newAlphaPreMult);
}
public static void multiplyAlpha(WritableRaster wr) {
if (is_BYTE_COMP_Data(wr.getSampleModel()))
mult_BYTE_COMP_Data(wr);
else if (is_INT_PACK_Data(wr.getSampleModel(), true))
mult_INT_PACK_Data(wr);
else {
int [] pixel = null;
int bands = wr.getNumBands();
float norm = 1f/255f;
int x0, x1, y0, y1, a, b;
float alpha;
x0 = wr.getMinX();
x1 = x0+wr.getWidth();
y0 = wr.getMinY();
y1 = y0+wr.getHeight();
for (int y=y0; y= 0) && (a < 255)) {
alpha = a*norm;
for (b=0; b 0) && (a < 255)) {
ialpha = 255/(float)a;
for (b=0; b= 0) {
// Fill alpha channel with 255's
oPix[out] = 255;
out -= bands;
}
int b, in;
for (int y=y0; y<=y1; y++) {
pixel = srcR.getPixels(x0,y,w,1,pixel);
in = w*(bands-1)-1;
out = (w*bands)-2; // The 2 skips alpha channel on last pix
switch (bands) {
case 4:
while(in >= 0) {
oPix[out--] = pixel[in--];
oPix[out--] = pixel[in--];
oPix[out--] = pixel[in--];
out--;
}
break;
default:
while(in >= 0) {
for (b=0; b= 0) {
a = pixel[in];
if (a == 255)
in -= 4;
else {
in--;
alpha = fpNorm*a;
pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
pixel[in] = (pixel[in]*alpha+pt5)>>>24; in--;
}
}
break;
default:
while(in >= 0) {
a = pixel[in];
if (a == 255)
in -= bands;
else {
in--;
alpha = fpNorm*a;
for (b=0; b>>24;
in--;
}
}
}
}
dstR.setPixels(x0+dx, y+dy, w, 1, pixel);
}
} else if (dstAlpha && !dst.isAlphaPremultiplied()) {
// Src and dest have Alpha but we need to divide it out for dst.
// System.out.println("Div Case");
int a, b, ialpha, in, fpNorm = 0x00FF0000, pt5 = 1<<15;
for (int y=y0; y<=y1; y++) {
pixel = srcR.getPixels(x0,y,w,1,pixel);
in=(bands*w)-1;
switch(bands) {
case 4:
while(in >= 0) {
a = pixel[in];
if ((a <= 0) || (a >= 255))
in -= 4;
else {
in--;
ialpha = fpNorm/a;
pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
pixel[in] = (pixel[in]*ialpha+pt5)>>>16; in--;
}
}
break;
default:
while(in >= 0) {
a = pixel[in];
if ((a <= 0) || (a >= 255))
in -= bands;
else {
in--;
ialpha = fpNorm/a;
for (b=0; b>>16;
in--;
}
}
}
}
dstR.setPixels(x0+dx, y+dy, w, 1, pixel);
}
} else if (src.isAlphaPremultiplied()) {
int [] oPix = new int[bands*w];
// Src has alpha dest does not so unpremult and store...
// System.out.println("Remove Alpha, Div Case");
int a, b, ialpha, in, out, fpNorm = 0x00FF0000, pt5 = 1<<15;
for (int y=y0; y<=y1; y++) {
pixel = srcR.getPixels(x0,y,w,1,pixel);
in = (bands+1)*w -1;
out = (bands*w)-1;
while(in >= 0) {
a = pixel[in]; in--;
if (a > 0) {
if (a < 255) {
ialpha = fpNorm/a;
for (b=0; b>>16;
} else
for (b=0; b>>24;
if (a<=0) {
pixels[sp] = 0x00FFFFFF;
} else if (a<255) {
int aFP = (0x00FF0000/a);
pixels[sp] =
((a << 24) |
(((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) |
(((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) |
(((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16));
}
sp++;
}
}
}
protected static void mult_INT_PACK_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = sppsm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
final int base
= (db.getOffset() +
sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
// Access the pixel data array
final int[] pixels = db.getBankData()[0];
for (int y=0; y>>24;
if ((a>=0) && (a<255)) { // this does NOT include a == 255 (0xff) !
pixels[sp] = ((a << 24) |
((((pixel&0xFF0000)*a)>>8)&0xFF0000) |
((((pixel&0x00FF00)*a)>>8)&0x00FF00) |
((((pixel&0x0000FF)*a)>>8)&0x0000FF));
}
sp++;
}
}
}
protected static void divide_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
// Access the pixel data array
final byte[] pixels = db.getBankData()[0];
for (int y=0; y>>16);
}
}
sp+=pixStride;
}
}
}
protected static void mult_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
// Access the pixel data array
final byte[] pixels = db.getBankData()[0];
for (int y=0; y>8);
}
sp+=pixStride;
}
}
}
/*
This is skanky debugging code that might be useful in the future:
if (count == 33) {
String label = "sub [" + x + ", " + y + "]: ";
org.ImageDisplay.showImage
(label, subBI);
org.ImageDisplay.printImage
(label, subBI,
new Rectangle(75-iR.x, 90-iR.y, 32, 32));
}
// if ((count++ % 50) == 10)
// org.ImageDisplay.showImage("foo: ", subBI);
Graphics2D realG2D = g2d;
while (realG2D instanceof sun.java2d.ProxyGraphics2D) {
realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate();
}
if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) {
count++;
if (count == 34) {
RenderedImage ri;
ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg;
// g2d.setComposite(SVGComposite.OVER);
// org.ImageDisplay.showImage("Bar: " + count, cr);
org.ImageDisplay.printImage("Bar: " + count, cr,
new Rectangle(75, 90, 32, 32));
org.ImageDisplay.showImage ("Foo: " + count, ri);
org.ImageDisplay.printImage("Foo: " + count, ri,
new Rectangle(75, 90, 32, 32));
System.out.println("BI: " + ri);
System.out.println("BISM: " + ri.getSampleModel());
System.out.println("BICM: " + ri.getColorModel());
System.out.println("BICM class: " + ri.getColorModel().getClass());
System.out.println("BICS: " + ri.getColorModel().getColorSpace());
System.out.println
("sRGB CS: " +
ColorSpace.getInstance(ColorSpace.CS_sRGB));
System.out.println("G2D info");
System.out.println("\tComposite: " + g2d.getComposite());
System.out.println("\tTransform" + g2d.getTransform());
java.awt.RenderingHints rh = g2d.getRenderingHints();
java.util.Set keys = rh.keySet();
java.util.Iterator iter = keys.iterator();
while (iter.hasNext()) {
Object o = iter.next();
System.out.println("\t" + o.toString() + " -> " +
rh.get(o).toString());
}
ri = cr;
System.out.println("RI: " + ri);
System.out.println("RISM: " + ri.getSampleModel());
System.out.println("RICM: " + ri.getColorModel());
System.out.println("RICM class: " + ri.getColorModel().getClass());
System.out.println("RICS: " + ri.getColorModel().getColorSpace());
}
}
*/
/**
* Extracts an alpha raster from a RenderedImage. The method tries to avoid copying data
* unnecessarily by checking if the RenderedImage is a BufferedImage which offers suitable
* direct methods.
* @param image the image
* @return the alpha raster
*/
public static Raster getAlphaRaster(RenderedImage image) {
ColorModel cm = image.getColorModel();
if (!cm.hasAlpha() || cm.getTransparency() != ColorModel.TRANSLUCENT) {
throw new IllegalStateException("Image doesn't have an alpha channel");
}
Raster alpha;
if (image instanceof BufferedImage) {
//Optimization possible with BufferedImage (No copying)
alpha = ((BufferedImage)image).getAlphaRaster();
} else {
WritableRaster wraster = GraphicsUtil.makeRasterWritable(image.getData());
alpha = image.getColorModel().getAlphaRaster(wraster);
}
return alpha;
}
}