2014-10-26 88 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; 
    } 
}