(位图)图像的行为与新的位图(图像)不同

Oli*_*ver 5 .net c# colors

这是我写的测试,目前将失败:

var unusableColor = Color.FromArgb(13, 19, 20, 19);
var retrievedColor = Color.Empty;
var tempFile = Path.GetTempFileName();

using (var bitmap = new Bitmap(1, 1))
{
    bitmap.SetPixel(0, 0, unusableColor);
    bitmap.Save(tempFile, ImageFormat.Png);
}

using (var image = Image.FromFile(tempFile))
// This will lead to the error
using (var bitmap = new Bitmap(image))
// But this will work
//using (var bitmap = (Bitmap)image)
{
    retrievedColor = bitmap.GetPixel(0, 0);
}

Assert.That(retrievedColor, Is.SameAs(unusableColor));
Run Code Online (Sandbox Code Playgroud)

如果你看看retrievedColor你会发现它将是相同的Color.FromArgb(13, 19, 19, 19).所以区别在于绿色部分从20变为19.

知道为什么会发生这种情况或者在什么情况下Bitmap的构造函数会改变一个像素?

更新

似乎是一个更深层次的嵌套问题.通过Bitmap图像变量的简单转换替换构造函数,问题就消失了.这可能解决了这个问题,但并没有解释它.通过以下过程,我甚至可以在Paint.Net中重现问题:

  • 打开Paint.Net并创建一个新图像(大小无关紧要)
  • 全选(Ctrl+ A)
  • 删除选择(Del)
  • 打开颜色对话框(F8)
  • 输入RGB(19,20,19)的上述值,透明度(13)的底部.
  • 选择填充工具(F)
  • 将颜色填充到空图像中
  • 选择颜色选择工具(K)
  • 单击某处新鲜图像并观看颜色对话框

所以它似乎可能是一个更深层次的问题,不是由Bitmap或Image类引起的,而是可能是由一些更深层次的功能,如GDI +或类似的东西.

更新2

我刚刚写了一个新测试来找出所有受影响的颜色:

for (int a = 0; a < 256; a++)
{
    for (int r = 0; r < 256; r++)
    {
        for (int g = 0; g < 256; g++)
        {
            for (int b = 0; b < 256; b++)
            {
                using (var bitmap = new Bitmap(1, 1))
                {
                    var desiredColor = Color.FromArgb(a, r, g, b);
                    bitmap.SetPixel(0, 0, desiredColor);

                    // This will fail in a lot of colors with a low alpha channel value
                    using (var copiedBitmap = new Bitmap(bitmap))
                    // This will work, cause the information is entirely copied.
                    //using (var copiedBitmap = (Bitmap)bitmap.Clone())
                    {
                        var retrievedColor = copiedBitmap.GetPixel(0, 0);

                        if (desiredColor != retrievedColor)
                        {
                            Debug.Print(desiredColor + " != " + retrievedColor);
                        }
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

请不要让它完全自行运行,因为它需要一段时间才能完成,它也会发现一些差异.但是你可以看到,如果你玩透明度(设置为1或10),那么你会看到RGB值使用它作为某种位深度.

因此,如果您从使用低透明度值的现有位图创建新位图,则会出现此问题.真正的根本原因似乎远远落后于GDI,内核或该领域的某个地方,并且无法从.Net解决.

只需注意,如果颜色的透明度值较低,则可以通过调用位图构造函数来更改颜色.如果你真的需要原始颜色在第二个实例中保持活着而不是使用(Bitmap)myBitmap.Clone()或者如果你从磁盘加载它使用(Bitmap)Image.FromFile(filename)原因Image只是一个抽象类,它通常会通过Bitmap类实例化.

Mar*_*rco 8

我使用Paint.NET检查了使用您的代码保存的PNG文件,并且像素颜色正是如此unusableColor.
如果您更改您的阅读代码:

using (Bitmap bitmap = (Bitmap)Image.FromFile(tempFile))
{
    retrievedColor = bitmap.GetPixel(0, 0);
}
Run Code Online (Sandbox Code Playgroud)

一切正常

  • 同意.该缺陷位于Bitmap(Image)构造函数中,它使用Graphics.DrawImage()来制作副本.DrawImage()制作快捷方式,它是为人眼设计的. (4认同)