-
Bug
-
Resolution: Fixed
-
P3
-
1.4.1
-
None
-
beta
-
sparc
-
solaris_7
When doing alpha composite in a buffered image with AlphaComposite.SRC_OVER
rule on a 8 bit display, the output of the pixel values are sometimes
unexpected.
Here is a test program:
import java.awt.*;
import java.awt.image.*;
public class SrcOverTest {
public static final BufferedImage bi;
public static final Graphics2D g2;
protected static int colorDepth, maxError;
public static final Color colors[] = { new Color(255, 0, 255),
Color.black, Color.red, Color.pink, Color.orange, Color.yellow,
Color.green, Color.magenta, Color.cyan, Color.blue};
static {
GraphicsEnvironment lge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc =
lge.getDefaultScreenDevice().getDefaultConfiguration();
bi = gc.createCompatibleImage(200, 200);
g2 = bi.createGraphics();
g2.setColor(new Color(0, 255, 0));
g2.fill3DRect(1, 0, 100, 50, true);
}
public static Color accountForColorConversion(Color c) {
BufferedImage bi2 = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration().createCompatibleImage(1,1);
int x = 0;
int y = 0;
// Set a pixel with the input color
int rgb = c.getRGB();
bi2.setRGB(x, y, rgb);
// Read the pixel we just set, BufferedImage should take care
// of the color conversion
rgb = bi2.getRGB(x,y);
// Return the converted color
return new Color(rgb);
}
public static Color calcSrcOver(Color cb, Color c, float alpha, ColorModel colorModel) {
boolean hasAlpha = colorModel.hasAlpha();
float[] rgbaSrc = c.getRGBComponents(null);
float[] rgbaDst = cb.getRGBComponents(null);
float alphasource = rgbaSrc[3] * alpha;
float alphadest = rgbaDst[3];
float r = rgbaSrc[0]*alphasource + rgbaDst[0]*alphadest*(1-alphasource);
float g = rgbaSrc[1]*alphasource + rgbaDst[1]*alphadest*(1-alphasource);
float b = rgbaSrc[2]*alphasource + rgbaDst[2]*alphadest*(1-alphasource);
float a = alphasource + alphadest*(1-alphasource);
if (hasAlpha) {
return new Color(r, g, b, a);
} else if (a != 0.0f) {
return new Color(r / a, g / a, b / a, 1.0f);
} else {
return new Color(0.0f, 0.0f, 0.0f, 1.0f);
}
}
public static void main(String[] args) {
float alphas[] = {0.0f, 0.5f, 1.0f};
for (int j = 0; j < alphas.length; j++) {
for (int i = 0; i < colors.length; i++) {
Color c_before = new Color(bi.getRGB(50, 25), true);
AlphaComposite composite =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphas[j]);
g2.setComposite(composite);
Color c = accountForColorConversion(colors[i]);
g2.setColor(c);
g2.fill3DRect(1, 0, 100, 50, true);
Color c_after = new Color(bi.getRGB(50, 25), true);
Color c_expected = calcSrcOver(c_before, c, alphas[j],
bi.getColorModel());
System.out.println("ColorModel has alpha: " + bi.getColorModel().hasAlpha());
System.out.println("alpha of the composite: " + composite.getAlpha());
System.out.println("Source Color: " + c + ", alpha: " + c.getAlpha());
System.out.println("Dest Color: " + c_before + ", alpha: " + c_before.getAlpha());
System.out.println("Returned color: "+ c_after +
", alpha: " + c_after.getAlpha());
System.out.println("Expected color: " + c_expected +
", alpha: " + c_expected.getAlpha());
System.out.println();
}
}
}
}
Attached is the output on 24 bit display and output on 8 bit display. It shows
that the all resulting colors on 24 bit display are consistent with expected
values. However, some resulting colors on 8 bit display are not within
expectation, especially when alpha of blending is not 1.0, for example:
ColorModel has alpha: false
alpha of the composite: 0.0
Source Color: java.awt.Color[r=255,g=0,b=255], alpha: 255
Dest Color: java.awt.Color[r=0,g=255,b=0], alpha: 255
Returned color: java.awt.Color[r=59,g=250,b=52], alpha: 255
Expected color: java.awt.Color[r=0,g=255,b=0], alpha: 255
...
ColorModel has alpha: false
alpha of the composite: 0.5
Source Color: java.awt.Color[r=0,g=0,b=0], alpha: 255
Dest Color: java.awt.Color[r=197,g=98,b=139], alpha: 255
Returned color: java.awt.Color[r=127,g=0,b=0], alpha: 255
Expected color: java.awt.Color[r=99,g=49,b=70], alpha: 255
It is acceptable that there might be some errors in
floating point calculation, but some returned values are way off.
For instance, in the first 8 bit output example, the alpha is 0, which means
the resulting color should be the same as the original destination color.
But the actual resulting color is totally unexpected.
rule on a 8 bit display, the output of the pixel values are sometimes
unexpected.
Here is a test program:
import java.awt.*;
import java.awt.image.*;
public class SrcOverTest {
public static final BufferedImage bi;
public static final Graphics2D g2;
protected static int colorDepth, maxError;
public static final Color colors[] = { new Color(255, 0, 255),
Color.black, Color.red, Color.pink, Color.orange, Color.yellow,
Color.green, Color.magenta, Color.cyan, Color.blue};
static {
GraphicsEnvironment lge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc =
lge.getDefaultScreenDevice().getDefaultConfiguration();
bi = gc.createCompatibleImage(200, 200);
g2 = bi.createGraphics();
g2.setColor(new Color(0, 255, 0));
g2.fill3DRect(1, 0, 100, 50, true);
}
public static Color accountForColorConversion(Color c) {
BufferedImage bi2 = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration().createCompatibleImage(1,1);
int x = 0;
int y = 0;
// Set a pixel with the input color
int rgb = c.getRGB();
bi2.setRGB(x, y, rgb);
// Read the pixel we just set, BufferedImage should take care
// of the color conversion
rgb = bi2.getRGB(x,y);
// Return the converted color
return new Color(rgb);
}
public static Color calcSrcOver(Color cb, Color c, float alpha, ColorModel colorModel) {
boolean hasAlpha = colorModel.hasAlpha();
float[] rgbaSrc = c.getRGBComponents(null);
float[] rgbaDst = cb.getRGBComponents(null);
float alphasource = rgbaSrc[3] * alpha;
float alphadest = rgbaDst[3];
float r = rgbaSrc[0]*alphasource + rgbaDst[0]*alphadest*(1-alphasource);
float g = rgbaSrc[1]*alphasource + rgbaDst[1]*alphadest*(1-alphasource);
float b = rgbaSrc[2]*alphasource + rgbaDst[2]*alphadest*(1-alphasource);
float a = alphasource + alphadest*(1-alphasource);
if (hasAlpha) {
return new Color(r, g, b, a);
} else if (a != 0.0f) {
return new Color(r / a, g / a, b / a, 1.0f);
} else {
return new Color(0.0f, 0.0f, 0.0f, 1.0f);
}
}
public static void main(String[] args) {
float alphas[] = {0.0f, 0.5f, 1.0f};
for (int j = 0; j < alphas.length; j++) {
for (int i = 0; i < colors.length; i++) {
Color c_before = new Color(bi.getRGB(50, 25), true);
AlphaComposite composite =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphas[j]);
g2.setComposite(composite);
Color c = accountForColorConversion(colors[i]);
g2.setColor(c);
g2.fill3DRect(1, 0, 100, 50, true);
Color c_after = new Color(bi.getRGB(50, 25), true);
Color c_expected = calcSrcOver(c_before, c, alphas[j],
bi.getColorModel());
System.out.println("ColorModel has alpha: " + bi.getColorModel().hasAlpha());
System.out.println("alpha of the composite: " + composite.getAlpha());
System.out.println("Source Color: " + c + ", alpha: " + c.getAlpha());
System.out.println("Dest Color: " + c_before + ", alpha: " + c_before.getAlpha());
System.out.println("Returned color: "+ c_after +
", alpha: " + c_after.getAlpha());
System.out.println("Expected color: " + c_expected +
", alpha: " + c_expected.getAlpha());
System.out.println();
}
}
}
}
Attached is the output on 24 bit display and output on 8 bit display. It shows
that the all resulting colors on 24 bit display are consistent with expected
values. However, some resulting colors on 8 bit display are not within
expectation, especially when alpha of blending is not 1.0, for example:
ColorModel has alpha: false
alpha of the composite: 0.0
Source Color: java.awt.Color[r=255,g=0,b=255], alpha: 255
Dest Color: java.awt.Color[r=0,g=255,b=0], alpha: 255
Returned color: java.awt.Color[r=59,g=250,b=52], alpha: 255
Expected color: java.awt.Color[r=0,g=255,b=0], alpha: 255
...
ColorModel has alpha: false
alpha of the composite: 0.5
Source Color: java.awt.Color[r=0,g=0,b=0], alpha: 255
Dest Color: java.awt.Color[r=197,g=98,b=139], alpha: 255
Returned color: java.awt.Color[r=127,g=0,b=0], alpha: 255
Expected color: java.awt.Color[r=99,g=49,b=70], alpha: 255
It is acceptable that there might be some errors in
floating point calculation, but some returned values are way off.
For instance, in the first 8 bit output example, the alpha is 0, which means
the resulting color should be the same as the original destination color.
But the actual resulting color is totally unexpected.