302

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?

10 Answers 10

524

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.

Source: http://www.vcskicks.com/image-to-byte.php

Sign up to request clarification or add additional context in comments.

9 Comments

You can also use bitmap.Lockbits and Marshal.Copy for a simple fast copy without any intermediate memorystreams etc.
Please be aware that the ImageConverter method will save the image as Png, resulting in HUGE files.
you dont need to close the stream when using 'using'
Can 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]?
ImageConverter isn't .net standard you might use MemoryStream
|
122

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

9 Comments

Lovely. That'll do! I take it you'll want to dispose of the MemoryStream, though - care to update?
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.
Nice use of an extension method, I like it!
+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.
I 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
|
61

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

}

.

14 Comments

Hi, 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?
Hi, 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();
What is the bug? Many programmers including myself are using this code style and it works fine.
@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.
|
20

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();
  }

5 Comments

There is not Save method on Image.
@PrescottChartier The above example is assuming you are working from a type derived from System.Drawing.Image (see: learn.microsoft.com/en-us/dotnet/api/… )
Yup and I get System.Drawing.Image does not exist. So .. no, doesn't work :(
You can see what I'm trying to do here: stackoverflow.com/questions/55084620/…
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);
14

Use a MemoryStream instead of a FileStream, like this:

MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();

5 Comments

You probably want ToArray, not GetBuffer.
GetBuffer returns an array of unsigned bytes (byte array)
It 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.
This approach saves the image as a jpeg with default compression settings, which will introduce compression artefacts that might visibly degrade your image.
These is no Save method on bmp.
13

More simple:

return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))

1 Comment

Thanks - works like a charm, but the answer would be even better, if you added explanation on how it works.
11

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;

2 Comments

This approach saves the image as a jpeg with default compression settings, which will introduce compression artefacts that might visibly degrade your image.
Again, no Save method on bitmap.
8

I believe you may simply do:

ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));

Comments

7
MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();

Comments

-4

Very simple use this just in one line:

byte[] imgdata = File.ReadAllBytes(@"C:\download.png");

1 Comment

op said he is not interested in this option

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.