(Bitmap)图像的行为与新Bitmap(image)不同

本文关键字:Bitmap 不同 image 图像 | 更新日期: 2023-09-27 18:14:01

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

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

如果你看一下retrievedColor,你会发现它和Color.FromArgb(13, 19, 19, 19)是一样的。因此,差异将是绿色部分从20变为19。

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

更新

似乎是更深层次的嵌套问题。通过将Bitmap构造函数替换为图像变量的简单转换,问题就消失了。这也许能解决问题,但不能解释问题。此外,我甚至可以在油漆中重现这个问题。Net通过以下程序:

  • 开放漆。创建一个新图像(大小无关)
  • 选择所有( Ctrl + )
  • 删除选区(Del)
  • 打开颜色对话框(F8)
  • 输入上述RGB值(19,20,19),并在底部输入透明度(13)。
  • 选择填充工具(F)
  • 为空图像填充颜色
  • 选择颜色选择工具(K)
  • 点击新图像的某个位置,观察颜色对话框

所以这似乎是一个更深层次的问题,不是由位图或图像类引起的,而是由一些更深层的功能如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);
                        }
                    }
                }
            }
        }
    }

请不要让它完全自己运行,因为它会花很长时间来完成,而且它也会发现很多差异。但是你可以看到,如果你设置透明度(设置为1或10),那么你会看到RGB值使用它作为某种位深。

因此,如果您从使用低透明度值的现有位图创建新的位图,则会出现问题。真正的根本原因似乎在GDI,内核或这个区域的某个地方,不能从。net解决。

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

(Bitmap)图像的行为与新Bitmap(image)不同

我检查了PNG文件保存与您的代码使用油漆。. NET和像素颜色完全为unusableColor
如果你改变你的阅读代码:

using (Bitmap bitmap = (Bitmap)Image.FromFile(tempFile))
{
    retrievedColor = bitmap.GetPixel(0, 0);
}

一切作品

你可以使用克隆方法:

    using (var image = Image.FromFile(tempFile))
    {
        using (var bitmap = image.Clone() as Bitmap)
        {
            retrievedColor = bitmap.GetPixel(0, 0);
        }
    }

问题是在'new Bitmap(image)'中,因为它创建了新的实例。如果您查看bitmap的构造函数,它会创建新的透明图像并绘制源图像。图形对象具有平滑模式属性,用于绘制质量。默认为无抗锯齿。

下面是Bitmap的构造函数:

Graphics graphics = null;
try
{
    graphics = Graphics.FromImage(this);
    graphics.Clear(Color.Transparent);
    graphics.DrawImage(original, 0, 0, width, height);
}
finally
{
    if (graphics != null)
    {
        graphics.Dispose();
    }
}

所以如果你只是从文件中加载图像,或者克隆,位图数据是一样的