【发布时间】:2012-10-20 16:31:25
【问题描述】:
我在将一些代码从 Bitmap.GetPixel 更改为使用 LockBits 返回的直接像素缓冲区时遇到问题。与 GetPixel 相比,LockBits 返回的数据似乎确实给了我不同的颜色值。
这很不幸,因为这种更改确实会产生不同的颜色,这会破坏自动化单元测试。我有一个 29*30 像素的 png 文件,我将 Format32bppArgb 加载到位图中。这真的是LockBits和GetPixel返回的数据不同吗?我该如何解决这个问题?
这里有一些代码可以用加载的位图重现它
public unsafe static Bitmap Convert(Bitmap originalBitmap)
{
Bitmap converted = new Bitmap(originalBitmap);
Rectangle rect = new Rectangle(0, 0, converted.Width, converted.Height);
var locked = converted.LockBits(rect, ImageLockMode.ReadWrite, originalBitmap.PixelFormat);
byte* pData = (byte*)locked.Scan0;
// bytes per pixel
var bpp = ((int)converted.PixelFormat >> 11) & 31;
byte* r;
byte* g;
byte* b;
byte* a;
for (int y = 0; y < locked.Height; y++)
{
var row = pData + (y * locked.Stride);
for (int x = 0; x < locked.Width; x++)
{
a = row + x * bpp + 3;
r = row + x * bpp + 2;
g = row + x * bpp + 1;
b = row + x * bpp + 0;
var col = Color.FromArgb(*a, *r, *g, *b);
var origCol = originalBitmap.GetPixel(x, y);
if (origCol != col)
{
Debug.Print("Orig: {0} Pixel {1}", origCol, col);
}
}
}
converted.UnlockBits(locked);
return converted;
}
Orig: Color [A=128, R=128, G=128, B=255] Pixel Color [A=128, R=127, G=127, B=255]
Orig: Color [A=0, R=128, G=128, B=255] Pixel Color [A=0, R=0, G=0, B=0]
Orig: Color [A=45, R=128, G=128, B=255] Pixel Color [A=45, R=130, G=130, B=254]
ok -2 -2 +1
大部分时间,但似乎正在进行一些舍入和转换。我可以强制 LockBits 返回 GetPixel 返回的数据吗?
【问题讨论】:
-
PNG 不能包含颜色配置文件/伽马设置/其他吗?也许
GetPixel会根据颜色配置文件检索像素的颜色。显然原始 ARGB 值无法存储颜色配置文件,因此您会看到不同的结果。 -
您的 bpp 变量试图处理像素格式。但实际上不能工作,除非它是 32bpp 图像。至少在 LockBits() 调用中询问您需要的像素格式。 PArgb 将是一个问题。它也可以通过在原始图像上使用 LockBits() 来工作。但是代码已经没有任何意义了。
-
我确实在我的测试数据中发现了一些 24/32bpp 图像。是的,我拒绝其他一切。 bpp 变量提取代码实际上根本不起作用,因为它确实报告了错误的字节数。现在我有了一个支持格式的开关盒。