Why does the color after Image.Clear(x) not exactly equal the color x?

China☆狼群 提交于 2019-12-23 03:50:35

问题


The sample code for this issue is largely self-explanatory, so:

[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);
}

In this instance I would expect the color of the background to be identical to the color I cleared it to. Instead I get this:

Assert.Equal() Failure 

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

How is this even possible?

Some pass:

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

Some more examples that fail:

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]

回答1:


@redwyre's comment is correct (but I don't have sufficient reputation myself to comment). So I'll refer you to Vincent Povirk's comment at Drawing PixelFormat32bppPARGB images with GDI+ uses conventional formula instead of premultiplied one:

The format of your foreground image doesn't matter (given that it has alpha) because you're setting it to a Gdiplus::Color. Color values are defined as non-premultiplied, so gdiplus multiplies the components by the alpha value when it clears the foreground image. The alternative would be for Color values to have different meaning depending on the format of the render target, and that way lies madness.

The example in that post uses Gdiplus directly, but then, so does System.Drawing.Graphics, as you can see here in the .NET sources.

The different values you see are directly related to round-tripping from color channel value to premultiplied value and back using 8-bit arithmetic. (E.g., from your last example, alpha=32 and B=90: 90*32/255 = 11.2+ truncates to 11 then back 11*255/32 = 87.6+ truncates to 87.)



来源:https://stackoverflow.com/questions/22086404/why-does-the-color-after-image-clearx-not-exactly-equal-the-color-x

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!