Using C#, is there a better way to convert a Windows Bitmap
to a byte[]
than saving to a temporary file and reading the result using a FileStream
?

- 7,151
- 7
- 49
- 71

- 24,842
- 10
- 63
- 95
10 Answers
There are a couple ways.
ImageConverter
public static byte[] ImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
This one is convenient because it doesn't require a lot of code.
Memory Stream
public static byte[] ImageToByte2(Image img)
{
using (var stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
This one is equivalent to what you are doing, except the file is saved to memory instead of to disk. Although more code you have the option of ImageFormat and it can be easily modified between saving to memory or disk.

- 2,599
- 1
- 25
- 37

- 12,528
- 5
- 34
- 50
-
2You can also use bitmap.Lockbits and Marshal.Copy for a simple fast copy without any intermediate memorystreams etc. – deegee Jun 21 '13 at 21:31
-
8Please be aware that the `ImageConverter` method will save the image as Png, resulting in HUGE files. – skolima Mar 05 '14 at 18:12
-
8you dont need to close the stream when using 'using' – I Stand With Russia May 15 '15 at 22:11
-
2Can anybody give me a bit more information on how this array is structured? Does it begin with x = 0 and cycles through every y and then incrementing x? And then store it like this: [0,0,1,1,1,1,0,0,1,1]? – Raymond May 20 '17 at 06:43
-
1`ImageConverter` isn't .net standard you might use `MemoryStream` – Alexandre Jan 03 '19 at 11:40
-
1I get an error on img.Save, apparently it doesn't exist. – Prescott Chartier Mar 10 '19 at 12:20
-
I really liked the first solution. It was simple, easy to use, and really helped me. Thanks so much. – programmerRaj Mar 21 '20 at 17:00
-
@Raymond the byte array represents what the saved-to-disk image would be in the given ImageFormat (e.g. PNG, JPEG, etc.), which is not necessarily in any pixel order – p10ben Jan 10 '21 at 22:17
-
I put a 2x2 pixel bitmap into this function and got back an array of length 901?? – john k Mar 18 '23 at 21:47
A MemoryStream can be helpful for this. You could put it in an extension method:
public static class ImageExtensions
{
public static byte[] ToByteArray(this Image image, ImageFormat format)
{
using(MemoryStream ms = new MemoryStream())
{
image.Save(ms, format);
return ms.ToArray();
}
}
}
You could just use it like:
var image = new Bitmap(10, 10);
// Draw your image
byte[] arr = image.ToByteArray(ImageFormat.Bmp);
I partially disagree with prestomanifto's answer in regards to the ImageConverter. Do not use ImageConverter. There's nothing technically wrong with it, but simply the fact that it uses boxing/unboxing from object tells me it's code from the old dark places of the .NET framework and its not ideal to use with image processing (it's overkill for converting to a byte[] at least), especially when you consider the following.
I took a look at the ImageConverter
code used by the .Net framework, and internally it uses code almost identical to the one I provided above. It creates a new MemoryStream
, saves the Bitmap
in whatever format it was in when you provided it, and returns the array. Skip the extra overhead of creating an ImageConverter
class by using MemoryStream

- 29,917
- 5
- 57
- 77
-
Lovely. That'll do! I take it you'll want to dispose of the MemoryStream, though - care to update? – Jeremy McGee Sep 08 '11 at 15:39
-
I've updated my answer with some discussion about why not to use ImageConverter, as your selected answer suggests, as well as the addition of disposal. – Christopher Currens Sep 08 '11 at 16:39
-
-
3+1 for looking into ImageConverter and reporting the results of your research. But I don't think what you've discovered warrants the statement "Do not use ImageConverter." It definitely provides useful services going the other way, from byte array to Image, for example setting the image resolution (dpi). And the "extra overhead of creating an ImageConverter class" is presumably negligible, and only needs to be done once irrespective of how many times you use it. – RenniePet May 16 '13 at 00:42
-
1I found ImageConverter helpful too in that it can determine the type of the image automatically - for example if you have a byte array of the image, but don't know the format - you could try reading headers and getting hints from there, but, well, ... using (Image img = (Image)myImgConverter.ConvertFrom(byteImage)) and then checking img.PixelFormat etc. is just easier.. - of course depending on what you want to do – hello_earth Nov 07 '14 at 09:38
-
-
-
I've been using the `Marshal.Copy` approach, but I'm curious whether anyone knows if the stream approach eliminates any stride overhead? Hard for me to test as all my current image sources align to boundaries, stride is the same as width in my cases. But I'm doing a lot of extra work to account for stride "just in case". – McGuireV10 Jul 25 '20 at 14:51
-
To answer my own question above -- the `MemoryStream` approach also includes stride alignment data for odd-sized images. – McGuireV10 Jul 26 '20 at 15:59
You can also just Marshal.Copy the bitmap data. No intermediary memorystream etc. and a fast memory copy. This should work on both 24-bit and 32-bit bitmaps.
public static byte[] BitmapToByteArray(Bitmap bitmap)
{
BitmapData bmpdata = null;
try
{
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
int numbytes = bmpdata.Stride * bitmap.Height;
byte[] bytedata = new byte[numbytes];
IntPtr ptr = bmpdata.Scan0;
Marshal.Copy(ptr, bytedata, 0, numbytes);
return bytedata;
}
finally
{
if (bmpdata != null)
bitmap.UnlockBits(bmpdata);
}
}
.

- 1,553
- 14
- 13
-
2Hi, I used this method, but I cannot convert this byte array back to an image again. Bitmap bitmap1 = new Bitmap(new MemoryStream(array)); it throws an exception of invalid parameters. Is there any mistake? – Howard Jul 30 '13 at 04:47
-
1Hi, the comments section is too small for me to post full clean code. The simplest way is to pin the array: GCHandle handle = GCHandle.Alloc(bufferarray, GCHandleType.Pinned); get the pointer to the array IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement(bufferarray, 0); then create a new bitmap using the IntPtr: bitmap = new Bitmap(width, height, (width * 4), PixelFormat.Format32bppArgb, iptr); but you will have to use the appropriate bitmap creation parameters for your bitmap format. Be sure to clean up: iptr = IntPtr.Zero; handle.Free(); – deegee Jul 30 '13 at 19:28
-
-
4What is the bug? Many programmers including myself are using this code style and it works fine. – deegee Dec 06 '13 at 18:01
-
@mini-me - what bug? This code works fine for 32-bit bitmaps. Perhaps you are trying to use it with paletted pixelformat bitmaps? If so, convert them to 32-bit first. – deegee Dec 30 '13 at 16:26
-
When you use 24-bit, 16-bit or 8-bit bitmaps with odd widths you'll have junk bytes between the scanlines. I call that a bug because I can't have those junk bytes. My algorithms work with pixel data only (which is good). If you keep those junk bytes (that's what your functions does) you'll have to deal with them in your algorithms. – Bitterblue Jan 06 '14 at 10:13
-
6@mini-me - I recommend looking up what bitmap stride versus bitmap width is. This is not a bug in my code, this is how Windows handles bitmaps. Stride may include extra data at the end of each line (width) in order to have each line end and start on a 32-bit boundary for memory alignment and performance. – deegee Jan 06 '14 at 20:32
-
Please don't try to teach me about bitmaps. See my last comment. That's all I had to add on that matter. – Bitterblue Jan 07 '14 at 07:48
-
6It is not a bug. http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride%28v=vs.110%29.aspx – deegee Jan 07 '14 at 17:48
-
1Great! This works even when you try to pass the byte array to c++ and create opencv image from it. – benderto Jul 17 '15 at 10:08
-
I get several errors, `LockBits`, `ImageLockMode` and `PixelFormat` doesn't exist. – Prescott Chartier Mar 10 '19 at 12:24
-
1@PrescottChartier - Make sure that you are referencing the proper namespaces: using System.Drawing; and using System.Drawing.Imaging; – deegee Mar 29 '19 at 06:00
-
i thought i was seeing a similar problem as @PrescottChartier but my mistake was using `Bitmap.LoadFrom(:Stream)` which is actually a static method inherited (defined on) `Image`, so the resulting object reference was not `Bitmap` but was `Image` typed. Switching to `new Bitmap(:Stream)` solved this problem. Hope that helps others, took me a few to realize what I had done wrong. – Shaun Wilson Feb 07 '21 at 08:16
-
This solution **only stores the pixel data**. You can't create the Bitmap from this binary data without knowing the other bitmap data. The solution of Chris Baxter also contains the metadata, so it can be used to fill a MemoryStream and create the same Bitmap again: `using (var ms = new MemoryStream(previewBinary))` `bitmap = (Bitmap)Image.FromStream(ms);` – huha Nov 24 '21 at 14:55
Save the Image to a MemoryStream and then grab the byte array.
http://msdn.microsoft.com/en-us/library/ms142148.aspx
Byte[] data;
using (var memoryStream = new MemoryStream())
{
image.Save(memoryStream, ImageFormat.Bmp);
data = memoryStream.ToArray();
}

- 16,083
- 9
- 51
- 72
-
-
@PrescottChartier The above example is assuming you are working from a type derived from `System.Drawing.Image ` (see: https://learn.microsoft.com/en-us/dotnet/api/system.drawing.image.save?view=netframework-4.7.2#System_Drawing_Image_Save_System_IO_Stream_System_Drawing_Imaging_ImageFormat_ ) – Chris Baxter Mar 10 '19 at 13:23
-
Yup and I get `System.Drawing.Image does not exist`. So .. no, doesn't work :( – Prescott Chartier Mar 10 '19 at 13:29
-
You can see what I'm trying to do here: https://stackoverflow.com/questions/55084620/android-xamarin-retrieve-the-image-stored-in-an-imageview/55084716#55084716 – Prescott Chartier Mar 10 '19 at 13:53
-
This solution also contains the metadata in the byte array. So it can be used to fill a MemoryStream and create the same Bitmap again: `using (var ms = new MemoryStream(previewBinary))` `bitmap = (Bitmap)Image.FromStream(ms);` – huha Nov 24 '21 at 14:57
Use a MemoryStream
instead of a FileStream
, like this:
MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();

- 5,551
- 9
- 55
- 88
-
-
-
5It could have filler data that is not part of the image. From docs: `Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method.` So now the byte array from `GetBuffer` will return the image plus unused bytes, which will probably result in a corrupt image. – vcsjones Sep 08 '11 at 16:13
-
This approach saves the image as a jpeg with default compression settings, which will introduce compression artefacts that might visibly degrade your image. – Richard Ev Jan 05 '15 at 15:26
-
More simple:
return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))

- 157
- 1
- 5
-
3Thanks - works like a charm, but the answer would be even better, if you added explanation on how it works. – Igand Jul 02 '20 at 12:04
Try the following:
MemoryStream stream = new MemoryStream();
Bitmap bitmap = new Bitmap();
bitmap.Save(stream, ImageFormat.Jpeg);
byte[] byteArray = stream.GetBuffer();
Make sure you are using:
System.Drawing & using System.Drawing.Imaging;

- 3,382
- 2
- 22
- 27
-
1This approach saves the image as a jpeg with default compression settings, which will introduce compression artefacts that might visibly degrade your image. – Richard Ev Jan 05 '15 at 15:27
-
I believe you may simply do:
ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));

- 2,534
- 5
- 18
- 29
MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();

- 2,320
- 2
- 25
- 33

- 1,963
- 2
- 19
- 38
Very simple use this just in one line:
byte[] imgdata = File.ReadAllBytes(@"C:\download.png");