为什么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] 

@ redwyre的评论是正确的(但我自己没有足够的声誉来评论)。 因此,我将向您介绍Vincent Povirk对使用GDI +绘制PixelFormat32bppPARGB图像的评论, 使用传统公式而不是预乘公式 :

前景图像的格式无关紧要(假设它具有alpha),因为您将其设置为Gdiplus :: Color。 颜色值定义为非预乘,因此gdiplus在清除前景图像时将组件乘以alpha值。 另一种选择是Color值具有不同的含义,具体取决于渲染目标的格式,这种方式就是疯狂。

该post中的示例直接使用Gdiplus,但是,System.Drawing.Graphics也是如此,您可以在.NET源代码中看到。

您看到的不同值与从颜色通道值到预乘值的往返和使用8位算术返回直接相关。 (例如,从你的上一个例子中,alpha = 32和B = 90:90 * 32/255 = 11.2+截断为11然后返回11 * 255/32 = 87.6+截断为87.)