(This is a followup to a previous question)
The standard recommended way of transforming a BufferedImage from one type to another, or to make a copy, is to use getGraphics().drawImage() (example). To my surprise, I've found that this procedure does not leave the pixel value unaltered, even even when both the source and target images are both of the same type! The issue shows up when there is some transparency.
Example with a single pixel ARGB image:
public static void imagesTestBiIssue() throws IOException {
//it also happens with TYPE_INT_ARGB
BufferedImage bi1 = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
// rather arbitrary. low values of alpha tend to give more difference
int argb = 0x11663322;
bi1.setRGB(0, 0, argb);
int p1 = bi1.getRGB(0, 0);
BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(),
bi1.getType());
bi2.getGraphics().drawImage(bi1, 0, 0, null);
int p2 = bi2.getRGB(0, 0);
System.out.printf("im1: %08x %s ", p1, formatARGB(p1));
System.out.printf("im2: %08x %s %s\n", p2,
formatARGB(p2), (p1 == p2 ? "" : "DIF"));
}
public static String formatARGB(int v) {
return String.format("(%d,%d,%d,%d)",
(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
}
This gives: im1: 11663322 (17,102,51,34) im2: 11692d1e (17,105,45,30) DIF
There seems to be some colour conversion somewhere, I cannot imagine why, given that the target and source are of the same type. Is this expected (or acceptable) behaviour?
I finally got it. Try setting graphics.setComposite(AlphaComposite.Src). In my own library code I do that, but I have never given it much thought...
Because the default composite is AlphaComposite.SrcOver, you're actually composing semi-transparent pixels onto completely transparent pixels, both with non-premultiplied alpha, so there is a difference here. Using AlphaComposite.Src you basically say that only the source matters.
Also note that lower alpha values means more transparent. This means that for low alpha, the RGB values has less significance, as they are multiplied by alpha when composing (ie. 17/255 for your example image), thus the diff will not make a difference when composed onto an opaque background.
So I'd say: Somewhat unexpected? Yes. Acceptable? Probably, yes. :-)
Here's an updated version of your code, using AlphaComposite.Src, and the output with no diff:
public static void main(String[] args) {
//it also happens with TYPE_INT_ARGB
BufferedImage bi1 = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
// rather arbitrary. low values of alpha tend to give more difference
int argb = 0x11663322;
bi1.setRGB(0, 0, argb);
int p1 = bi1.getRGB(0, 0);
BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(),
bi1.getType());
Graphics2D graphics = bi2.createGraphics();
try {
graphics.setComposite(AlphaComposite.Src);
graphics.drawImage(bi1, 0, 0, null);
}
finally {
graphics.dispose();
}
int p2 = bi2.getRGB(0, 0);
System.out.printf("im1: %08x %s ", p1, formatARGB(p1));
System.out.printf("im2: %08x %s %s\n", p2,
formatARGB(p2), (p1 == p2 ? "" : "DIF"));
}
public static String formatARGB(int v) {
return String.format("(%d,%d,%d,%d)",
(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
}
Output:
im1: 11663322 (17,102,51,34) im2: 11663322 (17,102,51,34)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With