UPDATE: For the RTM version you have to use SetSourceAsync method of the BitmapImage or WritableBitmap. A synchronous call just blocks the execution.
It seems to be a very common need among the Windows 8 (metro) developers to convert byte array to an IRandomAccessStream (i.e. when you want to set the source of a BitmapImage).
Here is what seems to work:
1) First we declare a wrapper class for a MemoryStream:
class MemoryRandomAccessStream : IRandomAccessStream { private Stream m_InternalStream; public MemoryRandomAccessStream(Stream stream) { this.m_InternalStream = stream; } public MemoryRandomAccessStream(byte[] bytes) { this.m_InternalStream = new MemoryStream(bytes); } public IInputStream GetInputStreamAt(ulong position) { this.m_InternalStream.Seek((long)position, SeekOrigin.Begin); return this.m_InternalStream.AsInputStream(); } public IOutputStream GetOutputStreamAt(ulong position) { this.m_InternalStream.Seek((long)position, SeekOrigin.Begin); return this.m_InternalStream.AsOutputStream(); } public ulong Size { get { return (ulong)this.m_InternalStream.Length; } set { this.m_InternalStream.SetLength((long)value); } } public bool CanRead { get { return true; } } public bool CanWrite { get { return true; } } public IRandomAccessStream CloneStream() { throw new NotSupportedException(); } public ulong Position { get { return (ulong)this.m_InternalStream.Position; } } public void Seek(ulong position) { this.m_InternalStream.Seek((long)position, 0); } public void Dispose() { this.m_InternalStream.Dispose(); } public Windows.Foundation.IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) { var inputStream = this.GetInputStreamAt(0); return inputStream.ReadAsync(buffer, count, options); } public Windows.Foundation.IAsyncOperation<bool> FlushAsync() { var outputStream = this.GetOutputStreamAt(0); return outputStream.FlushAsync(); } public Windows.Foundation.IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer) { var outputStream = this.GetOutputStreamAt(0); return outputStream.WriteAsync(buffer); } }
2) Then you can either use an extension method that will convert the bytes or memory stream (i.e. public static IRandomAccessStream AsRandomAccessStream(this byte[] byteArray) ), or you can directly use this class to convert the byte array to IRandomAccessStream:
// // We create the random access stream MemoryStream stream = new MemoryStream(imageBytes); var randomAccessStream = new MemoryRandomAccessStream(stream); // or // var randomAccessStream = new InMemoryRandomAccessStream(imageBytes); BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSourceAsync(randomAccessStream); image.Source = bitmapImage;
Good luck everyone…
Thanks for the post! Been tearing my hair out at this one for hours π
I was using this approach but my class stopped working with the latest windows 8 release. The differences was my class didn’t implement the ReadAsync, FlushAsync and WriteAsync methods.
I’m guessing something changed with SetSource to do with threading.
LikeLike
I know right? π As it seems now the SetSource calls the ReadAsync.
LikeLike
Pingback: Converting StorageFiles (png) to a Byte[] in order to display as an Image in WinRT (C#) - Derik Whittaker - Devlicio.us - Just the Tasty Bits
This piece of art seems to be broken in RTM code… any solution?
LikeLike
Hey Thomas, working on the solution… Does it completely block the execution in RTM for you as well?
LikeLike
return inputStream.ReadAsync(buffer, count, options); blocks the execution on my machine.
LikeLike
hey Thomas, the only solutions seems to be to call SetSourceAsync on the BitmapImage. A synchronous call just blocks the execution as you mentioned.
LikeLike
Need help regarding this blog entry, see this, http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/d758d8ae-c72b-48a1-92e6-06a6c412d3ed
LikeLike
I read PDF content as byte[] and then I use above method. It does work.
But for the image (png, bmp, jpeg) byet[], it works properly.
Why it doesn’t work for PDF byte[]. Do you have any good ideas?
LikeLike
In above comment, there was some mistakes. Sorry!!!
I read PDF content as byte[] and then I use above method. It doesn’t work.
But for the image (png, bmp, jpeg) byet[], it works properly
Why it doesnβt work for PDF byte[]. Do you have any good ideas?
LikeLike
hey yu lin, would you paste some code sample showing what your are trying to achieve with the PDF bytes converted into randomaccessstream… maybe the control your are trying to load requires something extra…
LikeLike
FileOpenPicker filepickerOpen = new FileOpenPicker();
filepickerOpen.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filepickerOpen.ViewMode = PickerViewMode.Thumbnail;
filepickerOpen.FileTypeFilter.Clear();
filepickerOpen.FileTypeFilter.Add(“.png”);
filepickerOpen.FileTypeFilter.Add(“.pdf”);
StorageFile storage= await filepickerOpen.PickSingleFileAsync();
byte[] buffer = WindowsRuntimeBufferExtensions.ToArray(await FileIO.ReadBufferAsync(storage));
using (MemoryStream ms = new MemoryStream(buffer))
{
var ims = new InMemoryRandomAccessStream();
DataWriter dataWriter = new DataWriter(ims);
dataWriter.WriteBytes(buffer);
dataWriter.StoreAsync();
ims.Seek(0);
BitmapImage img = new BitmapImage();
img.SetSource(ims);
ImageDocument.Source = img;
}
LikeLike
oh I see what is going on… you cannot load pdf bytes to bitmapimage (ImageSource)… it only supports different image types (e.g. png, gif, tiff, bmp)… for pdf there is no native control that can display the data… you might want to look for a 3rd part control, or just launch the pdf file using the launcher class… it will automatically use the Reader app to open the file.
LikeLike
no. I don’t want to launch with Reader cos it is look alike changing to another application. I only want to show within my application. I have already looked for 3rd part control. I found one. It is
“Foxit Embedded PDF SDK”(http://www.foxitsoftware.com/products/sdk/embedded/windows/) . We can get source code from this side. But problem is trial version only for 30days. I haven’t found another vendor that are full free. I have also looked for silverlight library. But nothing works …:(
Do you have any other options?
LikeLike
Dude, you saved my life. I searched everywhere online(yeah, was a bit desperate). Finally landed here, I just implemented it and found that one to be working. Thanks a lot
LikeLike
haha, awesome mate, glad it worked out for you…
LikeLike
Thanks a lot, I was looking all over the place for a solution, and this worked out flawlessly for me. I’m surprised I haven’t found really anyone else with this problem.
LikeLike
@Nkosi Dean: glad the solution worked for you… I guess the main issue is to pass this transitional period between the System.IO and the new memory streams that are introduced in windows.storage namespace. Probably there will be more and more options for the new streams.
LikeLike
Dude i have an error at
public Windows.Foundation.IAsyncOperation FlushAsync()
{
var outputStream = this.GetOutputStreamAt(0);
return outputStream.FlushAsync();
}
and the error says
“Error6 Using the generic type ‘Windows.Foundation.IAsyncOperation’ requires 1 type arguments”? lol i am new to this but have no idea what that means any help will be appreciated π awesome post btw!
π
LikeLike
hey there,
I am not sure how or why but the method signature was not correct, nice catch mate… the correct signature should be:
public Windows.Foundation.IAsyncOperation<bool> FlushAsync()
I just updated the post as well…
good luck…
LikeLike
Thanks for the post! π
LikeLike
Nice code
Using this code can I use it to read a mp4 stream in a media element?
LikeLike
Hi, everything seems to be working but i still can’t seem to display the image on the screen
here’s my code:
public void BytesToImage(byte[] bytes)
{
BitmapImage bitmapImage = new BitmapImage();
MemoryStream ms = new MemoryStream(bytes);
var randomAccessStream = new MemoryRandomAccessStream(ms);
bitmapImage.SetSource(randomAccessStream);
ImgResult.Source = bitmapImage;
ImgResult.Visibility = Visibility.Visible;
}
my application is running and everything but i cant get it to display the image.
LikeLike
hey sorry for the late response, but did you try to use bitmapImage.SetSourceAsync(randomAccessStream)? I think the problem is with the UI synchronization context interfering with the async operations in the memoryrandomaccessstream.
LikeLike
I used this on WP8 but found I needed to change this.GetInputStream(0) to this.GetInputStream(Position) and this.GetOutputStream(0) to this.GetOutputStream(Position). This way, subsequent calls to ReadAsync, etc will use the current stream position.
LikeLike
I used this class to convert an in-memory stream of samples to something that Sharpdx.XAudio2 could play. The first second or so was repeating constantly. I fixed this by changing the SeekOrigin in MemoryRandomAccessStream.GetInputStreamAt and .GetOutputStreamAt from SeekOrigin.Begin to SeekOrigin.Current.
Maybe this is a problem with XAudio2? Hopefully it will help someone else out anyway.
LikeLike
How can I do the opposite, I want to create a short array from a IMemoryRandomAccessStream
LikeLike
thanks a lot bro…. π
LikeLike