I have an issue while changing some code from Bitmap.GetPixel to using a direct pixel buffer returned by LockBits. It seems that the returned data by LockBits does give me different Color values compared to GetPixel.
That is unfortunate since this change does produce different colors which would break automated unit tests. I have a png file of 29*30 pixel which I do load a Format32bppArgb into a bitmap. Can this really be that the data returend by LockBits and GetPixel are different. How can I get around this?
Here is some code to repro it with a loaded bitmap
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
Most of the time but there seems to be some rounding and conversion to be going on. Can I force LockBits to return data as it would be returned by GetPixel?
To the best of my knowledge, PNGs can contain colour profiles and gamma correction information and whatever else which can affect the final colour of pixels vs. their raw representation.
Even if we disregard specific knowledge about PNGs, in general
GetPixelcan return different values than is expected.Bitmap.GetPixelis implemented thus:The definition of
SafeNativeMethods.Gdip.GdipBitmapGetPixelis:Which we learn from here is
Gdiplus::Bitmap::GetPixel. The documentation for that function says: