开发者

C# Bitmap image masking using unsafe code

I'm using the following code to make image masks in 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);
    }
}

But it's WAY too slow... What is the unsafe equivalent to this? Will it be allot faste开发者_运维问答r?

In the end I do a bmp.Save() in PNG format.

UPDATE:

After reading through [Link removed, dangerous site] as suggested by MusiGenesis, I made it work using the following code (for anyone who needs it):

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 channel: 0 being fully transparent, 255 being no transparency on that pixel.

I'm sure you can easily modify the loop for painting a rectangle :)


You can still speed up your loop by quite a lot, by doing fewer write operations.

Create a single row of bytes in a buffer, and ask the .net runtime to copy those to managed memory. This is roughly 10-15 times faster on my computer.

// 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);

If you want to keep your "one loop iteration for each pixel", you should at least only write each pixel value once. This halves the running time on my computer.

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;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜