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 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…
.jpg)
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.
I know right?
As it seems now the SetSource calls the ReadAsync.
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?
Hey Thomas, working on the solution… Does it completely block the execution in RTM for you as well?
return inputStream.ReadAsync(buffer, count, options); blocks the execution on my machine.
hey Thomas, the only solutions seems to be to call SetSourceAsync on the BitmapImage. A synchronous call just blocks the execution as you mentioned.
Need help regarding this blog entry, see this, http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/d758d8ae-c72b-48a1-92e6-06a6c412d3ed
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?
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?
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…
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;
}
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.
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?
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
haha, awesome mate, glad it worked out for you…
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.
@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.