使用不安全代码进行 C# 位图图像掩码处理

22

我正在使用以下代码在C#中创建图像蒙版:

for(int x = 0; x < width; x++)
{
    for(int y = 0; y < height; y++)
    {
        bmp.SetPixel(x,y,Color.White);
    }
}

for(int x = left; x < width; x++)
{
    for(int y = top; y < height; y++)
    {
        bmp.SetPixel(x,y,Color.Transparent);
    }
}

但是速度太慢了...有没有不安全但更快的等效方法?

最后我会以PNG格式执行bmp.Save()。

更新:

在阅读了 MusiGenesis 建议的 [链接已移除,该网站存在危险] 后,我使用以下代码使其工作(适用于任何需要它的人):

Bitmap     bmp = new Bitmap(1000,1000,PixelFormat.Format32bppArgb);
BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width,bmp.Height), 
                                  System.Drawing.Imaging.ImageLockMode.ReadWrite, 
                                  bmp.PixelFormat);

int PixelSize=4;

unsafe 
{
    for(int y=0; y<bmd.Height; y++)
    {
        byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);

        for(int x=0; x<bmd.Width; x++)
        {
            row[x*PixelSize]     = 0;   //Blue  0-255
            row[x*PixelSize + 1] = 255; //Green 0-255
            row[x*PixelSize + 2] = 0;   //Red   0-255
            row[x*PixelSize + 3] = 50;  //Alpha 0-255
        }
    }
}

bmp.UnlockBits(bmd);

bmp.Save("test.png",ImageFormat.Png);

Alpha通道:0表示完全透明,255表示该像素没有透明度。

我相信您可以轻松修改绘制矩形的循环 :)


你不能在一个循环中完成这个任务吗?这样会更快的。 - Ortiga
第二个循环针对位图应用每个矩形或透明度会运行多次。即使组合这些循环,仍然无法像使用不安全代码那样快速产生结果。 - Tom
1
你在循环中正确地使用了BitmapData对象的Width和Height属性。如果在Bitmap本身上访问这些属性,代码会变慢(这是.NET图像处理中常见的错误)。 - MusiGenesis
1个回答

1
你仍然可以通过减少写操作来加速循环。
在缓冲区中创建一行字节,并要求.NET运行时将其复制到托管内存中。在我的电脑上,这大约快了10-15倍。
// Build a "row" array and copy once for each row
// You can also build the full byte array and do only one
// call to Marshal.Copy, but that of course takes more memory.

var bytesPerPixel = 4;
byte[] row = new byte[bmp.Width * bytesPerPixel];
for (var i = 0; i < bmp.Width; ++i)
{
    var offset = i * bytesPerPixel;

    row[offset+0] = 0; //Blue  0-255
    row[offset+1] = 255; //Green 0-255
    row[offset+2] = 0;   //Red   0-255
    row[offset+3] = 50;  //Alpha 0-255
}

var bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
for (var i = 0; i < bits.Height; ++i)
{
    Marshal.Copy(row, 0, bits.Scan0 + (i * bits.Stride), row.Length);
}
bmp.UnlockBits(bits);

如果您想保持“每个像素一个循环迭代”,那么您至少应该只写入每个像素值一次。这将使我的计算机运行时间减半。
var pixel = (uint)(a << 24) | (uint)(r << 16) | (uint)(g << 8) | (b);
unsafe
{
    for (int y = 0; y < bmd.Height; y++)
    {
        var row = (uint*) ((byte*)bmd.Scan0 + (y * bmd.Stride));

        for (int x = 0; x < bmd.Width; x++)
        {
            row[x] = pixel;
        }
    }
}

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