3

在 C#、.NET 2.0、Windows 窗体、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");

例如,如果我正在使用

颜色 [A=153, R=193, G=204, B=17] 或#C1CC11

在我保存图像并在 Paint.NET、IrfanView、XNView 等外部查看器中打开它之后。我被告知图像的颜色实际上是:

颜色 [A=153, R=193, G=203, B=16] 或#C1CB10

所以它是一个相似的颜色,但不一样!

我尝试同时保存 PNG 和 BMP。

当涉及透明度(alpha)时,.NET 会保存不同的颜色!当 alpha 为 255(无透明度)时,它会保存正确的颜色。

4

2 回答 2

2

谢谢乔和汉斯·帕桑特的评论。

是的,正如乔所说,问题出在:

graphics.FillRectangle(brush, 0, 0, width, height);

这里 GDI+ 用相似的颜色修改颜色,但不是确切的颜色。

似乎解决方案是直接在像素中写入颜色值,使用 Bitmap.LockBits 和 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;
于 2011-12-14T17:43:28.100 回答
2

只是想补充一点。根据我的经验,最后一个代码片段可能会引发运行时错误。这是因为位图中的 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%(或者应该)......我自己仍在努力......

于 2013-07-04T16:09:35.823 回答