1

I have saved images in our database by using the following method to convert them to byte arrays in different ImageFormats:

public byte[] foo()
{
    Image img = Image.FromFile(path);
    var tmpStream = new MemoryStream();
    ImageFormat format = img.RawFormat;
    img.Save(tmpStream, format);
    tmpStream.Seek(0, SeekOrigin.Begin);
    var imgBytes = new byte[MAX_IMG_SIZE];
    tmpStream.Read(imgBytes, 0, MAX_IMG_SIZE);
    return imgBytes;
}

Now I need to read them out and convert them back into the BitmapImage type so I can display them to the user. I was thinking about using the Image.FromStream(Stream) method but that doesn't seem to take into account the different ImageFormats... Anyone know what to do? Thanks in advance.

Clemens
  • 123,504
  • 12
  • 155
  • 268
m4gik
  • 430
  • 5
  • 27
  • 1
    IIRC, Image.FromStream should automatically detect the image format. Do you need to do anything special with it based on its format? – MrZander Apr 21 '17 at 00:02
  • Possible duplicate of [convert array of bytes to bitmapimage](http://stackoverflow.com/questions/14337071/convert-array-of-bytes-to-bitmapimage) – mm8 Apr 21 '17 at 08:51

1 Answers1

6

You shouldn't use classes from the WinForms System.Drawing namespace in a WPF application (like you do with Image.FromFile).

WPF provides its own set of classes to load and save bitmaps from Streams and URIs, and has built-in support for automatically detecting the format of a bitmap frame buffer.

Just create a BitmapImage or a BitmapFrame directly from a Stream:

public static BitmapSource BitmaSourceFromByteArray(byte[] buffer)
{
    var bitmap = new BitmapImage();

    using (var stream = new MemoryStream(buffer))
    {
        bitmap.BeginInit();
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = stream;
        bitmap.EndInit();
    }

    bitmap.Freeze(); // optionally make it cross-thread accessible
    return bitmap;
}

or

public static BitmapSource BitmaSourceFromByteArray(byte[] buffer)
{
    using (var stream = new MemoryStream(buffer))
    {
        return BitmapFrame.Create(
            stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    }
}

Either method returns a BitmapSource, which is the base class of BitmapImage and BitmapFrame, and should be sufficient to deal with bitmaps in the rest of your application. E.g. the Source property of an Image control uses another base class, ImageSource, as property type.

Note also that when you load a BitmapSource from a Stream that is to be closed after loading, you have to set BitmapCacheOption.OnLoad. Otherwise the Stream must be kept open until the bitmap is eventually shown.


For encoding a BitmapSource you should be using a method like this:

public static byte[] BitmapSourceToByteArray(BitmapSource bitmap)
{
    var encoder = new PngBitmapEncoder(); // or any other BitmapEncoder

    encoder.Frames.Add(BitmapFrame.Create(bitmap));

    using (var stream = new MemoryStream())
    {
        encoder.Save(stream);
        return stream.ToArray();
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268