简体   繁体   English

如何使用 InkCanvas 将 canvas 上完成的工作保存到 UWP C# 中的图像文件中?

[英]how to save work done on canvas using InkCanvas to an image file in UWP C#?

I want to save my work done on a canvas in my UWP app.我想在我的 UWP 应用程序中保存我在 canvas 上完成的工作。 I am using InkCanvas to draw lines on an selected image inside the canvas and I want to save the canvas work to a new image file.我正在使用 InkCanvas 在 canvas 内的选定图像上绘制线条,并且我想将 canvas 工作保存到新的图像文件中。

I am getting a blank image after trying to save the file.尝试保存文件后,我得到一个空白图像。 I've tried two approaches to save file.我尝试了两种保存文件的方法。

work done:完成工作:

xaml code xaml代码

<Button Click="ShowPopup" Content="click me"/>
<Popup x:Name="IMG_G"  Width="600" Height="300" HorizontalAlignment="Left" ManipulationMode="All">
<Grid x:Name="img_grid" Height="300" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" ManipulationMode="Scale">
      <Image VerticalAlignment="Top" HorizontalAlignment="Left"
             x:Name="img" Stretch="Fill" Height="300" ManipulationMode="All">
      </Image>
      <Canvas x:Name="selectionCanvas" Width="600" Background="Transparent" Height="300"/>
      <InkCanvas x:Name="inker" />
      <InkToolbar x:Name="img_inktoolbar" TargetInkCanvas="{x:Bind inker}" 
                  VerticalAlignment="Top">
      </InkToolbar>
</Grid>
</Popup>
<Button Content="Save"
        Width="100"
        Height="25"
        HorizontalAlignment="Center"
        VerticalAlignment="Center" Click="BtnSave_Click"/>

Code Behind代码背后

public DrawLines()
    {
        InitializeComponent();

        inker.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
        inker.InkPresenter.UnprocessedInput.PointerPressed += StartLine;
        inker.InkPresenter.UnprocessedInput.PointerMoved += ContinueLine;
        inker.InkPresenter.UnprocessedInput.PointerReleased += CompleteLine;
        inker.InkPresenter.InputProcessingConfiguration.RightDragAction = InkInputRightDragAction.LeaveUnprocessed;
    }

private async void ShowPopup(object sender, RoutedEventArgs e)
    {
        var _filePicker = new FileOpenPicker();
        _filePicker.SuggestedStartLocation = PickerLocationId.Desktop;
        _filePicker.ViewMode = PickerViewMode.Thumbnail;
        _filePicker.FileTypeFilter.Add(".bmp");
        _filePicker.FileTypeFilter.Add(".jpg");
        StorageFile _file = await _filePicker.PickSingleFileAsync();
        IRandomAccessStream imageStream = await _file.OpenAsync(FileAccessMode.Read);
        BitmapImage bmpimage = new BitmapImage();
        await bmpimage.SetSourceAsync(imageStream);
        img.Source = bmpimage;
        IMG_G.IsOpen = true;
    }

private void StartLine(InkUnprocessedInput sender, PointerEventArgs args)
    {
        line = new Line();
        line.X1 = args.CurrentPoint.RawPosition.X;
        line.Y1 = args.CurrentPoint.RawPosition.Y;
        line.X2 = args.CurrentPoint.RawPosition.X;
        line.Y2 = args.CurrentPoint.RawPosition.Y;

        line.Stroke = new SolidColorBrush(Colors.Purple);
        line.StrokeThickness = 4;
        selectionCanvas.Children.Add(line);
    }

private void ContinueLine(InkUnprocessedInput sender, PointerEventArgs args)
    {
        line.X2 = args.CurrentPoint.RawPosition.X;
        line.Y2 = args.CurrentPoint.RawPosition.Y;
    }

private void CompleteLine(InkUnprocessedInput sender, PointerEventArgs args)
    {
        List<InkPoint> points = new List<InkPoint>();
        InkStrokeBuilder builder = new InkStrokeBuilder();


        InkPoint pointOne = new InkPoint(new Point(line.X1, line.Y1), 0.5f);
        points.Add(pointOne);
        InkPoint pointTwo = new InkPoint(new Point(line.X2, line.Y2), 0.5f);
        points.Add(pointTwo);

        InkStroke stroke = builder.CreateStrokeFromInkPoints(points, System.Numerics.Matrix3x2.Identity);
        InkDrawingAttributes ida = inker.InkPresenter.CopyDefaultDrawingAttributes();
        stroke.DrawingAttributes = ida;
        inker.InkPresenter.StrokeContainer.AddStroke(stroke);
        selectionCanvas.Children.Remove(line);
    }

Approach 1 for saving the file保存文件的方法1

private async void BtnSave_Click(object sender, RoutedEventArgs e)
    {
        StorageFolder pictureFolder = KnownFolders.SavedPictures;
        var file = await pictureFolder.CreateFileAsync("test2.bmp", CreationCollisionOption.ReplaceExisting);
        CanvasDevice device = CanvasDevice.GetSharedDevice();

        CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)img.ActualWidth, (int)img.ActualHeight, 96);

        //get image's path
        StorageFolder folder = ApplicationData.Current.LocalFolder;
        //Get the same image file copy which i selected to draw on in ShowPopup() but I actually wanted to get the edited canvas
        StorageFile Ifile = await folder.GetFileAsync("Datalog_2020_09_22_10_44_59_2_3_5_RSF.bmp");
        var inputFile = Ifile.Path;

        using (var ds = renderTarget.CreateDrawingSession())
        {
            ds.Clear(Colors.White);
            CanvasBitmap image = await CanvasBitmap.LoadAsync(device, inputFile);
            //var image = img2.Source;
            // I want to use this too, but I have no idea about this

            ds.DrawImage(image);
            ds.DrawInk(inker.InkPresenter.StrokeContainer.GetStrokes());
        }
        // save results           

        using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Jpeg, 1f);
        }
    }

Results结果

desired result期望的结果

Note: Arrow is drawn by me on the image注意:箭头是我在图片上绘制的期望的结果

Result I am getting with this approach结果我用这种方法得到

test2.bmp (image is getting zoomed in for some reason) test2.bmp(图像由于某种原因被放大)

测试2.bmp

Approach 2 for saving the file保存文件的方法2

private async void BtnSave_Click(object sender, RoutedEventArgs e)
    {
        RenderTargetBitmap bitmap = new RenderTargetBitmap();
        await bitmap.RenderAsync(selectionCanvas);
        Debug.WriteLine($"Capacity = {(uint)bitmap.PixelWidth}, Length={(uint)bitmap.PixelHeight}");
        var pixelBuffer = await bitmap.GetPixelsAsync();
        Debug.WriteLine($"Capacity = {pixelBuffer.Capacity}, Length={pixelBuffer.Length}");
        byte[] pixels = pixelBuffer.ToArray();
        var displayInformation = DisplayInformation.GetForCurrentView();
        StorageFolder pictureFolder = KnownFolders.SavedPictures;
        var file = await pictureFolder.CreateFileAsync("test2.bmp", CreationCollisionOption.ReplaceExisting);
        using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
            encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                 BitmapAlphaMode.Ignore,
                                 (uint)bitmap.PixelWidth,
                                 (uint)bitmap.PixelHeight,
                                 displayInformation.RawDpiX,
                                 displayInformation.RawDpiY,
                                 pixels);
            await encoder.FlushAsync();
        }
    }

Result with this approach这种方法的结果

For some reason I am getting all black image出于某种原因,我得到全黑图像

test2.bmp测试2.bmp

全黑图像

Any help will be apppreciated.任何帮助将不胜感激。 Any help with approach 2 will be better.方法2的任何帮助都会更好。

how to save work done on canvas using InkCanvas to an image file in UWP C#?如何使用 InkCanvas 将 canvas 上完成的工作保存到 UWP C# 中的图像文件中?

You have no need use RenderTargetBitmap to save InkCanvas to image.您无需使用RenderTargetBitmap将 InkCanvas 保存到图像。 UWP InkCanvas has SaveAsync method that could save the StrokeContainer stream to image file directly. UWP InkCanvas具有 SaveAsync 方法,可以将StrokeContainer stream 直接保存到图像文件中。 For example.例如。

async void OnSaveAsync(object sender, RoutedEventArgs e)
{
    // We don't want to save an empty file
    if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
    {
        var savePicker = new FileSavePicker();
        savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
        savePicker.FileTypeChoices.Add("png with embedded ISF", new[] { ".png" });

        StorageFile file = await savePicker.PickSaveFileAsync();
        if (null != file)
        {
            try
            {
                using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    // Truncate any existing stream in case the new file
                    // is smaller than the old file.
                    stream.Size = 0;
                    await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
                }
                
            }
            catch (Exception ex)
            {
             
            }
        }
    }
    else
    {
     
    }
}

For more detail please refer UWP simple ink code sample scenario 3更多详情请参考 UWP 简单墨水代码示例场景3

Update更新

I am getting a blank image after trying to save the file.尝试保存文件后,我得到一个空白图像。

Above code can only save InkCanvas stroke, I checked your code, I found you have not place any element in the selectionCanvas .上面的代码只能保存InkCanvas笔画,我检查了你的代码,我发现你没有在selectionCanvas中放置任何元素。 so the RenderTargetBitmap of selectionCanvas will black empty.所以selectionCanvasRenderTargetBitmap将变黑为空。 Please try to use img_grid to replace.请尝试使用img_grid替换。

Hey sorry but now the InkToolbar is also getting copied on the image along with the ink changes i make:(嘿抱歉,但现在 InkToolbar 也与我所做的墨水更改一起被复制到图像上:(

It's by-design, RenderTargetBitmap will render all element that was viewed, for your scenario, we suggest you make rectangle to covered InkToolbar or set img_inktoolbar Visibility as Collapsed, before you capture the screen and reset it after finish.这是设计使然, RenderTargetBitmap将渲染所有查看过的元素,对于您的场景,我们建议您制作矩形覆盖InkToolbar或将 img_inktoolbar Visibility 设置为 Collapsed,然后再捕获屏幕并在完成后重置它。

I made some changes in approach 2 and got the desired result我对方法 2 进行了一些更改并得到了预期的结果

Approach 2 for saving the file保存文件的方法2

private async void BtnSave_Click(object sender, RoutedEventArgs e)
{
    // In order to hide the InkToolbar before the saving the image
    img_inktoolbar.Visibility = Visibility.Collapsed;

    RenderTargetBitmap bitmap = new RenderTargetBitmap();
    await bitmap.RenderAsync(img_grid);
    Debug.WriteLine($"Capacity = {(uint)bitmap.PixelWidth}, Length={(uint)bitmap.PixelHeight}");
    var pixelBuffer = await bitmap.GetPixelsAsync();
    Debug.WriteLine($"Capacity = {pixelBuffer.Capacity}, Length={pixelBuffer.Length}");
    byte[] pixels = pixelBuffer.ToArray();
    var displayInformation = DisplayInformation.GetForCurrentView();
    StorageFolder pictureFolder = KnownFolders.SavedPictures;
    var file = await pictureFolder.CreateFileAsync("test2.bmp", CreationCollisionOption.ReplaceExisting);
    using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                             BitmapAlphaMode.Ignore,
                             (uint)bitmap.PixelWidth,
                             (uint)bitmap.PixelHeight,
                             displayInformation.RawDpiX,
                             displayInformation.RawDpiY,
                             pixels);
        await encoder.FlushAsync();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM