这个问题的示例代码在很大程度上是不言自明的,所以:
[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值。另一种选择是,根据渲染目标的格式,"颜色"值具有不同的含义,这种方式就是疯狂。
这篇文章中的示例直接使用Gdiplus,但是System.Drawing.Graphics也是如此,正如您在.NET源代码中看到的那样。
您看到的不同值与从颜色通道值到预乘值的往返直接相关,并使用8位算术返回。(例如,从上一个例子来看,alpha=32和B=90:90*32/255=11.2+截断到11,然后返回11*255/32=87.6+截断到87。)