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

如何将使用InkCanvas在画布上完成的工作保存到UWP C#中的图像文件?,c#,canvas,uwp-xaml,xamarin.uwp,inkcanvas,C#,Canvas,Uwp Xaml,Xamarin.uwp,Inkcanvas,我想在UWP应用程序中保存在画布上完成的工作。我正在使用InkCanvas在画布内的选定图像上绘制线条,我想将画布作品保存到一个新的图像文件中 尝试保存文件后,我得到一个空白图像。我尝试了两种保存文件的方法 已完成的工作: xaml代码 <Button Click="ShowPopup" Content="click me"/> <Popup x:Name="IMG_G" Width="600"

我想在UWP应用程序中保存在画布上完成的工作。我正在使用InkCanvas在画布内的选定图像上绘制线条,我想将画布作品保存到一个新的图像文件中

尝试保存文件后,我得到一个空白图像。我尝试了两种保存文件的方法

已完成的工作:

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"/>
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);
        }
    }
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();
        }
    }
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();
    }
}
结果

期望结果

注:箭头由我在图像上绘制

我用这种方法得到的结果

test2.bmp(图像由于某种原因被放大)

保存文件的方法2

<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"/>
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);
        }
    }
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();
        }
    }
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();
    }
}
此方法的结果

由于某种原因,我得到了全黑的图像

test2.bmp

任何帮助都将被请求。方法2的任何帮助都会更好

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

无需使用
RenderTargetBitmap
将InkCanvas保存到图像。UWP具有SaveAsync方法,可以将流直接保存到图像文件。比如说

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
    {
     
    }
}
有关更多详细信息,请参考UWP代码示例场景3

更新

<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"/>
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);
        }
    }
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();
        }
    }
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();
    }
}
尝试保存文件后,我得到一个空白图像

上面的代码只能保存
InkCanvas
笔划,我检查了您的代码,发现您没有在
selectionCanvas
中放置任何元素。因此
selectionCanvas
RenderTargetBitmap
将为黑色空。请尝试使用
img\u网格
替换

嘿,抱歉,但是现在InkToolbar也被复制到图像上,以及我所做的墨迹更改:(


根据设计,
RenderTargetBitmap
将渲染所有已查看的元素,对于您的场景,我们建议您在捕获屏幕并在完成后重置之前,将矩形设置为覆盖
InkToolbar
或将img\u InkToolbar可见性设置为折叠。

我在方法2中做了一些更改,并获得了预期的结果

保存文件的方法2

<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"/>
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);
        }
    }
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();
        }
    }
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();
    }
}

您好,谢谢您的时间。我尝试过使用
inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
但我得到的只是墨迹笔划和图像的所有传输,也就是说,我得到的只是墨迹笔划而已,没有图像背景