The fastest way to get image data out of an image is to use LockBits and Marshal.Copy.
I strongly advice against using GetPixel. See, LockBits works by reserving memory for putting the bytes of the image and copying the bytes of the image in there. UnlockBits will then clean up that reserved memory.
Now, the problem is, GetPixel performs this same locking and unlocking operation for every single pixel you access. Using LockBits once is fairly fast, but using it over and over for tens of thousands of pixels really slows things down.
Note that there are two ways of using LockBits; either you get the data in the original pixel format, using sourceImage.PixelFormat, or you make LockBits convert the data to the format you require, by giving a different one. In this code, I force the output to the pixel format Format32bppArgb.
/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageDataAs32bppArgb(Bitmap sourceImage)
{
BitmapData sourceData = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Byte[] data = new Byte[sourceData.Stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}
Stride can normally differ from width * bpp since lines of bitmaps are always aligned to multiples of 4 bytes, so normally you need to return that as well and keep track of it, but since this is a 32-bit format, its data is always aligned to 4 bytes, so there is never an actual difference here.
Note, your question never specifies the order in which you need the data. Typical ARGB data is actually in the byte order B, G, R, A, because normal integer saving on IBM PC architecture is little-endian, meaning that the actual bytes of an Int32 value "FFEEDDCC" are reversed in memory to [CC DD EE FF]. But your comment on the other answer given here seemed to indicate you went for byte order [RR, GG, BB, AA], or, 'ABGR', which is honestly not a format I've ever seen before. But if you do need to change that, it's just a simple extra loop to exchange red and blue:
for (Int32 i = 0; i < data.Length; i += 4)
{
Byte b = data[i]; // save Blue
data[i] = data[i + 2]; // set first component to the Red value
data[i + 2] = b; // set third component to the Blue value
}