有4位调色板奇怪的BufferedImage行为(Strange BufferedImage beh

2019-10-20 03:37发布

[见相关]

下面的代码打开一个微小的PNG图像,具有4位的调色板和透明度(TRNS块),并打印的像素(1,1)和(1,2)的值。 然后,它把从自动型图像以TYPE_4BYTE_ABGR和打印相同的像素值。

  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);
  }

结果我得到的是

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)

(当从JAI读取器被选中时,TYPE_BYTE_INDEXED选择代替,但像素值是相同的)。

我有两个问题在这里:

  1. 据文档 ,TYPE_BYTE_BINARY“表示不透明的字节填充1,2,或4位图像的图像有一个IndexColorModel没有阿尔法”。 这似乎在的结果,其示出了(正确地)为两个像素的α值矛盾。

  2. 原始结果(128,226,95,177)是正确的(一个可以与任何图像浏览器验证,或更好地与http://entropymine.com/jason/tweakpng/ )。 为什么要传递给TYPE_4BYTE_ABGR介绍本(小)的错误?

图像(4x3的,右半部分是完全透明的)是在这里: https://dl.dropboxusercontent.com/u/1608708/tech/04ptx.png

我的Java是

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)

Answer 1:

我可以试着回答第1项; 该文档是有点unprecise,我认为其目的是说,图像具有IndexColorModel的, 没有离散的alpha通道。 即:有只是在彩色地图索引的单信道。 这并不矛盾的事实,在IndexColorModel中颜色本身可以是(半)透明的。 这种解释与我的经验适合,当然,我没有写API或文档... ;-)

第2项看起来有点怪。 该误差很小+/- 1,所以它可能在实践中(不可见的大多数人眼里)没什么大不了的。 完整的猜测,但我猜有某种优化的循环中被使用,是牺牲了一些精度速度。 你是否尝试过使用setRGB()/getRGB()看看是否能给出不同的结果?



Answer 2:

我会haraldK在1点一致。

对于点2.通过BufferedImage的源代码的简单挖表示TYPE_4BYTE_ABGR使用ICC配置文件和色彩空间,所以这是可能被引入的差的位置。

回答haraldK的评论对这个问题, TYPE_INT_ARGB只是使用RGB色彩模式,所以我认为这就是为什么没有错误存在。

这两个相关案例来自BufferedImage的:

    case TYPE_INT_ARGB:
        {
            colorModel = ColorModel.getRGBdefault();

            raster = colorModel.createCompatibleWritableRaster(width,
                                                               height);
        }
    break;

    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;

和从在ColorSpace中getInstance方法:

    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;


文章来源: Strange BufferedImage behaviour with 4bits palette