locked
Can't save canvas in a file (returned image is corrupted)

    Question

  • Hi,

    i've this canvas:

                    <Canvas x:Name="signCanvas" IsTapEnabled="True" Height="300" Width="500" Background="White">
                        <Ellipse Width="50" Height="50" Fill="red" />
                    </Canvas>

    And i want to save it as a bitmap after render. So:

    private async Task CreateSaveBitmapAsync(Canvas canvas)
            {
                if (canvas != null)
                {
                    RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
                    await renderTargetBitmap.RenderAsync(canvas);
    
                    var picker = new FileSavePicker();
                    picker.FileTypeChoices.Add("PNG Image", new string[] { ".png" });
                    StorageFile file = await picker.PickSaveFileAsync();
                    if (file != null)
                    {
                        var pixels = await renderTargetBitmap.GetPixelsAsync();
    
                        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)canvas.Width, (uint)canvas.Height,
                                                 96, 96, bytes);
    
                            await encoder.FlushAsync();
                        }
                    }
                }
            }

    This code works good on my pc, but when i try on my ARM surface the saved image is corrupted:

    I'm quite sure the problem is after RenderTargetBitmap.RenderAsync() - can you help me?

    Saturday, October 11, 2014 9:32 AM

Answers

  • Setting the encoder.SetPixelData last two properties to canvas' actual sizes doesn't work... but your idea made me think (i was thinking about bugs before... i also tried to restart visual studio and surface lots of time :D). Anyway i solved setting the data this way:

                            encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                                 BitmapAlphaMode.Ignore,
                                                 (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight,
                                                 96, 96, bytes);

    Saturday, October 11, 2014 10:59 AM

All replies

  • I guess that your PC uses 100 % scaling and your Surface is using a higher scaling factor (140% I believe). So the Canvas on the phone is actually rendered at a higher size and therefore the RenderTargetBitmap is bigger than 500 x 300.

    You can fix how the image looks by using canvas.ActualHeight and canvas.ActualWidth when calling encoder.SetPixelData.

    If you need a resulting image with a certain size you would have to either resize the RenderTargetBitmap before encoding it or compensate for the OS scale factor before rendering the Canvas.

    Saturday, October 11, 2014 10:44 AM
  • Setting the encoder.SetPixelData last two properties to canvas' actual sizes doesn't work... but your idea made me think (i was thinking about bugs before... i also tried to restart visual studio and surface lots of time :D). Anyway i solved setting the data this way:

                            encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                                 BitmapAlphaMode.Ignore,
                                                 (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight,
                                                 96, 96, bytes);

    Saturday, October 11, 2014 10:59 AM