
org.apache.xmlgraphics.image.GraphicsUtil Maven / Gradle / Ivy
/*
* 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.
*/
/* $Id: GraphicsUtil.java 750418 2009-03-05 11:03:54Z vhennebert $ */
package org.apache.xmlgraphics.image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import org.apache.xmlgraphics.image.rendered.Any2LsRGBRed;
import org.apache.xmlgraphics.image.rendered.Any2sRGBRed;
import org.apache.xmlgraphics.image.rendered.BufferedImageCachableRed;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.xmlgraphics.image.rendered.RenderedImageCachableRed;
/**
* Set of utility methods for Graphics.
* These generally bypass broken methods in Java2D or provide tweaked
* implementations.
*
* @author Thomas DeWeese
* @version $Id: GraphicsUtil.java 750418 2009-03-05 11:03:54Z vhennebert $
*/
public class GraphicsUtil {
public static AffineTransform IDENTITY = new AffineTransform();
/**
* Standard prebuilt Linear_sRGB color model with no alpha */
public static final ColorModel Linear_sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with premultiplied alpha.
*/
public static final ColorModel Linear_sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
*/
public static final ColorModel Linear_sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with no alpha.
*/
public static final ColorModel sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with premultiplied alpha.
*/
public static final ColorModel sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with unpremultiplied alpha.
*/
public static final ColorModel sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
* based on premult flag.
* @param premult True if the ColorModel should have premultiplied alpha.
* @return a ColorMdoel with Linear sRGB colorSpace and
* the alpha channel set in accordance with
* premult
*/
public static ColorModel makeLinear_sRGBCM(boolean premult) {
return premult ? Linear_sRGB_Pre : Linear_sRGB_Unpre;
}
/**
* Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
* @param width The desired width of the BufferedImage
* @param height The desired height of the BufferedImage
* @param premult The desired state of alpha premultiplied
* @return The requested BufferedImage.
*/
public static BufferedImage makeLinearBufferedImage(int width,
int height,
boolean premult) {
ColorModel cm = makeLinear_sRGBCM(premult);
WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
return new BufferedImage(cm, wr, premult, null);
}
/**
* This method will return a CacheableRed that has it's data in
* the linear sRGB colorspace. If src is already in
* linear sRGB then this method does nothing and returns src.
* Otherwise it creates a transform that will convert
* src's output to linear sRGB and returns that CacheableRed.
*
* @param src The image to convert to linear sRGB.
* @return An equivilant image to src who's data is in
* linear sRGB.
*/
public static CachableRed convertToLsRGB(CachableRed src) {
ColorModel cm = src.getColorModel();
ColorSpace cs = cm.getColorSpace();
if (cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
return src;
return new Any2LsRGBRed(src);
}
/**
* This method will return a CacheableRed that has it's data in
* the sRGB colorspace. If src is already in
* sRGB then this method does nothing and returns src.
* Otherwise it creates a transform that will convert
* src's output to sRGB and returns that CacheableRed.
*
* @param src The image to convert to sRGB.
* @return An equivilant image to src who's data is in sRGB.
*/
public static CachableRed convertTosRGB(CachableRed src) {
ColorModel cm = src.getColorModel();
ColorSpace cs = cm.getColorSpace();
if (cs == ColorSpace.getInstance(ColorSpace.CS_sRGB))
return src;
return new Any2sRGBRed(src);
}
/**
* Convertes any RenderedImage to a CacheableRed.
* If ri is already a CacheableRed it casts it down and
* returns it.
*
* In cases where ri is not already a CacheableRed it
* wraps ri with a helper class. The wrapped
* CacheableRed "Pretends" that it has no sources since it has no
* way of inteligently handling the dependency/dirty region calls
* if it exposed the source.
* @param ri The RenderedImage to convert.
* @return a CacheableRed that contains the same data as ri.
*/
public static CachableRed wrap(RenderedImage ri) {
if (ri instanceof CachableRed)
return (CachableRed) ri;
if (ri instanceof BufferedImage)
return new BufferedImageCachableRed((BufferedImage)ri);
return new RenderedImageCachableRed(ri);
}
/**
* An internal optimized version of copyData designed to work on
* Integer packed data with a SinglePixelPackedSampleModel. Only
* the region of overlap between src and dst is copied.
*
* Calls to this should be preflighted with is_INT_PACK_Data
* on both src and dest (requireAlpha can be false).
*
* @param src The source of the data
* @param dst The destination for the data.
*/
public static void copyData_INT_PACK(Raster src, WritableRaster dst) {
// System.out.println("Fast copyData");
int x0 = dst.getMinX();
if (x0 < src.getMinX()) x0 = src.getMinX();
int y0 = dst.getMinY();
if (y0 < src.getMinY()) y0 = src.getMinY();
int x1 = dst.getMinX()+dst.getWidth()-1;
if (x1 > 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 height = y1-y0+1;
SinglePixelPackedSampleModel srcSPPSM;
srcSPPSM = (SinglePixelPackedSampleModel)src.getSampleModel();
final int srcScanStride = srcSPPSM.getScanlineStride();
DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
final int [] srcPixels = srcDB.getBankData()[0];
final int srcBase =
(srcDB.getOffset() +
srcSPPSM.getOffset(x0-src.getSampleModelTranslateX(),
y0-src.getSampleModelTranslateY()));
SinglePixelPackedSampleModel dstSPPSM;
dstSPPSM = (SinglePixelPackedSampleModel)dst.getSampleModel();
final int dstScanStride = dstSPPSM.getScanlineStride();
DataBufferInt dstDB = (DataBufferInt)dst.getDataBuffer();
final int [] dstPixels = dstDB.getBankData()[0];
final int dstBase =
(dstDB.getOffset() +
dstSPPSM.getOffset(x0-dst.getSampleModelTranslateX(),
y0-dst.getSampleModelTranslateY()));
if ((srcScanStride == dstScanStride) &&
(srcScanStride == width)) {
// System.out.println("VERY Fast copyData");
System.arraycopy(srcPixels, srcBase, dstPixels, dstBase,
width*height);
} else if (width > 128) {
int srcSP = srcBase;
int dstSP = dstBase;
for (int y=0; y 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;
}
}