In C#, .NET 2.0, Windows Forms, Visual Studio Express 2010, I'm saving an image made of the same color:
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
Brush brush = new SolidBrush(color);
graphics.FillRectangle(brush, 0, 0, width, height);
brush.Dispose();
}
bitmap.Save("test.png");
bitmap.Save("test.bmp");
If I'm using, for example
Color [A=153, R=193, G=204, B=17] or #C1CC11
after I'm saving the image and open it in an external viewer such as Paint.NET, IrfanView, XNView, etc. I am told that the color of the image is actually:
Color [A=153, R=193, G=203, B=16] or #C1CB10
so it's a similar color, but not the same!
I tried with both PNG and BMP saving.
When transparency (alpha) is involved, .NET saves a different color! When the alpha is 255 (no transparency), it saves the corrent color.
Thank you, Joe and Hans Passant for your comments.
Yes, as Joe said, the problem is on the line:
graphics.FillRectangle(brush, 0, 0, width, height);
Here GDI+ modifies the color with a similar color, but not the exact one.
It seems that the solution is to write the color values directly in the pixels, using Bitmap.LockBits and Marshal.Copy:
Bitmap bitmap = new Bitmap(this.currentSampleWidth, this.currentSampleHeight, PixelFormat.Format32bppArgb);
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap (32 bits per pixel)
int pixelsCount = bitmap.Width * bitmap.Height;
int[] argbValues = new int[pixelsCount];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, argbValues, 0, pixelsCount);
// Set the color value for each pixel.
for (int counter = 0; counter < argbValues.Length; counter++)
argbValues[counter] = color.ToArgb();
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(argbValues, 0, ptr, pixelsCount);
// Unlock the bits.
bitmap.UnlockBits(bmpData);
return bitmap;