问题
[See related]
The following code opens a tiny PNG image, with a 4-bits palette and transparency (TRNS chunk) and prints the value of the pixels (1,1) and (1,2). Then it converts the image from the automatic type to TYPE_4BYTE_ABGR and prints the same pixels values.
public static void images() throws IOException {
File png = new File("c:\\temp\\04ptx.png");
BufferedImage bi1 = ImageIO.read(png);
System.out.printf("%s is TYPE_BYTE_BINARY? %s (%d)\n",png,
String.valueOf(BufferedImage.TYPE_BYTE_BINARY==bi1.getType()),
bi1.getType());
int p1i1 = bi1.getRGB(1, 1);
int p2i1 = bi1.getRGB(2, 1);
System.out.printf("im1: p1=%08x %s p2=%08x %s\n",
p1i1,formatARGB(p1i1),p2i1,formatARGB(p2i1));
BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
bi2.getGraphics().drawImage(bi1, 0, 0, null);
int p1i2 = bi2.getRGB(1, 1);
int p2i2 = bi2.getRGB(2, 1);
System.out.printf("im2: p1=%08x %s p2=%08x %s\n",
p1i2,formatARGB(p1i2),p2i2,formatARGB(p2i2));
}
public static String formatARGB(int v) {
return String.format("(%d,%d,%d,%d)",
(v>>24)&0xFF,(v>>16)&0xFF,(v>>8)&0xFF,v&0xFF);
}
The result I get is
c:\temp\04ptx.png is TYPE_BYTE_BINARY? true (12)
im1: p1=80e25fb1 (128,226,95,177) p2=00000000 (0,0,0,0)
im2: p1=80e160b1 (128,225,96,177) p2=00000000 (0,0,0,0)
(When the reader from JAI gets selected, the TYPE_BYTE_INDEXED is chosen instead, but the pixel values are the same).
I have two questions here:
According to docs, TYPE_BYTE_BINARY "represents an opaque byte-packed 1, 2, or 4 bit image. The image has an IndexColorModel without alpha". This seems in contradiction with the results, which shows (correctly) the alpha value for both pixels.
The original result (128,226,95,177) is correct (one can verify with any image viewer, or, better, with http://entropymine.com/jason/tweakpng/). Why passing to TYPE_4BYTE_ABGR introduces this (small) error?
The image (4x3, right half is fully transparent) is here: https://dl.dropboxusercontent.com/u/1608708/tech/04ptx.png
My Java is
java version "1.7.0_17"
Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
Java HotSpot(TM) Client VM (build 23.7-b01, mixed mode, sharing)
回答1:
I can try to answer item 1; The docs is a little unprecise, and I think the intention is to say that the image has IndexColorModel and no discrete alpha channel. I.e.: There's just a single channel with indices in the color map. That is not in contradiction to the fact that the colors in the IndexColorModel themselves may be (semi-) transparent. This explanation fits with my experience, but of course, I didn't write the API or the docs... ;-)
Item 2 looks a little strange. The error is very small +/- 1, so it's probably no big deal in practice (invisible to most peoples eyes). Complete speculation, but I would guess that there's some kind of optimized loops being used, that sacrifices some accuracy for speed. Have you tried using setRGB()/getRGB()
to see if that gives different results?
回答2:
I would agree with haraldK on point 1.
For point 2. A brief dig through the source code of BufferedImage indicates that TYPE_4BYTE_ABGR
uses an ICC profile and colour space, so that is probably where the difference is introduced.
Answering haraldK's comment on the question, TYPE_INT_ARGB
just uses a RGB colour model, so I'd assume that is why there is no error there.
The two relevant cases from BufferedImage:
case TYPE_INT_ARGB:
{
colorModel = ColorModel.getRGBdefault();
raster = colorModel.createCompatibleWritableRaster(width,
height);
}
break;
and
case TYPE_4BYTE_ABGR:
{
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8, 8};
int[] bOffs = {3, 2, 1, 0};
colorModel = new ComponentColorModel(cs, nBits, true, false,
Transparency.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
width, height,
width*4, 4,
bOffs, null);
}
break;
and from the getInstance method in ColorSpace:
case CS_sRGB:
synchronized(ColorSpace.class) {
if (sRGBspace == null) {
ICC_Profile theProfile = ICC_Profile.getInstance (CS_sRGB);
sRGBspace = new ICC_ColorSpace (theProfile);
}
theColorSpace = sRGBspace;
}
break;
来源:https://stackoverflow.com/questions/23707736/strange-bufferedimage-behaviour-with-4bits-palette