26

I know how to do it in WinForms

byte[] binaryData = Convert.FromBase64String(bgImage64);
image = Image.FromStream(new MemoryStream(binaryData));

but how do i do the same thing in WPF?

LDomagala
  • 2,193
  • 4
  • 20
  • 34
  • Which part of those two lines of code aren't usable in WPF? – BFree Feb 27 '09 at 03:18
  • WPF doesn't use System.Drawing.Bitmap images like winforms does. I guess the question would be "how do I load a WPF image from a blob"? – Orion Edwards Feb 27 '09 at 03:22
  • Orion: get back to work. I'll go see how I do it in my app. – geofftnz Feb 27 '09 at 03:23
  • Interesting. I've only dabbled in WPF a little a few months back. What does it use for an Image? – BFree Feb 27 '09 at 03:25
  • Just did a quick Google search. See if this helps: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3d06d5ff-bf60-433c-a6be-28d3440ea582/ (I'm not posting this as an answer, because like I said I have very little knowledge of WPF nor do I know if that works) – BFree Feb 27 '09 at 03:28

3 Answers3

40
byte[] binaryData = Convert.FromBase64String(bgImage64);

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = new MemoryStream(binaryData);
bi.EndInit();

Image img = new Image();
img.Source = bi;
KenD
  • 5,280
  • 7
  • 48
  • 85
joshperry
  • 41,167
  • 16
  • 88
  • 103
  • 2
    THANK YOU!!! I have been tearing my hair out trying to convert a base64 string to an image and display it on the page. I could do the conversion, but I couldn't get it to display the image. This was exactly what I needed! – Mageician May 31 '13 at 18:43
  • 2
    Don't forget to add `bi.CacheOption = BitmapCacheOption.OnLoad;` before `bi.EndInit();` if you want to close `MemoryStream` right after setting `bi.StreamSource` – Veerakran Sereerungruangkul Jan 22 '21 at 06:02
  • The stream is disposable, should wrap it with a using statement to ensure the wasted memory is caught later by the GC. – Kevin B Burns Oct 07 '22 at 18:25
  • Thanks for the recommendation @KevinBBurns, but the documentation says this is unnecessary in the form I demonstrated: "The default OnDemand cache option retains access to the stream until the bitmap is needed, and cleanup is handled by the garbage collector". Taking advantage of IDisposable in the case of the OnLoad cache method would definitely be most efficient (it releases the memory immediately), but still no memory leak would happen without "using" unless the reference held by the BitmapImage is never released, but that is a problem outside of this implementation. – joshperry Oct 09 '22 at 02:35
36

Expanding on Josh's answer above - here's one that uses a ValueConverter so you can use binding instead of setting the image source in the code-behind.

Base64ImageConverter.cs

public class Base64ImageConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string s = value as string;

        if (s == null)
            return null;

        BitmapImage bi = new BitmapImage();

        bi.BeginInit();
        bi.StreamSource = new MemoryStream(System.Convert.FromBase64String(s));
        bi.EndInit();

        return bi;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

ImageData.cs (used as a data source)

public class ImageData
{
    public string Base64ImageData { get; set; }

    public ImageData()
    {
        this.Base64ImageData = "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";
    }
}

Window1.xaml

<Window x:Class="ImageFromData.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ImageFromData"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:Base64ImageConverter x:Key="Base64ImageConverter"/>
        <local:ImageData x:Key="ImageData"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource ImageData}">
        <Image Source="{Binding Base64ImageData, Converter={StaticResource Base64ImageConverter}}"/>
    </Grid>
</Window>

(root namespace for project is ImageFromData)

geofftnz
  • 9,954
  • 2
  • 42
  • 50
1

In a situation I came across, I created a converter to handle the conversion of a Base64 string to a WPF Image. So you can bind it to your base64 string property and let the converter take the rest. The main difference between the accepted answer and my own is the fact that a MemoryStream is an IDisposable resource and should be appropriately handled with either a try/catch/finally that disposes the resource after using it, or with a "using" statement to ensure everything is capture correctly in the Garbage Collector. Otherwise, you can run into memory leaks, or if there are enough images on the larger side, you can run into "OutOfMemory" exceptions.

https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream?view=net-6.0

https://michaelscodingspot.com/find-fix-and-avoid-memory-leaks-in-c-net-8-best-practices/

 public class ByteToImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            if (string.IsNullOrEmpty(value?.ToString()))
                return null;

            var imgBytes = System.Convert
                .FromBase64String(value.ToString() ?? throw new InvalidOperationException());

            using var stream = new MemoryStream(imgBytes);
            return BitmapFrame.Create(stream,
                BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }

        public object ConvertBack(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    
Kevin B Burns
  • 1,032
  • 9
  • 24
  • I dont understand the upvote. This answer was posted 7 years after the other answers and is basically a copy of geofftnz answer, only with fewer explanation. Also it obviously was not tested a single time, since there is a ) missing and the null value handling is bad ```string.IsNullOrEmpty(value.ToString()``` throws an exception on value being null. – FrankM Oct 07 '22 at 09:30
  • @FrankM, Thank you for the suggestion; I wrote it out in Notepad last time and edited the code with your fix. Every time you post something, you get a single vote. Not wrapping a stream in a "using" statement is one of the most significant memory leak issues. I linked some sources for my reasoning, one straight from the MSDN. – Kevin B Burns Oct 07 '22 at 18:20
  • I agree that taking advantage of immediately releasing the memory held by the MemoryStream by pairing a using directive with the OnLoad cache option is most efficient (otherwise there will be two copies of the image in memory, one in the stream and one in the BitmapImage cache after load); indeed if you have very large images this will halve your memory usage and forestall running out of memory. However, your assertion that the garbage collector will not clean up an IDisposable without a using block is incorrect, and the exception is not being caused by a "leak". – joshperry Oct 09 '22 at 02:43
  • The using statement is definately a plus. Still, it is unecessary complicated code. Your ```InvalidOperationException``` will never be thrown, mabe wrong placement of parenthesis?. ```Value.ToString()``` is called more than once and even ```.ToString()``` is questionable, since a simple ```as string``` or ```is string``` would be enough, imho. A more elegant solution would be: ```if (value is string val && !string.IsNullOrEmpty(val)) { var imgBytes = System.Convert.FromBase64String(val); ... } return null;``` ```.FromBase64String()``` throws Exceptions. I removed my downvote, no hard feelings – FrankM Nov 18 '22 at 16:40