Sometimes it’s super-valuable to take an image and convert it to text – let’s call this encoding. This text is base64 and it’s a well-established standard for such things. It can be inserted into JSON, XAML, and even used in CSS. Conversely, it’s important to convert that text back into an image – let’s call this decoding. And, developers can do it all in the Windows Runtime.
Let’s begin by recognizing that how binary information is translated into and out of text isn’t important. It’s all settled by the standards nerds – we’re just leveraging their hard work.
The ToBase64String method has been part of the .Net framework since version 1, just like the FromBase64String method. But that doesn’t mean developers are familiar with how to use it. It’s not quite as simple as it appears.
MSDN: Converts the value of an array of 8-bit unsigned integers to its equivalent string representation that is encoded with base-64 digits. Remarks: The elements of inArray are taken as a numeric value and converted to a string representation that is encoded with base-64 digits. The base-64 digits in ascending order from zero are the uppercase characters "A" to "Z", the lowercase characters "a" to "z", the numerals "0" to "9", and the symbols "+" and "/". The valueless character, "=", is used for trailing padding.
Looks pretty easy
It is. And, it’s not. Working with images in the Windows Runtime can test your wits if you aren’t familiar with how they work and, more importantly, why they work the way the do. So, let me talk you down the easy street.
How do I encode to base 64?
Long before we call ToBase64String, we must prepare the byte array with the image information we need to decode the image. Once you know how, it’s quite simple. The BitmapEncoder has a SetPixelData method for us to use. The encoder reads your image byte array and writes it, with the pixel data, to a RandomAccessStream, whose byte array we will encode.
In the code above, I take in a byte array and encode it to a base 64 string. Before I do, I set the pixel data. That’s important for when we decode it.
How do I decode base 64?
Assuming we have encoded our base 64 string correctly, decoding is simple. With one caveat; we must use the BitmapDecoder to extract the PixelHeight and PixelWidth from the resulting byte array before we try to set our final WriteableBitmap source. Without this, we have to guess what the size is, and magic numbers are unacceptable.
In the code above, I take a base 64 string and decode it into an ImageSource – a great option if you are trying to bind an image from your View Model to an Image control in XAML. But before I do, I decode the height and width so the resulting WriteableBitmap is the size I expect it to be when I encode.
Is it really that easy?
No. The most difficult part is going to be getting the byte array out of the object we are using. If we are using the BitmapImage, then getting a byte array is pretty much impossible if we don’t have reference to the original source. If we are using the WriteableBitmap, we’re in luck; the WriteableBitmap has a read-only PixelBuffer property that can be converted into a byte array.
If we want to convert an on-screen control, we use this:
In the code above, I take an XAML Image control and use the RenderTargetBitmap control to Render() the control into a Bitmap. It’s beautiful feature and a handy one, too, depending on your app.
If we want to convert a WriteableBitmap, we use this:
In the code above, I take a WriteableBitmap and use it’s PixelBuffer to access the data I can convert into a byte array. What’s important here is that ToArray() is an extension method that you can only use when you add a using statement like this: using System.Runtime.InteropServices.WindowsRuntime;
If we want to convert a StorageFile, we use this:
In the code above, I take a StorageFile and load it into a stream from which I can extract and detach the PixelData, which is a byte array. Exactly the type I need to pass to my ToBase64 method.
If we want to convert a RenderTargetBitmap, we use this:
In the code above, I take a RenderTargetBitmap (let’s say you create your own) and use it’s GetPixelsAsync() method to extract the buffer from which we can create out byte array. Like I mentioned above, you can only use ToArray() when you add: using System.Runtime.InteropServices.WindowsRuntime;
The only option I am really missing here is converting a BitmapImage. And, to be honest, just between you and me, I simply could not figure out how to convert a BitmapImage into a byte array or stream. I know WriteableBitmap and BitmapImage both inherit from BitmapSource, but it’s only WriteableBitmap that includes the PixelBuffer property that can be converted into a byte array. If BitmapImage is a serious, recurring use case for your app, you might have the same struggle and come up empty handed. Good luck :(
Listen. If you know how, please leave your solution in the comments. We’ll all be grateful. Also, if you’re dreading copying the code from those images, you can get the raw code here. (sample project)
Encoding and decoding to base 64 is an awesome way to turn binary images into text. It’s easy to forget that when we decode, we’re going to need the pixel information that must be included when it is encoded. The code in this article shows you how to include that code and how to use it when you decode.
Best of luck!