Image being saved from canvas is not rendered properly - c#

I'm trying to use the following code to save the contents of myCanvas as an image file in the gallery (for Windows Phone 8.1, not Silverlight). When I run the App, the image is saved but it is distorted. What am I doing wrong? I have uploaded the resultant image and the expected result.
public async void SaveFileToPhone()
{
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("bug.png", CreationCollisionOption.GenerateUniqueName);
await SaveVisualElementToFile(myCanvas, file);
}
async Task SaveVisualElementToFile(FrameworkElement element, StorageFile file)
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element, (int)element.Width, (int)element.Height);
var pixels = await renderTargetBitmap.GetPixelsAsync();
txt_bug.Text = "Width: " + (int)element.Width + " Height:" + (int)element.Height;
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await
BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)element.Width, (uint)element.Height,
96, 96, bytes);
await encoder.FlushAsync();
}
}
The XAML code for canvas is as follows:
<Canvas x:Name="myCanvas" Background="#FF33FFE3" Margin="25,75,26,10"
ManipulationStarted="myCanvas_ManipulationStarted"
ManipulationCompleted="myCanvas_ManipulationCompleted"
ManipulationDelta="myCanvas_ManipulationDelta" ManipulationMode="All"
Tapped="myCanvas_Tapped" MinHeight="555" MinWidth="350" Width="350" Height="555">
<Canvas.Clip>
<RectangleGeometry Rect="0 0 350 555"/>
</Canvas.Clip>
</Canvas>

The params to the SetPixelData method are incorrect.
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)element.Width, (uint)element.Height,
96, 96, bytes);
Change them to the follow can make it work.
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
bytes);
You can download the XAML render to bitmap sample from MSDN for reference.

Related

How to convert a UIElement which is created in code behind into stream using C#?

I have created UIelements dynamically in code behind without using Xaml and I need to convert it into stream. I have tried with RenderTargetBitmap. But it doesnot work, Is there any possible other ways for it?
private async void ConverteToImage(UIElement element, int pageIndex)
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element); // Render canvas.
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
using (var stream = new InMemoryRandomAccessStream())
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
logicalDpi,
logicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
SaveAsCustomStamp(stream.AsStream(), pageIndex, loadedDocument);
}
}

Windows phone 8.1 save StorageFile as image

I want to save StorageFile as image that can be seen in gallery and use later. StorageFile contain image taken by camera or taken from gallery and converted in StorageFile.
private async void SaveCroppedImage(object sender, RoutedEventArgs e)
{
StorageFile file = await KnownFolders.CameraRoll.CreateFileAsync("edited.jpg", CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream stream =await file.OpenAsync(FileAccessMode.ReadWrite))
{
await EncodeWriteableBitmap(WB_CroppedImage, stream, BitmapEncoder.JpegEncoderId);
}
}
private static async Task EncodeWriteableBitmap(WriteableBitmap bmp, IRandomAccessStream writeStream, Guid encoderId)
{
// Copy buffer to pixels
byte[] pixels;
using (var stream = bmp.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
// Encode pixels into stream
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied,
(uint)bmp.PixelWidth, (uint)bmp.PixelHeight,
96, 96, pixels);
await encoder.FlushAsync();
}
Save the storagefile with known image extensions (like .jpg or .png) in the public folder, it will show up in the gallery.

UWP encode image to PNG

I get an image by URI (web or file system) and want to encode it into PNG and save to a temporary file:
var bin = new MemoryStream(raw).AsRandomAccessStream(); //raw is byte[]
var dec = await BitmapDecoder.CreateAsync(bin);
var pix = (await dec.GetPixelDataAsync()).DetachPixelData();
var res = new FileStream(Path.Combine(ApplicationData.Current.LocalFolder.Path, "tmp.png"), FileMode.Create);
var enc = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, res.AsRandomAccessStream());
enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, dec.PixelWidth, dec.PixelHeight, 96, 96, pix);
await enc.FlushAsync(); //hangs here
res.Dispose();
Problem is, this code hangs on the await enc.FlushAsync() line.
Please help! Thanks.
I don't know for sure why your code hangs -- but you're using several IDisposable thingies, which may be related. At any rate, here's some code that does pretty much what you're trying to do, and it does work:
StorageFile file = await ApplicationData.Current.TemporaryFolder
.CreateFileAsync("image", CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (MemoryStream imageStream = new MemoryStream())
{
using (Stream pixelBufferStream = image.PixelBuffer.AsStream())
{
pixelBufferStream.CopyTo(imageStream);
}
BitmapEncoder encoder = await BitmapEncoder
.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)image.PixelWidth,
(uint)image.PixelHeight,
dpiX: 96,
dpiY: 96,
pixels: imageStream.ToArray());
await encoder.FlushAsync();
}
}
(My image is a WriteableBitmap; not sure what your raw is?)

How to get app screen shot

In the SL App, I can use:
var bitmap = new WriteableBitmap(uiElementForViewControl, new TranslateTransform());
But in UWP, how do I do the same thing?
Use RenderTargetBitmap to render a UIElement (such as your page) similar to how your snippet uses WriteableBitmap, then use a BitmapEncoder to encode the RenderTargetBitmap's pixels to a jpg or png to save out.
See https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.rendertargetbitmap.aspx and https://msdn.microsoft.com/en-us/library/windows/apps/mt244351.aspx
private async Task SaveVisualElementToFile(FrameworkElement element, StorageFile file)
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element);
var pixels = await renderTargetBitmap.GetPixelsAsync();
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixels.ToArray());
await encoder.FlushAsync();
}
}
With Control.DrawToBitmap you can capture a Form, which is the "app" you are looking for.

BitmapImage or ImageStream to image file - Windows 10

I have Windows.Graphics.Imaging ImageStream. It is easy to get it as source of XAML Image:
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
XAMLImage.Source = bitmapImage;
But I did not figured out how to save it to image file (png,jpg,...) in Windows 10 app.
Thnx for help.
You can not save a BitmapImage as png or jepg file, you should use WriteableBitmap to instead.
CODE(How to save a WriteableBitmap as JPEG):
var image = new WriteableBitmap(50, 50);
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/StoreLogo.png"));
var content = await file.OpenReadAsync();
image.SetSource(content);
var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("saveas.jpg");
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId,
await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite));
Stream pixelStream = image.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)image.PixelWidth, (uint)image.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();

Categories

Resources