I have to capture a photo with camera or loading it from file into a canvas which should be edited for highlighting some stuff on it after that saved into a folder.
As for now I use this:
<Grid x:Name="grid">
<Image Source="/Assets/stainless-images-110606.jpg" x:Name="ImageToEdit" Stretch="Uniform" />
<StackPanel Background="LightGreen" Width="700" Height="700" x:Name="StackPanel">
<InkCanvas x:Name="MyInkCanvas" Width="{Binding Width, ElementName=StackPanel}" Height="{Binding Height, ElementName=StackPanel}"/>
</StackPanel>
<InkToolbar TargetInkCanvas="{x:Bind MyInkCanvas}" Name="inkToolbar"/>
<Button Content="Save" Click="Button_Click" HorizontalAlignment="Right"/>
</Grid>
And this is how I get the whole stuff from xaml:
public static async Task<IRandomAccessStream> RenderToRandomAccessStream(this UIElement element)
{
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(element);
var pixelBuffer = await rtb.GetPixelsAsync();
var pixels = pixelBuffer.ToArray();
// Useful for rendering in the correct DPI
var displayInformation = DisplayInformation.GetForCurrentView();
var stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)rtb.PixelWidth,
(uint)rtb.PixelHeight,
displayInformation.RawDpiX,
displayInformation.RawDpiY,
pixels);
await encoder.FlushAsync();
stream.Seek(0);
return stream;
}
When I capture the photo from camera I set the image source to photo, but when saving the whole stuff it saves only the photo and not the strokes from canvas. My assumption is that I have to somehow attach the stream got from camera to inkCanvas.
According to the "XAML visuals and RenderTargetBitmap capture capabilities" of RenderTargetBitmap
class:
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. And it seems like there is no APIs can directly capture a InkCanvas
with an image attached at the same time. But you can use Win2D. More details please reference this thread.
You could use DrawImage
method combined the DrawInk
method to draw them both on CanvasDevice
, then can save the photo and strokes together. For example:
<StackPanel Padding="30" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Image
x:Name="imgbackground"
Source="/Assets/ob_0_0.png"
Stretch="None" />
<InkCanvas x:Name="ink" />
</Grid>
<StackPanel Orientation="Horizontal">
<Button
x:Name="btnUpdate"
Margin="10"
Click="btnUpdate_Click"
Content="update ink size, click me firstly" />
<Button
Margin="10"
Click="BtnSave_Click"
Content="Save" />
</StackPanel>
</StackPanel>
Code behind:
BitmapImage inkimage;
public MainPage()
{
this.InitializeComponent();
ink.InkPresenter.InputDeviceTypes = Windows.UI.Core.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)
{
StorageFile inputFile = await StorageFile.GetFileFromApplicationUriAsync(inkimage.UriSource);
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)ink.ActualWidth, (int)ink.ActualHeight, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
ds.Clear(Colors.White);
var image = await CanvasBitmap.LoadAsync(device, inputFile.Path, 96);
ds.DrawImage(image);// Draw image firstly
ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());// Draw the stokes
}
//Save them to the output.jpg in picture folder
StorageFolder storageFolder = KnownFolders.SavedPictures;
var file = await storageFolder.CreateFileAsync("output.jpg", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Jpeg, 1f);
}
}
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
//Get the image source that for attaching to the inkcanvas, update the inkcanvas to be same size with image.
inkimage = (BitmapImage)imgbackground.Source;
var imagewidth = inkimage.PixelWidth;
var imageheight = inkimage.PixelWidth;
ink.Height = imageheight;
ink.Width = imagewidth;
ink.UpdateLayout();
}