Search code examples
c#xamlwindows-runtimewindows-store-appswin2d

How to save contents of CanvasControl as an image file


I'm making a paint-like program using Win2D. My CanvasControl contains some text, images and some lines which the user has drawn. I want to save the entire contents of this CanvasControl as a file on disk (in any standard image format). I want to do this as I want to display it (at a later time) inside a standard Image control.

How would I do this? I tried using RenderTargetBitmap to load the CanvasControl (code below) but for some reason it clips the image and only a small horizontal top-portion image is made.


async private void Button_Click(object sender, RoutedEventArgs e)
    {
        #region (c) rendering UIElement to bitmap code

        var bitmap = new RenderTargetBitmap();
        await bitmap.RenderAsync(ccDraw); // ccDraw is CanvasControl

        // get the pixels
        IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
        byte[] pixels = pixelBuffer.ToArray();

        // write the pixels to a InMemoryRandomAccessStream
        var stream = new InMemoryRandomAccessStream();
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96, 96, pixels);

        await encoder.FlushAsync();
        stream.Seek(0);

        Image iNew = new Image();
        iNew.Stretch = Stretch.None;
        iNew.Source = bitmap;
        gOuter.Children.Add(iNew);
        ccDraw.Visibility = Visibility.Collapsed; // hide CanvasControl so we can see added image 

     #endregion
    }

Solution

  • Here is how i did this for me. imageSize is size of your image, for example var imageSize = new Size(500,500);

    var displayInformation = DisplayInformation.GetForCurrentView();
    
    ccDraw.Measure(imageSize);
    ccDraw.UpdateLayout();
    ccDraw.Arrange(new Rect(0, 0, imageSize.Width, imageSize.Height));
    
    var renderTargetBitmap = new RenderTargetBitmap();
    await renderTargetBitmap.RenderAsync(ccDraw, Convert.ToInt32(imageSize.Width), Convert.ToInt32(imageSize.Height));
    
    var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
    var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("Screen.jpg", CreationCollisionOption.ReplaceExisting);
    using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
          var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, fileStream);
    
          encoder.SetPixelData(
                  BitmapPixelFormat.Bgra8,
                  BitmapAlphaMode.Ignore,
                  (uint)renderTargetBitmap.PixelWidth,
                  (uint)renderTargetBitmap.PixelHeight,
                  displayInformation.LogicalDpi,
                  displayInformation.LogicalDpi,
                  pixelBuffer.ToArray());
    
          await encoder.FlushAsync();
    }