-
Bug
-
Resolution: Fixed
-
P2
-
1.2.2
-
1.3
-
generic
-
solaris_7
-
Not verified
The included test program pops up six display windows. All display a
checkerboard image. Each window varies whether the image is represented
as monochrome or RGB, with or without alpha, and (if with alpha) whether the
alpha channel is premultiplied into the other channels.
All the windows but two display correctly. The incorrect windows are
those attempting to display Gray + Alpha, premultiplied or not. The symptoms
are horizontal stretching and alternation of values from the gray and alpha
channels, as well as incorrect partial updates (e.g. when a window is dragged
across).
With the introduction of support for PNG in Java2D and JAI, and JAI support
for FlashPIX and IIP, Gray + Alpha imagery will become more commonly used and
thus the probability of customers encountering this problem is increased.
import java.awt.*;
import java.awt.color.*;
import java.awt.geom.*;
import java.awt.image.*;
public class GrayAlpha extends Canvas {
BufferedImage bi;
AffineTransform identityTransform = new AffineTransform();
public GrayAlpha(int width, int height,
boolean hasAlpha, boolean isAlphaPremultiplied,
boolean useRGB) {
boolean isAlphaPremuliplied = true;
int bands = useRGB ? 3 : 1;
bands = hasAlpha ? bands + 1 : bands;
ColorSpace cs = useRGB ?
ColorSpace.getInstance(ColorSpace.CS_sRGB) :
ColorSpace.getInstance(ColorSpace.CS_GRAY);
int transparency = hasAlpha ?
Transparency.TRANSLUCENT : Transparency.OPAQUE;
int[] bits = new int[bands];
for (int i = 0; i < bands; i++) {
bits[i] = 8;
}
ColorModel cm = new ComponentColorModel(cs,
bits,
hasAlpha,
isAlphaPremultiplied,
transparency,
DataBuffer.TYPE_BYTE);
WritableRaster wr =
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
width, height, bands,
new Point(0, 0));
for (int b = 0; b < bands; b++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int s;
if (b != bands - 1 || !hasAlpha) {
// Gray band(s), fill with a checkerboard pattern
if (((x / 10) % 2) == ((y / 10) % 2)) {
s = 255;
} else {
s = 0;
}
if (isAlphaPremultiplied) {
int alpha = (x*255)/(width - 1);
s = (s*alpha)/255;
}
} else {
// Alpha band, increase opacity left to right
s = (x*255)/(width - 1);
}
wr.setSample(x, y, b, s);
}
}
}
this.bi = new BufferedImage(cm, wr, isAlphaPremultiplied, null);
}
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(), bi.getHeight());
}
public void paint(Graphics g) {
((Graphics2D)g).drawImage(bi, 0, 0, null);
}
public static void makeFrame(String title,
int x, int y, int width, int height,
boolean hasAlpha,
boolean isAlphaPremultiplied,
boolean useRGB) {
Frame f = new Frame(title);
f.add(new GrayAlpha(width, height,
hasAlpha, isAlphaPremultiplied, useRGB));
f.pack();
f.setLocation(x, y);
f.setVisible(true);
}
public static void main(String[] args) {
int width = 200;
int height = 200;
int x = 100;
int y = 100;
makeFrame("Gray w/o Alpha",
x, y, width, height,
false, false, false);
x += width + 20;
makeFrame("Gray (non-premultiplied)",
x, y, width, height,
true, false, false);
x += width + 20;
makeFrame("Gray (premultiplied)",
x, y, width, height,
true, true, false);
x = 100;
y += height + 50;
makeFrame("RGB w/o Alpha",
x, y, width, height,
false, false, true);
x += width + 20;
makeFrame("RGBA (non-premultiplied)",
x, y, width, height,
true, false, true);
x += width + 20;
makeFrame("RGBA (premultiplied)",
x, y, width, height,
true, true, true);
}
}
checkerboard image. Each window varies whether the image is represented
as monochrome or RGB, with or without alpha, and (if with alpha) whether the
alpha channel is premultiplied into the other channels.
All the windows but two display correctly. The incorrect windows are
those attempting to display Gray + Alpha, premultiplied or not. The symptoms
are horizontal stretching and alternation of values from the gray and alpha
channels, as well as incorrect partial updates (e.g. when a window is dragged
across).
With the introduction of support for PNG in Java2D and JAI, and JAI support
for FlashPIX and IIP, Gray + Alpha imagery will become more commonly used and
thus the probability of customers encountering this problem is increased.
import java.awt.*;
import java.awt.color.*;
import java.awt.geom.*;
import java.awt.image.*;
public class GrayAlpha extends Canvas {
BufferedImage bi;
AffineTransform identityTransform = new AffineTransform();
public GrayAlpha(int width, int height,
boolean hasAlpha, boolean isAlphaPremultiplied,
boolean useRGB) {
boolean isAlphaPremuliplied = true;
int bands = useRGB ? 3 : 1;
bands = hasAlpha ? bands + 1 : bands;
ColorSpace cs = useRGB ?
ColorSpace.getInstance(ColorSpace.CS_sRGB) :
ColorSpace.getInstance(ColorSpace.CS_GRAY);
int transparency = hasAlpha ?
Transparency.TRANSLUCENT : Transparency.OPAQUE;
int[] bits = new int[bands];
for (int i = 0; i < bands; i++) {
bits[i] = 8;
}
ColorModel cm = new ComponentColorModel(cs,
bits,
hasAlpha,
isAlphaPremultiplied,
transparency,
DataBuffer.TYPE_BYTE);
WritableRaster wr =
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
width, height, bands,
new Point(0, 0));
for (int b = 0; b < bands; b++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int s;
if (b != bands - 1 || !hasAlpha) {
// Gray band(s), fill with a checkerboard pattern
if (((x / 10) % 2) == ((y / 10) % 2)) {
s = 255;
} else {
s = 0;
}
if (isAlphaPremultiplied) {
int alpha = (x*255)/(width - 1);
s = (s*alpha)/255;
}
} else {
// Alpha band, increase opacity left to right
s = (x*255)/(width - 1);
}
wr.setSample(x, y, b, s);
}
}
}
this.bi = new BufferedImage(cm, wr, isAlphaPremultiplied, null);
}
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(), bi.getHeight());
}
public void paint(Graphics g) {
((Graphics2D)g).drawImage(bi, 0, 0, null);
}
public static void makeFrame(String title,
int x, int y, int width, int height,
boolean hasAlpha,
boolean isAlphaPremultiplied,
boolean useRGB) {
Frame f = new Frame(title);
f.add(new GrayAlpha(width, height,
hasAlpha, isAlphaPremultiplied, useRGB));
f.pack();
f.setLocation(x, y);
f.setVisible(true);
}
public static void main(String[] args) {
int width = 200;
int height = 200;
int x = 100;
int y = 100;
makeFrame("Gray w/o Alpha",
x, y, width, height,
false, false, false);
x += width + 20;
makeFrame("Gray (non-premultiplied)",
x, y, width, height,
true, false, false);
x += width + 20;
makeFrame("Gray (premultiplied)",
x, y, width, height,
true, true, false);
x = 100;
y += height + 50;
makeFrame("RGB w/o Alpha",
x, y, width, height,
false, false, true);
x += width + 20;
makeFrame("RGBA (non-premultiplied)",
x, y, width, height,
true, false, true);
x += width + 20;
makeFrame("RGBA (premultiplied)",
x, y, width, height,
true, true, true);
}
}