Reputation: 245
I'm an iOS developer learning Windows Store App development with no previous Microsoft technology experience.
I need to save an image to a file. I figured this would be easy, but I've been at it for a day and I've got nothing to show for it. Either this is extremely difficult in Windows, or I'm missing something due to ignorance of the platform / APIs.
The source of the image I need to save is Windows.UI.Xaml.Media.Imaging.RenderTargetBitmap. RenderTargetBitmap can return an image as either a source for Windows.UI.Xaml.Controls.Image or as a IBuffer.
I can verify that RenderTargetBitmap is rendering the image correctly. However, I have not been able to save the image to a file. I'd hoped that Image would have a Save() method, but it doesn't. So I figured I'd need to use the IBuffer somehow. I got close, I was able to save the buffer to disk, but it was unencoded, so I couldn't open it in anything.
So, next, I tried converting the buffer to a stream, encoding that into PNG with BitmapEncoder. That worked, but that left me with my PNG data in a IRandomAccessStream. I have no idea how to save a IRandomAccessStream to a file.
I tried 5-10 different convoluted approaches, such as going through type conversion hell to attempt to turn a IRandomAccessStream into an IBuffer so I could use .WriteAsync() on a file stream. I tried using a DataWriter on a file stream fed by a DataReader on my IRandomAccessStream but I ran into a type mismatch problem. Etc, etc.
So, how can I save my file? Here's what I got so far:
private async void saveButton_Click(object sender, RoutedEventArgs e)
{
//Create a new temporary image for saving
//Image tempImage = new Image();
//Create a render object
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
//Render the app's display buffer
await renderTargetBitmap.RenderAsync(null);
//Set the temp image to the contents of the app's display buffer
//tempImage.Source = renderTargetBitmap;
//Create a new file picker, set the default name, and extenstion
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedFileName = "New LightTable.png";
savePicker.FileTypeChoices.Add("Image", new List<string>(){".png"});
//Get the file the user selected
StorageFile saveFile = await savePicker.PickSaveFileAsync();
//Only move on if the user actually selected a file
if (saveFile != null)
{
//Get a buffer of the pixels captured from the screen
Windows.Storage.Streams.IBuffer buffer = await renderTargetBitmap.GetPixelsAsync();
//Get a stream of the data in the buffer
System.IO.Stream stream = buffer.AsStream();
//Convert the stream into a IRandomAccessStream because I don't know what I'm doing.
Windows.Storage.Streams.IRandomAccessStream raStream = stream.AsRandomAccessStream();
//Attempt to encode the stream into a PNG
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, raStream);
//Get a stream for the file the user selected
Windows.Storage.Streams.IRandomAccessStream fileStream = await saveFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
//FIND SOME WAY TO SAVE raStream TO fileStream
//Something like:
// await fileStream.WriteAsync(raStream.AsStreamForRead());
}
}
Either I'm just missing the very end: how to write my raStream to a file, or my approach is totally off.
I appreciate the help. Keep in mind I've only been developing with Microsoft tech for a week now. I have no .NET, Silverlight, or other MS tech experience. Saving an encoded image from a UIImage control on iOS is a single method call, so the shear complexity of the solution I'm circling makes me think I'm missing something really easy that I just don't know about.
Upvotes: 1
Views: 5727
Reputation: 3311
You need to set the pixel data into the StorageFile stream. See http://basquang.wordpress.com/2013/09/26/windows-store-8-1-save-visual-element-to-bitmap-image-file/ for an example.
Upvotes: 3