Strange BufferedImage behaviour with 4bits palette

為{幸葍}努か 提交于 2019-12-14 02:33:12

问题


[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:

  1. 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.

  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!