I have an InkCanvas in my UWP app, and would like to display an image (ideally as part of the Canvas, but otherwise, overlay it in some way (the idea being that I can save the changed image back to the image file). WPF seems to allow the InkCanvas to have children, but in UWP that doesn't seem to be possible. I've tried the following:
<InkCanvas x:Name="drawInkCanvas">
<Image Source="{Binding DrawingImage}"/>
</InkCanvas>
But that doesn't work; I've also tried this:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<InkCanvas x:Name="drawInkCanvas" Opacity=".5"/>
<Image Source="{Binding DrawingImage}" Opacity=".5"/>
</Canvas>
Which, to be fair, I didn't have very high hopes for; anyway, although it does, kind of work, it makes both the image and the InkCanvas look wrong and, obviously, doesn't allow me to save the resulting image.
Ideally, there would be a background image or something similar. Is there anything that I can use to achieve this; I'm approaching the opinion that I may have to replace the InkCanvas with a standard canvas and then re-write all the InkCanvas functionality!
So you have couple of problems:
InkCanvas
over Image
control.I'll use simple UWP app in this example, which assumes that you have "sample.jpg" file in your Assets folder, and you have "Pictures Library" capability in your manifest.
To solve first problem, just put both InkCanvas
and Image
into same container (like Grid
), but remember that order matters:
<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>
If you put InkCanvas
first (like you did in question example) - it won't work. However if put InkCanvas
last - all works fine and you can draw over your image.
Now to solve second problem you need to use Win2D (install nuget Win2D.uwp package), because standard RenderTargetBitmap
won't render InkCanvas
contents. First draw your original image (take image from original source directly, that is from original file for example), then draw contents of your ink canvas over it. Full code of MainPage (if you add xaml above you will have complete working sample):
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With