本文介绍了BufferedImage.getGraphics()。drawImage()改变像素值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(这是对问题的跟进)

BufferedImage 从一种类型转换为另一种类型或制作副本的标准推荐方法是使用 getGraphics()。drawImage()( )。令我惊讶的是,我发现即使源图像和目标图像都属于同一类型,此过程也不会使像素值保持不变!如果存在透明度,则会出现此问题。

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.

单像素ARGB图像示例:

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

这给出: 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?

推荐答案

我终于明白了。尝试设置 graphics.setComposite(AlphaComposite.Src)。在我自己的库代码中,我这样做了,但我从来没有想过太多...

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

因为默认复合是 AlphaComposite.SrcOver ,你实际上半透明像素组合到完全透明的像素上,两者都是非预乘的alpha,所以这里有区别。使用 AlphaComposite.Src 你基本上只说源是重要的。

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.

另请注意,较低的alpha值意味着更透明。这意味着对于低alpha,RGB值具有较小的重要性,因为它们在编写时乘以alpha(即。 17/255 用于示例图像),因此差异在不透明的背景上构图时不会产生任何影响。

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. :-)

这是您的代码的更新版本,使用 AlphaComposite.Src ,输出没有差异:

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

输出:

im1: 11663322 (17,102,51,34) im2: 11663322 (17,102,51,34)

这篇关于BufferedImage.getGraphics()。drawImage()改变像素值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-21 23:07