在 UWP 墨水上显示背景图像 canvas
Displaying a background image on a UWP ink canvas
我的 UWP 应用程序中有一个 InkCanvas,并且想要显示图像(理想情况下作为 Canvas 的一部分,但除此之外,以某种方式覆盖它(想法是我可以将更改后的图像保存回图像文件。WPF 似乎允许 InkCanvas 具有 children,但在 UWP 中这似乎是不可能的。我试过了以下:
<InkCanvas x:Name="drawInkCanvas">
<Image Source="{Binding DrawingImage}"/>
</InkCanvas>
但这行不通;我也试过这个:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<InkCanvas x:Name="drawInkCanvas" Opacity=".5"/>
<Image Source="{Binding DrawingImage}" Opacity=".5"/>
</Canvas>
老实说,我并没有抱太大希望;无论如何,虽然它确实有点工作,但它使图像和 InkCanvas 看起来都不对,而且显然不允许我保存生成的图像。
理想情况下,应该有背景图片或类似的东西。有什么我可以用来实现这个目标的吗?我正在接近我可能必须用标准 canvas 替换 InkCanvas 的意见,然后 re-write 所有 InkCanvas 功能!
所以你有几个问题:
- 如何在
Image
控件上使用 InkCanvas
进行绘制。
- 如何将结果保存到文件中。
我将在此示例中使用简单的 UWP 应用程序,它假设您的资产文件夹中有 "sample.jpg" 文件,并且您的清单中有 "Pictures Library" 功能。
要解决第一个问题,只需将 InkCanvas
和 Image
放入同一个容器中(如 Grid
),但请记住 顺序很重要:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Image Source="/Assets/sample.jpg"></Image>
<InkCanvas x:Name="ink"></InkCanvas>
</Grid>
<Button Content="Save"
Width="100"
Height="25"
HorizontalAlignment="Center"
VerticalAlignment="Center" Click="BtnSave_Click"/>
</StackPanel>
如果您将 InkCanvas
放在首位(就像您在问题示例中所做的那样)- 它不会起作用。但是,如果将 InkCanvas
放在最后 - 一切正常,您可以绘制图像。
现在要解决第二个问题,您需要使用 Win2D(安装 nuget Win2D.uwp 包),因为标准 RenderTargetBitmap
不会呈现 InkCanvas
内容。首先绘制原始图像(直接从原始来源获取图像,例如从原始文件中获取图像),然后在其上绘制墨水 canvas 的内容。 MainPage 的完整代码(如果您在上面添加 xaml,您将获得完整的工作示例):
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
// just set some properties of ink canvas, not directly relevant to your question
ink.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
var attr = new InkDrawingAttributes();
attr.Color = Colors.Red;
attr.IgnorePressure = true;
attr.PenTip = PenTipShape.Circle;
attr.Size = new Size(4, 10);
ink.InkPresenter.UpdateDefaultDrawingAttributes(attr);
}
private async void BtnSave_Click(object sender, RoutedEventArgs e) {
// grab output file
StorageFolder storageFolder = KnownFolders.SavedPictures;
var file = await storageFolder.CreateFileAsync("output.jpg", CreationCollisionOption.ReplaceExisting);
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int) ink.ActualWidth, (int) ink.ActualHeight, 96);
// grab your input file from Assets folder
StorageFolder appInstalledFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder assets = await appInstalledFolder.GetFolderAsync("Assets");
var inputFile = await assets.GetFileAsync("sample.jpg");
using (var ds = renderTarget.CreateDrawingSession()) {
ds.Clear(Colors.White);
var image = await CanvasBitmap.LoadAsync(device, inputFile.Path);
// draw your image first
ds.DrawImage(image);
// then draw contents of your ink canvas over it
ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
}
// save results
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite)) {
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Jpeg, 1f);
}
}
}
我的 UWP 应用程序中有一个 InkCanvas,并且想要显示图像(理想情况下作为 Canvas 的一部分,但除此之外,以某种方式覆盖它(想法是我可以将更改后的图像保存回图像文件。WPF 似乎允许 InkCanvas 具有 children,但在 UWP 中这似乎是不可能的。我试过了以下:
<InkCanvas x:Name="drawInkCanvas">
<Image Source="{Binding DrawingImage}"/>
</InkCanvas>
但这行不通;我也试过这个:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<InkCanvas x:Name="drawInkCanvas" Opacity=".5"/>
<Image Source="{Binding DrawingImage}" Opacity=".5"/>
</Canvas>
老实说,我并没有抱太大希望;无论如何,虽然它确实有点工作,但它使图像和 InkCanvas 看起来都不对,而且显然不允许我保存生成的图像。
理想情况下,应该有背景图片或类似的东西。有什么我可以用来实现这个目标的吗?我正在接近我可能必须用标准 canvas 替换 InkCanvas 的意见,然后 re-write 所有 InkCanvas 功能!
所以你有几个问题:
- 如何在
Image
控件上使用InkCanvas
进行绘制。 - 如何将结果保存到文件中。
我将在此示例中使用简单的 UWP 应用程序,它假设您的资产文件夹中有 "sample.jpg" 文件,并且您的清单中有 "Pictures Library" 功能。
要解决第一个问题,只需将 InkCanvas
和 Image
放入同一个容器中(如 Grid
),但请记住 顺序很重要:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Image Source="/Assets/sample.jpg"></Image>
<InkCanvas x:Name="ink"></InkCanvas>
</Grid>
<Button Content="Save"
Width="100"
Height="25"
HorizontalAlignment="Center"
VerticalAlignment="Center" Click="BtnSave_Click"/>
</StackPanel>
如果您将 InkCanvas
放在首位(就像您在问题示例中所做的那样)- 它不会起作用。但是,如果将 InkCanvas
放在最后 - 一切正常,您可以绘制图像。
现在要解决第二个问题,您需要使用 Win2D(安装 nuget Win2D.uwp 包),因为标准 RenderTargetBitmap
不会呈现 InkCanvas
内容。首先绘制原始图像(直接从原始来源获取图像,例如从原始文件中获取图像),然后在其上绘制墨水 canvas 的内容。 MainPage 的完整代码(如果您在上面添加 xaml,您将获得完整的工作示例):
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
// just set some properties of ink canvas, not directly relevant to your question
ink.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
var attr = new InkDrawingAttributes();
attr.Color = Colors.Red;
attr.IgnorePressure = true;
attr.PenTip = PenTipShape.Circle;
attr.Size = new Size(4, 10);
ink.InkPresenter.UpdateDefaultDrawingAttributes(attr);
}
private async void BtnSave_Click(object sender, RoutedEventArgs e) {
// grab output file
StorageFolder storageFolder = KnownFolders.SavedPictures;
var file = await storageFolder.CreateFileAsync("output.jpg", CreationCollisionOption.ReplaceExisting);
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int) ink.ActualWidth, (int) ink.ActualHeight, 96);
// grab your input file from Assets folder
StorageFolder appInstalledFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder assets = await appInstalledFolder.GetFolderAsync("Assets");
var inputFile = await assets.GetFileAsync("sample.jpg");
using (var ds = renderTarget.CreateDrawingSession()) {
ds.Clear(Colors.White);
var image = await CanvasBitmap.LoadAsync(device, inputFile.Path);
// draw your image first
ds.DrawImage(image);
// then draw contents of your ink canvas over it
ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
}
// save results
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite)) {
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Jpeg, 1f);
}
}
}