填充矩形使用提供的SolidBrush颜色时无法精确填充。

3

我正在使用色彩填充Bitmap

// Assume we have something like: 
// Bitmap bitmap = new Bitmap(3, 2, PixelFormat.Format32bppArgb);

using (SolidBrush b = new SolidBrush(color))
{
    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(Bitmap))
    {
        g.FillRectangle(b, 0, 0, Bitmap.Width, Bitmap.Height);
    }
}

然而,当我执行Bitmap.GetPixel(0, 0)这样的操作时,它会返回一个非常接近但并不完全相同的颜色。如果我将Color的Alpha通道降低到足够低,RGB颜色通道就会为零。例如,使用Color.FromArgb(1, 2, 3, 4)作为刷子颜色将产生一幅由1, 0, 0, 0组成的位图。如果我使用Color.FromArgb(11, 22, 33, 44),那么我得到的位图颜色将如11, 22, 22, 44一般。因此,我的单元测试正在失败,因为我无法得到直接匹配。

我是否有办法快速填充整个矩形以提供精确的纯色?速度很重要,在程序中需要进行一些热循环,因此不可能使用Bitmap.SetPixel(...)。除非没有其他方法,否则我不想使用unsafe


using System;
using System.Drawing;
using System.Drawing.Imaging;

public class Program
{
    public static void Main()
    {
        Bitmap Bitmap = new Bitmap(3, 2, PixelFormat.Format32bppArgb);

        using (SolidBrush b = new SolidBrush(Color.FromArgb(1, 2, 3, 4)))
        {
            using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(Bitmap))
            {
                g.FillRectangle(b, 0, 0, Bitmap.Width, Bitmap.Height);
            }
        }

        var pixel = Bitmap.GetPixel(0, 0);
        Console.WriteLine(pixel);
    }
}

2
插值伪影,Graphics.PixelOffsetMode对此代码很重要。 - Hans Passant
@HansPassant 我已经尝试了PixelOffsetMode的所有设置(根据其他SO帖子,实际上只有两个,但我为了确保尝试了所有设置),但都没有成功,然后尝试了将SmoothingModePixelOffsetMode组合使用,但仍然无济于事。我还缺少哪些东西? - Water
当然,您没有发布足够的可重现代码。位图的像素格式也很重要,我猜您有一个32bppPArgb位图。尝试使用32bppArgb,这样当alpha分量<255时,颜色就不必被转换。 - Hans Passant
@HansPassant 现在底部有一个完整的 MCVE,尽管代码在像 dotnetfiddle 这样的地方可以在 5 秒内重现。与我在帖子开始时的评论类似,我正在使用 32bppArgb 而不是 P 版本。 - Water
1个回答

1
使用LockBits()函数,在内存中设置颜色:
public static Bitmap Fill(Bitmap bmp, Color color)
{
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData =
        bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
        bmp.PixelFormat);
    IntPtr ptr = bmpData.Scan0;
    int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
    byte[] rgbValues = new byte[bytes];
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);  
    for (int i= 0; i< rgbValues.Length; i+= 4)
    {
         rgbValues[i] = color.A;
         rgbValues[i] = color.B;
         rgbValues[i] = color.G;
         rgbValues[i] = color.R;
    }
    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
    bmp.UnlockBits(bmpData);
    e.Graphics.DrawImage(bmp, 0, 0);
    return bmp;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接