In any case, I found myself inside some code that got an image (in native Windows "DIB" format, as an object that was of type "byte[]") and needed to convert it into a System.Drawing.Bitmap. The code actually did this already, by extracting the image size from the DIB header, creating a new Bitmap, then proceeding to iterate over every single pixel to directly set it in the Bitmap. Obviously that was way too slow, and a better solution was needed.
I then searched the web far and wide, not really finding anything useful. Sure, there were a lot of hints, but no real solutions. Bitmap itself actually has no easy way to be created from a byte array. What it does have, strangely enough, is the ability to be created from a pointer to unmanaged memory and some hints:
public Bitmap (
int width,
int height,
int stride,
PixelFormat format,
IntPtr scan0
)
Since I had my data in a byte[], not as a chunk referenced by an IntPtr, the first step was to remedy the situation. Here is how you do it, as weird as it may look:
GCHandle handle = GCHandle.Alloc(dib, GCHandleType.Pinned);
IntPtr handlePtr = handle.AddrOfPinnedObject();
(When you are done using the handle, don't forget to call "handle.Free()".)
Now all I had to do was offset the IntPtr by 40 (size of the DIB header), add in the information the existing code already extracted from the header, and create a new bitmap. Here's the final result:
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
...
GCHandle handle = GCHandle.Alloc(dib, GCHandleType.Pinned);
IntPtr handlePtr = handle.AddrOfPinnedObject();
IntPtr scan0 = new IntPtr(handlePtr.ToInt32() + 40);
Bitmap bitmap =
new Bitmap(width, height, width * 3, PixelFormat.Format24bppRgb, scan0);
handle.Free();
...
It may look ugly, and very icky, but it does work. In fact, this allowed me to take an operation that took two whole seconds of wall-clock time and make it instantaneous.