views:

971

answers:

2

I need get all pixels from Bitmap, work this they and save them to Bitmap.

If I use Bitmap.GetPixel() and Bitmap.SetPixel() then I have very slow program.

How I can fast convert Bitmap to byte[] and back?

I need byte[] with size (4 * width * height) and contains RGBA of each pixel

+2  A: 

You want LockBits. You can then extract the bytes you want from the BitmapData object it gives you.

David Seiler
I think it's faster if you use the `BitmapData` object returned from LockBits inside an `unsafe` block with a pointer cast (NOTE: I actually have no idea if this is faster or not, but I'm trying to goad someone else into benchmarking it).
MusiGenesis
It'd save you the copies into and out of the BitmapData, which is nice. Not sure how much savings that would grant in practice, though; memcpy() is really fast these days.
David Seiler
+7  A: 

You can do it a couple of different ways. You can use unsafe to get direct access to the data, or you can use marshaling to copy the data back and forth. The unsafe code is faster, but marshaling doesn't require unsafe code. Here's a performance comparison I did a while back.

Here's a complete sample using lockbits:

/*Note unsafe keyword*/
public unsafe Image ThresholdUA(float thresh)
{
    Bitmap b = new Bitmap(_image);//note this has several overloads, including a path to an image

    BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);

    byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);

    /*This time we convert the IntPtr to a ptr*/
    byte* scan0 = (byte*)bData.Scan0.ToPointer();

    for (int i = 0; i < bData.Height; ++i)
    {
        for (int j = 0; j < bData.Width; ++j)
        {
            byte* data = scan0 + i * bData.Stride + j * bitsPerPixel / 8;

            //data is a pointer to the first byte of the 3-byte color data
        }
    }

    b.UnlockBits(bData);

    return b;
}

Here's the same thing, but with marshaling:

/*No unsafe keyword!*/
public Image ThresholdMA(float thresh)
{
    Bitmap b = new Bitmap(_image);

    BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);

    /* GetBitsPerPixel just does a switch on the PixelFormat and returns the number */
    byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);

    /*the size of the image in bytes */
    int size = bData.Stride * bData.Height;

    /*Allocate buffer for image*/
    byte[] data = new byte[size];

    /*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
    System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size);

    for (int i = 0; i < size; i += bitsPerPixel / 8 )
    {
        double magnitude = 1/3d*(data[i] +data[i + 1] +data[i + 2]);

        //data[i] is the first of 3 bytes of color

    }

    /* This override copies the data back into the location specified */
    System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length);

    b.UnlockBits(bData);

    return b;
}
notJim
Thanks, and I didn't even have to goad anybody. :)
MusiGenesis