C# Windows 8 Store (Metro, WinRT) Byte array to BitmapImage

15

I am working on a Windows 8 Metro app that applies filters to images. I have a web version of the app and wanted to port it. But as we all know WinRT doesn't have all the good things .NET provides otherwise :/

Currently I am applying the filters on a byte array and I want to keep it that way, because it's super fast! So for the past few days I have been searching for ways to convert a StorageFile to byte[] and then byte[] to BitmapImage.

So far I have managed to do the first one (StorageFile to byte[]). Here is how I do it:

public async Task<Byte[]> ImageFileToByteArray(StorageFile file)
    {
        IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
        PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
        return pixelData.DetachPixelData();
    }

This piece of code returns a byte[] that contains the pixel data as BGRA.

And here comes the tricky part. I cannot successfully convert the byte array into a BitmapImage. I have searched all over the places and many people suggest using WriteableBitmap but that doesn't do much good to me. I have also found some pieces of code that should be working... but they don't.

One of the solutions I have tried is using InMemoryRandomAccessStream like this:

public async Task<BitmapImage> ByteArrayToBitmapImage(Byte[] pixels)
    {
        var stream = new InMemoryRandomAccessStream();
        await stream.WriteAsync(pixels.AsBuffer());
        stream.Seek(0);
        var image = new BitmapImage();
        await image.SetSourceAsync(stream);
        return image;
    }

This one throws the following exception:

An exception of type 'System.Exception' occurred in mscorlib.dll but was not handled in user code

Additional information: The component cannot be found. (Exception from HRESULT: 0x88982F50)

I tried using this line instead:

PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
            BitmapPixelFormat.Bgra8, 
            BitmapAlphaMode.Ignore, 
            new BitmapTransform(),
            ExifOrientationMode.IgnoreExifOrientation, 
            ColorManagementMode.DoNotColorManage);

But it did me no good since I keep getting that exception.

I have also tried this:

var bitmapImage = new BitmapImage();
        var pixels = await ImageFileToByteArray(file);
        ImageSource imgSource;
        using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
        {
            using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
            {
                writer.WriteBytes(pixels);
                await writer.StoreAsync();
            }

            await bitmapImage.SetSourceAsync(ms);
            imgSource = bitmapImage;
        }

And get the same exception as the first piece of code.

I have also tried several other ways that include using a normal Stream then converting into a IRandomAccessStream but they didn't work either.

All of the above code seems fine to me. So my guess at the moment is that the problem is in the byte[]. I'm guessing that the format of the pixelData inside is not valid, so I tried changing it to RGBA but that didn't help either. Also the PixelHeight and PixelWidth of the BitmapImage are 0.

c#
microsoft-metro
bytearray
windows-store-apps
bitmapimage
asked on Stack Overflow Jun 14, 2013 by mitelinko • edited Jun 20, 2020 by Community

2 Answers

13

This is working for me,

    private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
    {
        var bitmapImage = new BitmapImage();

        var stream = new InMemoryRandomAccessStream();
        await stream.WriteAsync(byteArray.AsBuffer());
        stream.Seek(0);

        bitmapImage.SetSource(stream);
        return bitmapImage;
    }
answered on Stack Overflow Aug 9, 2013 by mcabral
1

this is my first answer..hope it will help.

I had the exact same problem and I spand more then 6 hours trying to figur this out. this is what i came up with: what you said was right. there are 2 waye to convert image to byteArray:

First aproach(yours)

        public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
    {
        IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
        PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
        return pixelData.DetachPixelData();
    }

Second aproach

        public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
    {
        var inputStream = await file.OpenSequentialReadAsync();
        var readStream = inputStream.AsStreamForRead();
        var buffer = new byte[readStream.Length];
        await readStream.ReadAsync(buffer, 0, buffer.Length);
        return buffer;
    }

if youll use the second aproach to decode the pic, with no Pixel, this converter will work:

public class ByteArrayToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null || !(value is byte[]))
            return null;

        using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
        {
            using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
            {
                writer.WriteBytes((byte[])value);
                writer.StoreAsync().GetResults();
            }
            BitmapImage image = new BitmapImage();
            image.SetSource(stream);
            return image;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)                                                                         
    {
        throw new NotImplementedException();
    }

for the first aproach youll need to work with WriteableBitmap as you said.

answered on Stack Overflow Nov 28, 2014 by Muffasa • edited Nov 30, 2014 by Muffasa

User contributions licensed under CC BY-SA 3.0