在Windows窗体中保存带有alpha通道的单色位图会保存不同的(错误的)颜色
本文关键字:保存 错误 颜色 位图 窗体 alpha Windows 通道 单色 | 更新日期: 2023-09-27 18:18:03
在c#, .NET 2.0, Windows Forms, Visual Studio Express 2010中,我保存了一个相同颜色的图像:
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");
如果我使用,例如
Color [A=153, R=193, G=204, B=17] or #C1CC11
保存图像后,在外部查看器(如Paint)中打开它。. NET, IrfanView, XNView等。我被告知图像的颜色实际上是:
Color [A=153, R=193, G=203, B=16] or #C1CB10
所以它是相似的颜色,但不一样!
我尝试了PNG和BMP保存。
当涉及到透明度(alpha)时,.NET保存不同的颜色!当alpha值为255(无透明度)时,它保存当前颜色
感谢Joe和Hans Passant的评论。
是的,正如Joe所说,问题就在这条线上:
graphics.FillRectangle(brush, 0, 0, width, height);
这里GDI+用相似的颜色修改颜色,但不是完全相同的颜色。
似乎解决方案是直接在像素中写入颜色值,使用位图。锁位和元帅。复制:
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;
只是想添加一点。根据我的经验,最后一个代码片段可能会抛出运行时错误。这是因为位图中的argb值数组是这样存储的:[a1, b1, g1, r1, a2, b2, g2, r2, a3,…]等等,其中a, r, g, b都是整数。您应该在图像上运行一些测试用例,以查看数组中a、r、g、b值的确切位置。位图不一定保证这种顺序性(是的,即使在。net中)。
稍微重写一下:
byte[] rgbValues1 = new byte[4];
System.Drawing.Imaging.BitmapData bpData =
bm.LockBits(new Rectangle(0,0,bm.Width,bm.Height),System.Drawing.Imaging.ImageLockMode.ReadWrite,
bm.PixelFormat);
int thisPixel = ptStart.X * 4 + ptStart.Y * bpData.Stride;
IntPtr px = bpData.Scan0 + thisPixel;
System.Runtime.InteropServices.Marshal.Copy(px, rgbValues1, 0, rgbValues1.Length);
rgbValues1[0] = (byte)(255);//blue channel
rgbValues1[1] = (byte)(0);//green channel
rgbValues1[2] = (byte)(0);//red channel
rgbValues1[3] = (byte)(127)//should be alpha channel
System.Runtime.InteropServices.Marshal.Copy(rgbValues1, 0, px, 4);
bm.UnlockBits(bpData);
这将设置单个像素为蓝色,透明度为50%(或者它应该)…