2014-10-26 90 views
0

我一直在ConvolveOp有一些问题,可以通过将我正在使用的BufferedImage的imageType设置为TYPE_INT_ARGB_PREsee related SO answer here)来修复。TYPE_INT_ARGB_PRE的影响

不幸的是我没有完全理解这个选择不同IMAGETYPE的所有影响,似乎我无法找到一条很好的参考,所以让我试一下:

其中绘图操作通过改变影响从TYPE_INT_ARGB到TYPE_INT_ARGB_PRE的BufferedImage的imageType?它只是BufferedImageOps?或者它会影响图像的Graphics对象上的任何绘制命令,或者如果将图像绘制到不同的Graphics对象上,则会影响图像的呈现方式?

+0

见http://en.wikipedia.org/wiki/Alpha_compositing。在大多数情况下,差异应该只是表现,而不是最终结果。 – haraldK 2014-10-28 11:46:57

回答

1

这基本上取决于绘画算法是否考虑到图像是否使用预乘alpha的信息。

正如在评论中已经指出的那样:结果在大多数情况下是相同的 - 至少对于基本的绘图操作来说:无论您是将“非预乘”图像绘制为预乘结果还是反之,不会影响结果,因为差异是在内部处理的。

特殊情况是BufferedImageOp s。 JavaDoc评论明确地说明了alpha通道是如何处理的,并且传入错误的图像会导致您链接的问题中描述的不良结果。

很难确定““他们决定以这种方式实施BufferedImageOp的原因。但是这里有一个(有些模糊的)陈述是:当对一个单一来源的像素进行操作(和组合),并且这些像素具有不同的alpha值时,alpha通道的处理可能会变得烦琐。这并不总是非常明显,应该与alpha通道发生

例如,假设你的像素的堆栈(在这里,在ARGB,与浮点值):

[1.00, 1.00, 0.00, 0.00] // 100% red, 100% alpha 
[0.00, 0.00, 0.00, 0.00] // black,  0% alpha 
[0.00, 0.00, 0.00, 0.00] // black,  0% alpha 

现在,你想要做的这些像素上的卷积(如问题,你链接到)。那么内核可能是

[0.33...] 
[0.33...], 
[0.33...] 

这意味着结果的中心像素应该仅仅是所有像素的“平均”(忽略边界 - 大致与ConvolveOp#EDGE_ZERO_FILL)。

卷积然后将平等对待所有渠道。对于非预乘图像,这将意味着,所得到的像素是暗红色低不透明度:

[0.33, 0.33, 0.00, 0.00] 

对于预乘图像,假定组件与它们的α值来multipled。在这种情况下,所得到的像素将完全红色,具有相同的不透明度:

[0.33, 1.00, 0.00, 0.00] 

在做数学这背后是乏味的。而事实上,过于繁琐的对我来说,做手工 - 所以这里有一个例子:

AlphaPremultiplied

和相应的代码

import java.awt.Color; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.image.BufferedImage; 
import java.awt.image.ConvolveOp; 
import java.awt.image.Kernel; 
import java.util.Locale; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class PremultipliedAlphaTest 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       createAndShowGUI(); 
      } 
     }); 
    }  

    private static void createAndShowGUI() 
    { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.getContentPane().add(new PremultipliedAlphaTestPanel()); 
     f.setSize(550,500); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 


class PremultipliedAlphaTestPanel extends JPanel 
{ 
    @Override 
    protected void paintComponent(Graphics gr) 
    { 
     super.paintComponent(gr); 
     Graphics2D g = (Graphics2D)gr; 
     g.setColor(Color.WHITE); 
     g.fillRect(0, 0, getWidth(), getHeight()); 

     BufferedImage imageS = createImage(BufferedImage.TYPE_INT_ARGB); 
     BufferedImage imageP = createImage(BufferedImage.TYPE_INT_ARGB_PRE); 

     Kernel kernel = new Kernel(1, 3, 
      new float[]{ 1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f }); 
     ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null); 
     BufferedImage resultS = op.filter(imageS, null); 
     BufferedImage resultP = op.filter(imageP, null); 

     g.setColor(Color.BLACK); 
     g.setFont(new Font("Monospaced", Font.PLAIN, 12)); 

     g.drawString("Straight:", 10, 40); 

     print(g, 2, 1, imageS.getRGB(0, 0)); 
     print(g, 2, 2, imageS.getRGB(0, 1)); 
     print(g, 2, 3, imageS.getRGB(0, 2)); 

     print(g, 7, 2, resultS.getRGB(0, 1)); 


     g.drawString("Premultiplied:", 10, 240); 

     print(g, 2, 5, imageP.getRGB(0, 0)); 
     print(g, 2, 6, imageP.getRGB(0, 1)); 
     print(g, 2, 7, imageP.getRGB(0, 2)); 

     print(g, 7, 6, resultP.getRGB(0, 1)); 

     g.scale(50, 50); 

     g.drawImage(imageS, 1, 1, null); 
     g.drawImage(resultS, 6, 1, null); 

     g.drawImage(imageP, 1, 5, null); 
     g.drawImage(resultP, 6, 5, null); 
    } 

    private static void print(Graphics2D g, int px, int py, int argb) 
    { 
     g.drawString(stringFor(argb), px*50+5, py*50+25); 
    } 


    private static String stringFor(int argb) 
    { 
     int a = (argb >> 24) & 0xFF; 
     int r = (argb >> 16) & 0xFF; 
     int g = (argb >> 8) & 0xFF; 
     int b = (argb  ) & 0xFF; 
     float fa = a/255.0f; 
     float fr = r/255.0f; 
     float fg = g/255.0f; 
     float fb = b/255.0f; 
     return String.format(Locale.ENGLISH, 
      "%4.2f %4.2f %4.2f %4.2f", fa, fr, fg, fb); 
    } 

    private static BufferedImage createImage(int type) 
    { 
     BufferedImage b = new BufferedImage(1,3, type); 
     Graphics2D g = b.createGraphics(); 
     g.setColor(new Color(1.0f,0.0f,0.0f,1.0f)); 
     g.fillRect(0, 0, 1, 1); 
     g.setColor(new Color(0.0f,0.0f,0.0f,0.0f)); 
     g.fillRect(0, 1, 1, 1); 
     g.setColor(new Color(0.0f,0.0f,0.0f,0.0f)); 
     g.fillRect(0, 2, 1, 1); 
     g.dispose(); 
     return b; 
    } 
}