Capturing ink data complete code (XAML)
This topic provides the complete code sample used in Quickstart: Capturing ink data.
This topic contains these sections:
- Technologies
- Requirements
- View the code ()
Download location
This sample is not available for download.
Technologies
Programming languages | C#, XAML |
Programming models | Windows Runtime |
Requirements
Minimum supported client | Windows 8 |
Minimum supported server | Windows Server 2012 |
Minimum required SDK | Microsoft Visual Studio Express 2012 for Windows 8 |
View the code ()
InkPage.xaml
<Page
x:Class="CaptureInkData.InkPage"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CaptureInkData"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Page title -->
<Grid x:Name="titlePanel">
<TextBlock x:Name="pageTitle" Text="Capturing ink data" Style="{StaticResource HeaderTextBlockStyle}" Margin="62,0,0,40"/>
</Grid>
<!-- Inking area -->
<Grid x:Name="inkPanel" Grid.Row="1" Margin="0,0,0,61">
<Canvas x:Name="InkCanvas" Background="White" Margin="62,0,62,10" />
</Grid>
</Grid>
</Page>
InkPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Input.Inking;
using Windows.Devices.Input;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Xaml.Shapes;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace CaptureInkData
{
public sealed partial class InkPage : Page
{
InkPage rootPage = null;
// Scenario specific constants and variables.
const double STROKETHICKNESS = 5;
Point _previousContactPt;
uint _penID = 0;
uint _touchID = 0;
// Create the InkManager instance.
InkManager _inkManager = new Windows.UI.Input.Inking.InkManager();
public InkPage()
{
this.InitializeComponent();
// Add pointer event handlers to the Canvas object.
InkCanvas.PointerPressed += new PointerEventHandler(InkCanvas_PointerPressed);
InkCanvas.PointerMoved += new PointerEventHandler(InkCanvas_PointerMoved);
InkCanvas.PointerReleased += new PointerEventHandler(InkCanvas_PointerReleased);
InkCanvas.PointerExited += new PointerEventHandler(InkCanvas_PointerReleased);
}
// Initiate ink capture.
public void InkCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Get information about the pointer location.
PointerPoint pt = e.GetCurrentPoint(InkCanvas);
_previousContactPt = pt.Position;
// Accept input only from a pen or mouse with the left button pressed.
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen ||
pointerDevType == PointerDeviceType.Mouse &&
pt.Properties.IsLeftButtonPressed)
{
// Pass the pointer information to the InkManager.
_inkManager.ProcessPointerDown(pt);
_penID = pt.PointerId;
e.Handled = true;
}
else if (pointerDevType == PointerDeviceType.Touch)
{
// Process touch input
}
}
// Draw on the canvas and capture ink data as the pointer moves.
public void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == _penID)
{
PointerPoint pt = e.GetCurrentPoint(InkCanvas);
// Render a red line on the canvas as the pointer moves.
// Distance() is an application-defined function that tests
// whether the pointer has moved far enough to justify
// drawing a new line.
Point currentContactPt = pt.Position;
if (Distance(currentContactPt, _previousContactPt) > 2)
{
Line line = new Line()
{
X1 = _previousContactPt.X,
Y1 = _previousContactPt.Y,
X2 = currentContactPt.X,
Y2 = currentContactPt.Y,
StrokeThickness = STROKETHICKNESS,
Stroke = new SolidColorBrush(Windows.UI.Colors.Red)
};
_previousContactPt = currentContactPt;
// Draw the line on the canvas by adding the Line object as
// a child of the Canvas object.
InkCanvas.Children.Add(line);
// Pass the pointer information to the InkManager.
_inkManager.ProcessPointerUpdate(pt);
}
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
e.Handled = true;
}
// Finish capturing ink data and use it to render ink strokes on
// the canvas.
public void InkCanvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == _penID)
{
PointerPoint pt = e.GetCurrentPoint(InkCanvas);
// Pass the pointer information to the InkManager.
_inkManager.ProcessPointerUp(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
_touchID = 0;
_penID = 0;
// Call an application-defined function to render the ink strokes.
RenderAllStrokes();
e.Handled = true;
}
// Render ink strokes as cubic bezier segments.
private void RenderAllStrokes()
{
// Clear the canvas.
InkCanvas.Children.Clear();
// Get the InkStroke objects.
IReadOnlyList<InkStroke> inkStrokes = _inkManager.GetStrokes();
// Process each stroke.
foreach (InkStroke inkStroke in inkStrokes)
{
PathGeometry pathGeometry = new PathGeometry();
PathFigureCollection pathFigures = new PathFigureCollection();
PathFigure pathFigure = new PathFigure();
PathSegmentCollection pathSegments = new PathSegmentCollection();
// Create a path and define its attributes.
Windows.UI.Xaml.Shapes.Path path = new Windows.UI.Xaml.Shapes.Path();
path.Stroke = new SolidColorBrush(Colors.Red);
path.StrokeThickness = STROKETHICKNESS;
// Get the stroke segments.
IReadOnlyList<InkStrokeRenderingSegment> segments;
segments = inkStroke.GetRenderingSegments();
// Process each stroke segment.
bool first = true;
foreach (InkStrokeRenderingSegment segment in segments)
{
// The first segment is the starting point for the path.
if (first)
{
pathFigure.StartPoint = segment.BezierControlPoint1;
first = false;
}
// Copy each ink segment into a bezier segment.
BezierSegment bezSegment = new BezierSegment();
bezSegment.Point1 = segment.BezierControlPoint1;
bezSegment.Point2 = segment.BezierControlPoint2;
bezSegment.Point3 = segment.Position;
// Add the bezier segment to the path.
pathSegments.Add(bezSegment);
}
// Build the path geometerty object.
pathFigure.Segments = pathSegments;
pathFigures.Add(pathFigure);
pathGeometry.Figures = pathFigures;
// Assign the path geometry object as the path data.
path.Data = pathGeometry;
// Render the path by adding it as a child of the Canvas object.
InkCanvas.Children.Add(path);
}
}
private double Distance(Point currentContact, Point previousContact)
{
return Math.Sqrt(Math.Pow(currentContact.X - previousContact.X, 2) +
Math.Pow(currentContact.Y - previousContact.Y, 2));
}
#region Template-Related Code - Do not remove
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Get a pointer to our main page
rootPage = e.Parameter as InkPage;
}
#endregion
/// <summary>
/// Handles when the Save button is clicked on the app bar.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
///
async void Save_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("GIF file", new List<string>() { ".gif" });
savePicker.DefaultFileExtension = ".gif";
savePicker.SuggestedFileName = "New Ink Image";
StorageFile savedItem = await savePicker.PickSaveFileAsync();
if (null != savedItem)
{
WriteInk(savedItem);
}
}
async void WriteInk(StorageFile storageFile)
{
if (storageFile != null)
{
IRandomAccessStream writeStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream outputStream = writeStream.GetOutputStreamAt(0);
await _inkManager.SaveAsync(outputStream);
await outputStream.FlushAsync();
Windows.Storage.FileProperties.BasicProperties props = await storageFile.GetBasicPropertiesAsync();
// Call an application-defined function to display the file size.
DisplayStatus("Saved " + props.Size.ToString() + " bytes.");
}
}
async void Load_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.List;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Clear();
openPicker.FileTypeFilter.Add(".gif");
StorageFile openedItem = await openPicker.PickSingleFileAsync();
if (null != openedItem)
{
ReadInk(openedItem);
}
}
async void ReadInk(StorageFile storageFile)
{
if (storageFile != null)
{
IRandomAccessStream readStream = await storageFile.OpenAsync(FileAccessMode.Read);
IInputStream inputStream = readStream.GetInputStreamAt(0);
await _inkManager.LoadAsync(inputStream);
IReadOnlyList<InkStroke> strokes = _inkManager.GetStrokes();
int c = strokes.Count;
if (c == 0)
{
DisplayStatus("File does not contain any ink strokes.");
}
else
{
DisplayStatus("Loaded " + c + " strokes.");
RenderAllStrokes();
}
Windows.Storage.FileProperties.BasicProperties props = await storageFile.GetBasicPropertiesAsync();
// Call an application-defined function to display the file size.
DisplayStatus("Loaded " + props.Size.ToString() + " bytes.");
}
}
async void DisplayStatus(String message)
{
Windows.UI.Popups.MessageDialog messagePopup = new Windows.UI.Popups.MessageDialog(message, "Status");
await messagePopup.ShowAsync();
}
}
}