8

How can I convert a BitmapImage object to byte array in UWP ? in .Net it is easy to achieve, even in previous WinRT versions, looked all over the internet but without success, one of the solutions was to use a WriteableBitmap like mentioned in this answer, but in the current version of UWP, constructing a WriteableBitmap out of a BitmapImage isn't possible, any work around ?

6
  • How do you get that BitmapImage? From an Url or what? Commented Mar 19, 2016 at 22:50
  • 1
    @fillobotto : From a Url sir, a web url. Commented Mar 19, 2016 at 22:52
  • I just elaborated an answer, working for me in a blank UWP project Commented Mar 19, 2016 at 23:07
  • Possible duplicate of Convert BitmapImage to byte[] array in Windows Phone 8.1 Runtime Commented Mar 20, 2016 at 3:05
  • This is exactly the same as in previous WinRT versions. The answer you linked which created a WritableBitmap from a BitmapImage was for a Windows Phone Silverlight app, not a Windows Phone Runtime app. Commented Mar 20, 2016 at 3:07

2 Answers 2

12

Since you start from image url, the only way I can figure out is to get the stream of the image. To do this, RandomAccessStreamReference.CreateFromUri() method is really useful.

Windows.Storage.Streams.IRandomAccessStream random = await Windows.Storage.Streams.RandomAccessStreamReference.CreateFromUri(new Uri("http://...")).OpenReadAsync();

Then we have to decode the stream in order to be able to read all pixels for later usage.

Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(random);
Windows.Graphics.Imaging.PixelDataProvider pixelData = await decoder.GetPixelDataAsync();

Finally you can access pixel buffer in such a way.

byte[] bytes = pixelData.DetachPixelData();
Sign up to request clarification or add additional context in comments.

2 Comments

Any way to convert the actual BitmapImage object itself without passing by the url ? the scenario is hard to explain ...
@AymenDaoudi while googling I found a post from MSDN forums saying this was not possible. I'll post a link if I find it again social.msdn.microsoft.com/Forums/en-US/…
4

Yeah, to a byte[] is not too complex, I think you can get it. I wish it were simpler, but it's not.

http://codepaste.net/ijx28i

This code actually goes a step further and converts the byte[] into a Base64 string (for serializing) but you can ignore that extra step, right?

// using System.Runtime.InteropServices.WindowsRuntime;

private async Task<string> ToBase64(Image control)
{
    var bitmap = new RenderTargetBitmap();
    await bitmap.RenderAsync(control);
    return await ToBase64(bitmap);
}

private async Task<string> ToBase64(WriteableBitmap bitmap)
{
    var bytes = bitmap.PixelBuffer.ToArray();
    return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}

private async Task<string> ToBase64(StorageFile bitmap)
{
    var stream = await bitmap.OpenAsync(Windows.Storage.FileAccessMode.Read);
    var decoder = await BitmapDecoder.CreateAsync(stream);
    var pixels = await decoder.GetPixelDataAsync();
    var bytes = pixels.DetachPixelData();
    return await ToBase64(bytes, (uint)decoder.PixelWidth, (uint)decoder.PixelHeight, decoder.DpiX, decoder.DpiY);
}

private async Task<string> ToBase64(RenderTargetBitmap bitmap)
{
    var bytes = (await bitmap.GetPixelsAsync()).ToArray();
    return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}

private async Task<string> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
{
    // encode image
    var encoded = new InMemoryRandomAccessStream();
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
    encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
    await encoder.FlushAsync();
    encoded.Seek(0);

    // read bytes
    var bytes = new byte[encoded.Size];
    await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);

    // create base64
    return Convert.ToBase64String(bytes);
}

private async Task<ImageSource> FromBase64(string base64)
{
    // read stream
    var bytes = Convert.FromBase64String(base64);
    var image = bytes.AsBuffer().AsStream().AsRandomAccessStream();

    // decode image
    var decoder = await BitmapDecoder.CreateAsync(image);
    image.Seek(0);

    // create bitmap
    var output = new WriteableBitmap((int)decoder.PixelHeight, (int)decoder.PixelWidth);
    await output.SetSourceAsync(image);
    return output;
}

This was the important part:

var bytes = (await bitmap.GetPixelsAsync()).ToArray();

Thought you might enjoy seeing it context.

Best of luck.

1 Comment

Been searching and experimenting for hours and this is the only helpful thing I've found. Needed to convert Image.Source to a CanvasBitmap for a Win2D animation when neither the StorageFile nor uri is available. Crazy how there's no way to do this. RenderTargetBitmap is the least awful workaround by far.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.