2014-02-28 39 views
1

此問題的示例代碼在很大程度上是不言自明的,所以:爲什麼Image.Clear(x)之後的顏色不完全等於顏色x?

[Fact] 
private void Color_in_should_equal_color_out() 
{ 
    var bitmap = new Bitmap(128,128,PixelFormat.Format32bppArgb); 
    var color = Color.FromArgb(30,60,90,120);   
    using (var g = Graphics.FromImage(bitmap)) 
    { 
     g.Clear(color); 
    } 

    var result = bitmap.GetPixel(0,0); 

    Assert.Equal(color, result); 
} 

在這種情況下我會期待背景的顏色是相同的,以我清除它的顏色。相反,我得到這個:

Assert.Equal() Failure 

Expected: Color [A=30, R=60, G=90, B=120] 
Actual: Color [A=30, R=59, G=93, B=119] 

這怎麼可能?

一些通:

Color.FromArgb(0, 0, 0, 0); 
Color.FromArgb(255, 255, 255, 255); 

一些更多的例子是失敗的:

Expected: Color [A=32, R=64, G=96, B=128] 
Actual: Color [A=32, R=63, G=95, B=127] 

Expected: Color [A=128, R=192, G=32, B=16] 
Actual: Color [A=128, R=191, G=31, B=15] 

Expected: Color [A=32, R=192, G=127, B=90] 
Actual: Color [A=32, R=191, G=127, B=87] 
+0

PS:並不認爲這是重複的,我能找到的最接近的匹配是http://stackoverflow.com/questions/721324/using-toargb-followed-by-fromargb-does-not-result-in-the-original-顏色和http://stackoverflow.com/questions/2032398/why-does-color-isnamedcolor-not-work-when-i-create-a-color-using-color-fromargb – nathanchere

回答

1

@ redwyre的評論是正確的(但我沒有足夠的聲譽自己的評論)。所以,我將把你文森特Povirk的評論在Drawing PixelFormat32bppPARGB images with GDI+ uses conventional formula instead of premultiplied one

您的前景圖像不要緊的格式(因爲它有阿爾法),因爲你將它設置爲一個Gdiplus ::顏色。顏色值被定義爲非預乘,因此gdiplus在清除前景圖像時將其乘以alpha值。另一種方法是根據渲染目標的格式,顏色值具有不同的含義,這就是瘋狂。

在該職位的例子使用Gdiplus直接,不過呢,也是如此System.Drawing.Graphics,你可以看到在.NET源here

您看到的不同值與使用8位算法從彩色通道值到預乘值和返回值的往返運算直接相關。 (例如,從最後一個例子中,alpha = 32和B = 90:90 * 32/255 = 11.2+截斷爲11,然後返回11 * 255/32 = 87.6+截斷爲87.)

+0

我試過PixelFormat32bppPArgb和PixelFormat32bppArgb和他們產生了相同的結果(就像64位PArgb等那樣)。我不希望* both *預先計算後的alpha可以產生完全相同的舍入誤差,否則根據預先計算得到的alpha通道的前提是什麼? – nathanchere

+0

同樣使用上面的主要例子(用'[A = 30,R = 60,G = 90,B = 120]')G怎麼可能最終成爲93?對於突出顯示的90-> 87範例,它必須將11.2舍入爲零。對於90-> 93的例子,它只有在從零開始舍入10.5(甚至應該是94而不是93)時才起作用。這就是結果的不一致性,使我認爲「錯誤」是一種可能性。 – nathanchere

+0

@nathanchere - 90-> 93的例子也適用,因爲結果是四捨五入的。我說上面截斷了,因爲那個例子就是這種情況,但算術實際上是四捨五入的。 94和93之間的問題是計算機算術的標準,並不總是我們在學校學到的方式(例如.5向上舍入)。事實上,計算機的算術運算往往會向0逼近。實際上,同一架構上的不同指令可能會有所不同,例如通用寄存器中的常規指令與SIMD寄存器中的SIMD指令(如SSE)。 – davidbak