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.
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;
}