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の両方で保存してみました。

透明度 (アルファ) が関係する場合、.NET は別の色を保存します! アルファが 255 (透明度なし) の場合、正しい色が保存されます。

4

2 に答える 2

2

Joe と Hans Passant さん、コメントありがとうございます。

はい、ジョーが言ったように、問題は次の行にあります。

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 は int です。画像に対していくつかのテスト ケースを実行して、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 に答える