Universal Windows InkCanvas strokes disappear on R

2019-02-25 03:05发布

问题:

I try to render the strokes of a InkCanvas to a RenderTargetBitmap in a windows 10 universal App. Here is my xaml code:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="10" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid x:Name="container">
        <Rectangle Fill="LightBlue" />
        <InkCanvas x:Name="InkCanvas" />
    </Grid>

    <Image Grid.Row="2" x:Name="TheImage" />

    <Button Grid.Row="3" Content="CopyToRendertargt" Click="Button_Click" />

</Grid>

And here is my code to set the Image.Source property:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        InkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse;
    }


    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        RenderTargetBitmap renderTarget = new RenderTargetBitmap();

        await renderTarget.RenderAsync(this.container);

        this.TheImage.Source = renderTarget;
    }

}

When i click to button the strokes i made on the InkCanvas disappear and the InkCanvas is forzen until i resize the app window. The strokes are not getting rendered to the RenderTargetBitmap. The Image shows just the LightBlue Rectangle.

Does sombody have a solution for this?

** UPDATE **

For those who are searching for the right way to save strokes to a bitmap on uwp. I found the UWP-way of saving InkCanvas Strokes to a Bitmap: The InkStrokeContainer Object has a method called SaveAsync(...) which saves the strokes to a stream. If you use this stream as source for a Bitmap you get the strokes as Bitmap.

        InkStrokeContainer container = TheInkCanvas.InkPresenter.StrokeContainer;
        WriteableBitmap bmp;
        using (InMemoryRandomAccessStream ims =
            new InMemoryRandomAccessStream())
        {
            await container.SaveAsync(ims);
            bmp = await new WriteableBitmap(1, 1)
                .FromStream(ims, BitmapPixelFormat.Bgra8);
        }

*Note: WriteableBitmapEx is used in this sample code (https://www.nuget.org/packages/WriteableBitmapEx/)

回答1:

In the XAML visuals and RenderTargetBitmap section in the RenderTargetBitmap documentation, it describes: Content that can't be captured will appear as blank in the captured image, but other content in the same visual tree can still be captured and will render (the presence of content that can't be captured won't invalidate the entire capture of that XAML composition).So it could be that the content of InkCanvas is not captureable.

An alternative is to use Win2D (Direct2D .NET wrapper from Microsoft). Win2D can be used in an UWP app via a nuget package. You will be able to manage the ink strokes and save them to image (jpeg, png, and other formats).



回答2:

You can use Win2D to render the Ink Strokes.

  1. Add Win2D.uwp to the project from NuGet
  2. Add this InkCanvasExtensions.cs file to your project
  3. Change the namespace or add using Zoetrope; to your source
  4. Create an image file or stream and pass it to the InkCanvas.RenderAsync()

InkCanvasExtensions.cs

namespace Zoetrope
{
    using System;
    using System.Threading.Tasks;
    using Microsoft.Graphics.Canvas;
    using Windows.Graphics.Display;
    using Windows.Storage.Streams;
    using Windows.UI;
    using Windows.UI.Xaml.Controls;

    /// <summary>
    /// InkCanvas Extensions
    /// </summary>
    public static class InkCanvasExtensions
    {
        /// <summary>
        /// Render an InkCanvas to a stream
        /// </summary>
        /// <param name="inkCanvas">the ink canvas</param>
        /// <param name="fileStream">the file stream</param>
        /// <param name="backgroundColor">the background color</param>
        /// <param name="fileFormat">the file format</param>
        /// <returns>an async task</returns>
        public static async Task RenderAsync(
            this InkCanvas inkCanvas, 
            IRandomAccessStream fileStream, 
            Color backgroundColor,
            CanvasBitmapFileFormat fileFormat)
        {
            // do not put in using{} structure - it will close the shared device.
            var device = CanvasDevice.GetSharedDevice();
            var width = (float) inkCanvas.ActualWidth;
            var height = (float) inkCanvas.ActualHeight;
            var currentDpi = DisplayInformation.GetForCurrentView().LogicalDpi;

            using (var offscreen = new CanvasRenderTarget(device, width, height, currentDpi))
            {
                using (var session = offscreen.CreateDrawingSession())
                {
                    session.Clear(backgroundColor);

                    session.DrawInk(inkCanvas.InkPresenter.StrokeContainer.GetStrokes());
                }

                await offscreen.SaveAsync(fileStream, fileFormat);
            }
        }
    }
}