Carlos28
Carlos28

Reputation: 2411

Save canvas from windows store app as image file

I'm looking for way to save canvas from windows store app, I have found:

private void CreateSaveBitmap(Canvas canvas, string filename)
     {
       RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
        (int)canvas.Width, (int)canvas.Height,
        96d, 96d, PixelFormats.Pbgra32);
      // needed otherwise the image output is black
       canvas.Measure(new Size((int)canvas.Width, (int)canvas.Height));
       canvas.Arrange(new Rect(new Size((int)canvas.Width, (int)canvas.Height)));

renderBitmap.Render(canvas);

//JpegBitmapEncoder encoder = new JpegBitmapEncoder();
       PngBitmapEncoder encoder = new PngBitmapEncoder();
       encoder.Frames.Add(BitmapFrame.Create(renderBitmap));

using (FileStream file = File.Create(filename))
       {
         encoder.Save(file);
       }
     }

But that method won't work in windows store app (there is no 5 argument constructor for RenderTargetBitmap no PngBitmapEncoder). So my question is how can I save canvas from windows store app as some kind of image file (jpg, png, etc.) is there any way to do this?

Upvotes: 3

Views: 4442

Answers (3)

Tom Lever
Tom Lever

Reputation: 435

Thank you, Xyroid, for your idea and structure. To get a version of CreateSaveBitmapAsync() to work on 04/24/20, I had to replace your using block with the following. The changes of your hard-coded "96"'s, and the replacement of "bytes" with its definition, are optional.

using (Windows.Storage.Streams.IRandomAccessStream stream = await fileToWhichToSave.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
    Windows.Graphics.Imaging.BitmapEncoder encoder = await Windows.Graphics.Imaging.BitmapEncoder.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId, stream);
    encoder.SetPixelData(
        Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8,
        Windows.Graphics.Imaging.BitmapAlphaMode.Ignore,
        (uint)renderTargetBitmap.PixelWidth,
        (uint)renderTargetBitmap.PixelHeight,
        Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi,
        Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi,
        pixels.ToArray());
    await encoder.FlushAsync();
}

Upvotes: 0

Dick
Dick

Reputation: 443

I came across this reply and although it looked exactly what I was looking for it didn't work. Adding an error handler revealed:

Value does not fall within the expected range.

Finally I found that:

(uint)canvas.Width, (uint)canvas.Height,

were both 0. After replacing it with:

(uint)canvas.ActualWidth, (uint)canvas.ActualHeight,

it worked. No idea why it worked for Carlos28 and not for me, but with this change it worked for me too and so I thank Xyriod for the answer

Upvotes: 3

Farhan Ghumra
Farhan Ghumra

Reputation: 15296

Try this

using System.Runtime.InteropServices.WindowsRuntime

private async Task CreateSaveBitmapAsync(Canvas canvas)
{
    if (canvas != null)
    {
        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
        await renderTargetBitmap.RenderAsync(canvas);

        var picker = new FileSavePicker();
        picker.FileTypeChoices.Add("JPEG Image", new string[] { ".jpg" });
        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.JpegEncoderId, stream);
                byte[] bytes = pixels.ToArray();
                encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                     BitmapAlphaMode.Ignore,
                                     (uint)canvas.Width, (uint)canvas.Height,
                                     96, 96, bytes);

                await encoder.FlushAsync();
            }
        } 
    }
}

Upvotes: 6

Related Questions