教程:在 Windows 应用中支持墨迹

Surface 触控笔英雄图像。
Surface 触控笔(可在 Microsoft Store 购买)。

本教程分步介绍如何创建一个支持使用 Windows Ink 进行写作和绘画的基本 Windows 应用。 我们使用示例应用中的代码片段(可从 GitHub 下载)(请参阅示例代码),以演示每个步骤中讨论的各种功能和关联的 Windows Ink API(请参阅 Windows Ink 平台的组件)。

重点关注以下内容:

  • 添加基本墨迹支持
  • 添加墨迹工具栏
  • 支持笔迹识别
  • 支持基本形状识别
  • 保存和加载墨迹

有关实现这些功能的更多详细信息,请参阅 Windows 应用中的笔交互和 Windows Ink

介绍

对于你可以想象到的几乎任何纸笔能提供的体验,从快速手写笔记和批注到白板演示,以及从建筑和工程绘图到个人创作,借助 Windows Ink 都可以为客户提供同等的数字体验。

先决条件

注意

虽然 Windows Ink 支持使用鼠标和触摸绘图(我们在本教程的步骤 3 中演示了如何执行此操作),但我们建议你准备一支数字笔和一台支持数字笔输入的带显示器的计算机。

代码示例

在本教程中,我们使用示例墨迹应用来演示所讨论的概念和功能。

GitHubwindows-appsample-get-started-ink 示例下载此 Visual Studio 示例和源代码:

  1. 选择绿色的“克隆或下载”按钮
    克隆存储库。
  2. 如果你有 GitHub 帐户,则可以选择“在 Visual Studio 中打开”,将存储库克隆到本地计算机。
  3. 如果你没有 GitHub 帐户,或者只是想要项目的本地副本,则选择“下载 ZIP”(你需要以后定期查看以下载最新的更新)

重要

示例中的大部分代码都会注释掉。当我们完成每个步骤时,系统会要求你取消注释代码的各个部分。 在 Visual Studio 中,只需突出显示代码行,然后按 Ctrl-K,然后按 Ctrl-U。

Windows Ink 平台的组件

这些对象提供 Windows 应用的大部分墨迹书写体验。

组件 说明
InkCanvas 默认情况下,XAML UI 平台控件接收来自笔的所有输入并将其显示为墨迹笔划或擦除笔划。
InkPresenter 代码隐藏对象,与 InkCanvas 控件一起实例化(通过 InkCanvas.InkPresenter 属性公开)。 此对象提供 InkCanvas 公开的所有默认墨迹书写功能以及适用于其他自定义和个性化的完整 API 集。
InkToolbar XAML UI 控件,包含一组可自定义和可扩展按钮,这些按钮用于在关联 InkCanvas 中激活与墨迹相关的功能。
IInkD2DRenderer
此处未介绍此功能,有关详细信息,请参阅复杂墨迹示例
支持将墨迹笔划呈现到通用 Windows 应用的指定 Direct2D 设备上下文,而不是默认的 InkCanvas 控件。

步骤 1:运行示例

下载 RadialController 示例应用后,请验证它是否运行:

  1. 在 Visual Studio 中打开示例项目。

  2. 将“解决方案平台”下拉列表设置为非 Arm 选择。

  3. 按 F5 编译、部署并运行。

    注意

    或者,可以选择“调试”>“开始调试”菜单项,或选择此处显示的“本地计算机”运行按钮。 Visual Studio 生成项目按钮。

应用窗口随即打开,初始屏幕显示几秒钟后,你将看到这个最先出现的屏幕。

空应用的屏幕截图。

好了,现在我们有了基本的 Windows 应用,在本教程接下来的所有部分我们都会用到它。 在以下步骤中,我们将添加墨迹功能。

步骤 2:使用 InkCanvas 支持基本墨迹书写

也许你可能已经注意到,应用在初始表单中不会让你使用笔绘制任何内容(尽管你可以使用笔作为标准指针设备来与应用交互)。

我们来修复此步骤中的小缺点。

若要添加基本的墨迹书写功能,只需将 InkCanvas 控件放在应用的相应页面上。

注意

InkCanvas 的默认 HeightWidth 属性为零,除非它是自动调整其子元素大小的元素的子项。

在此例中:

  1. 打开 MainPage.xaml.cs 文件。
  2. 找到标有此步骤标题的代码 ("// Step 2: Use InkCanvas to support basic inking")。
  3. 取消注释以下行。 (后续步骤中使用的功能需要这些引用)。
    using Windows.UI.Input.Inking;
    using Windows.UI.Input.Inking.Analysis;
    using Windows.UI.Xaml.Shapes;
    using Windows.Storage.Streams;
  1. 打开 MainPage.xaml 文件。
  2. 找到标有此步骤标题的代码 ("<!-- Step 2: Basic inking with InkCanvas -->")。
  3. 取消注释以下行。
    <InkCanvas x:Name="inkCanvas" />

就这么简单!

然后,再次运行应用。 继续写字,写你的名字,或者(如果你拿着一面镜子或有非常好的记忆),绘制你的自画像。

本主题中突出显示的基本墨迹示例应用的屏幕截图。

步骤 3:支持使用触摸和鼠标进行墨迹书写

你会注意到,默认情况下,仅支持笔输入使用墨迹。 如果你尝试用手指、鼠标或触摸板书写或绘制,你会感到失望。

若要使皱眉倒置,需要添加第二行代码。 这一次,它位于声明 InkCanvas 的 XAML 文件的代码隐藏中。

在此步骤中,我们将介绍 InkPresenter 对象,该对象提供对 InkCanvas 上墨迹输入(标准和修改)的输入、处理和呈现的精细管理。

注意

标准墨迹输入(笔尖或橡皮擦尖/按钮)未使用辅助硬件提供进行修改,例如笔桶按钮、鼠标右键或类似机制。

若要启用鼠标和触摸墨迹书写,请将 InkPresenterInputDeviceTypes 属性设置为所需的 CoreInputDeviceTypes 值的组合。

在此例中:

  1. 打开 MainPage.xaml.cs 文件。
  2. 查找标记为此步骤标题的代码 ("// Step 3: Support inking with touch and mouse")。
  3. 取消注释以下行。
    inkCanvas.InkPresenter.InputDeviceTypes =
        Windows.UI.Core.CoreInputDeviceTypes.Mouse | 
        Windows.UI.Core.CoreInputDeviceTypes.Touch | 
        Windows.UI.Core.CoreInputDeviceTypes.Pen;

再次运行应用,你会发现所有在计算机屏幕上用手指绘画的梦想都成真了!

注意

指定输入设备类型时,必须指示对每种特定输入类型(包括笔)的支持,因为设置此属性会替代默认的 InkCanvas 设置。

步骤 4:添加墨迹工具栏

InkToolbar 是一个 UWP 平台控件,它提供一组可自定义且可扩展的按钮,用于激活与墨迹相关的功能。

默认情况下,InkToolbar 包含一组基本按钮,允许用户在笔、铅笔、荧光笔或橡皮擦之间进行快速选择,其中任何一个按钮都可以与模具(标尺或量角器)一起使用。 每个笔、铅笔和荧光笔按钮还提供用于选择墨迹颜色和笔划大小的浮出控件。

要将默认 InkToolbar 添加到墨迹书写应用,只需将其放置在 InkCanvas 所在页面,并关联这两个控件。

在此例中

  1. 打开 MainPage.xaml 文件。
  2. 找到标有此步骤标题的代码 ("<!-- Step 4: Add an ink toolbar -->")。
  3. 取消注释以下行。
    <InkToolbar x:Name="inkToolbar" 
                        VerticalAlignment="Top" 
                        Margin="10,0,10,0"
                        TargetInkCanvas="{x:Bind inkCanvas}">
    </InkToolbar>

注意

为了使 UI 和代码尽可能简洁且简单,我们使用基本网格布局,并在网格行中的 InkCanvas 后面声明 InkToolbar。 如果在 InkCanvas 之前声明它,InkToolbar 将呈现在画布下方,而用户无法对其进行访问。

现在再次运行应用以查看 InkToolbar 并试用一些工具。

本主题中突出显示了默认 InkToolbar 的基本墨迹示例应用的屏幕截图。

挑战:添加自定义按钮

下面是自定义 InkToolbar 的示例(来自 Windows Ink 工作区中的草图板)。

墨迹工作区中草图板中的墨迹工具栏的屏幕截图。

有关如何自定义 InkToolbar 的更多详细信息,请参阅将 InkToolbar 添加到通用 Windows 应用墨迹书写应用

步骤 5:支持笔迹识别

现在,你可以在应用中编写和绘制,接下来让我们尝试对这些涂鸦执行一些有用的操作。

在此步骤中,我们使用 Windows Ink 的笔迹识别功能来尝试破译你写的内容。

注意

书写识别可以通过“笔和 Windows Ink”设置改进:

  1. 打开“开始”菜单,然后选择“设置”
  2. 从“设置”屏幕中选择“设备”>“笔和 Windows Ink”“笔和 Windows Ink 设置”页的屏幕截图。
  3. 选择“了解我的笔迹”以打开“笔迹个性化”对话框。 “手写识别个性化”对话框的屏幕截图。

在此例中:

  1. 打开 MainPage.xaml 文件。
  2. 找到标有此步骤标题的代码 ("<!-- Step 5: Support handwriting recognition -->")。
  3. 取消注释以下行。
    <Button x:Name="recognizeText" 
            Content="Recognize text"  
            Grid.Row="0" Grid.Column="0"
            Margin="10,10,10,10"
            Click="recognizeText_ClickAsync"/>
    <TextBlock x:Name="recognitionResult" 
                Text="Recognition results: "
                VerticalAlignment="Center" 
                Grid.Row="0" Grid.Column="1"
                Margin="50,0,0,0" />
  1. 打开 MainPage.xaml.cs 文件。
  2. 找到标有此步骤标题的代码 (" Step 5: Support handwriting recognition")。
  3. 取消注释以下行。
  • 这是此步骤所需的全局变量。
    InkAnalyzer analyzerText = new InkAnalyzer();
    IReadOnlyList<InkStroke> strokesText = null;
    InkAnalysisResult resultText = null;
    IReadOnlyList<IInkAnalysisNode> words = null;
  • 这是“识别文本”按钮的处理程序,我们在其中执行识别处理。
    private async void recognizeText_ClickAsync(object sender, RoutedEventArgs e)
    {
        strokesText = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
        // Ensure an ink stroke is present.
        if (strokesText.Count > 0)
        {
            analyzerText.AddDataForStrokes(strokesText);

            resultText = await analyzerText.AnalyzeAsync();

            if (resultText.Status == InkAnalysisStatus.Updated)
            {
                words = analyzerText.AnalysisRoot.FindNodes(InkAnalysisNodeKind.InkWord);
                foreach (var word in words)
                {
                    InkAnalysisInkWord concreteWord = (InkAnalysisInkWord)word;
                    foreach (string s in concreteWord.TextAlternates)
                    {
                        recognitionResult.Text += s;
                    }
                }
            }
            analyzerText.ClearDataForAllStrokes();
        }
    }
  1. 再次运行应用,编写内容,然后单击“识别文本”按钮
  2. 识别结果显示在按钮旁边

挑战 1:国际识别

Windows Ink 支持对多种 Windows 支持的语言进行文本识别。 每个语言包都包含一个笔迹识别引擎,可以随语言包一起安装。

通过查询已安装的笔迹识别引擎来定位特定语言。

有关国际笔迹识别的更多详细信息,请参阅将 Windows 墨迹笔划识别为文本

挑战 2:动态识别

在本教程中,我们需要按下按钮来启动识别。 还可以使用基本计时函数执行动态识别。

有关动态识别的更多详细信息,请参阅将 Windows Ink 笔划识别为文本

步骤 6:识别形状

所以现在你可以将手写笔记转换为更清晰的内容。 但是,早上的流程匿名会上那些歪歪扭扭的随意涂鸦又该怎么处理呢?

通过使用墨迹分析,应用还可以识别一组核心形状,包括:

  • 圆圈
  • 菱形
  • 绘图
  • 椭圆形
  • 等边三角形
  • 六边形
  • 等腰三角形
  • 平行四边形
  • 五角形
  • 四边形
  • 矩形
  • 直角三角形
  • Square
  • 梯形
  • 三角形

在此步骤中,我们使用 Windows Ink 的形状识别功能来尝试清理你的涂鸦。

对于此示例,我们不会尝试重绘墨迹笔划(尽管是可能的)。 而是在 InkCanvas 下添加标准画布,在其中绘制从原始墨迹派生的同等椭圆或多边形对象。 然后删除对应的墨迹笔划。

在此例中:

  1. 打开 MainPage.xaml 文件
  2. 找到标有此步骤标题的代码 ("<!-- Step 6: Recognize shapes -->")
  3. 取消注释该行。
   <Canvas x:Name="canvas" />

   And these lines.

    <Button Grid.Row="1" x:Name="recognizeShape" Click="recognizeShape_ClickAsync"
        Content="Recognize shape" 
        Margin="10,10,10,10" />
  1. 打开 MainPage.xaml.cs 文件
  2. 找到标有此步骤标题的代码 ("// Step 6: Recognize shapes")
  3. 取消注释这些行:
    private async void recognizeShape_ClickAsync(object sender, RoutedEventArgs e)
    {
        ...
    }

    private void DrawEllipse(InkAnalysisInkDrawing shape)
    {
        ...
    }

    private void DrawPolygon(InkAnalysisInkDrawing shape)
    {
        ...
    }
  1. 运行应用,绘制一些形状,然后单击“识别形状”按钮

下面是数字餐巾纸中的基本流程图示例。

数字餐巾纸中的基本流程图的屏幕截图。

下面是形状识别后的相同流程图。

用户选择“识别”形状后流程图的屏幕截图。

步骤 7:保存和加载墨迹

那么,你已经完成了涂鸦而且比较满意,但认为以后可能会做一些微小的调整? 可以将墨迹笔划保存到墨迹序列化格式 (ISF) 文件,并在灵感迸发时加载它们进行编辑。

ISF 文件是一种基本的 GIF 图像,其中包含用于描述笔划墨迹属性和行为的其他元数据。 未启用墨迹的应用可以忽略额外的元数据,但仍加载基本 GIF 图像(包括 alpha 通道背景透明度)。

注意

可以从 Microsoft 下载中心下载墨迹序列化格式 (ISF) 规格。

在此步骤中,我们将挂接位于墨迹工具栏旁边的“保存”和“加载”按钮。

在此例中:

  1. 打开 MainPage.xaml 文件。
  2. 找到标有此步骤标题的代码 ("<!-- Step 7: Saving and loading ink -->")。
  3. 取消注释以下行。
    <Button x:Name="buttonSave" 
            Content="Save" 
            Click="buttonSave_ClickAsync"
            Width="100"
            Margin="5,0,0,0"/>
    <Button x:Name="buttonLoad" 
            Content="Load"  
            Click="buttonLoad_ClickAsync"
            Width="100"
            Margin="5,0,0,0"/>
  1. 打开 MainPage.xaml.cs 文件。
  2. 找到标有此步骤标题的代码 ("// Step 7: Save and load ink")。
  3. 取消注释以下行。
    private async void buttonSave_ClickAsync(object sender, RoutedEventArgs e)
    {
        ...
    }

    private async void buttonLoad_ClickAsync(object sender, RoutedEventArgs e)
    {
        ...
    }
  1. 运行应用并绘制内容。
  2. 选择“保存”按钮并保存绘图。
  3. 擦除墨迹或重启应用。
  4. 选择“加载”按钮并打开刚刚保存的墨迹文件。

挑战:使用剪贴板复制并粘贴墨迹笔划

Windows Ink 还支持从剪贴板复制墨迹笔划以及将墨迹笔划粘贴到剪贴板。

有关将剪贴板与墨迹一起使用的更多详细信息,请参阅存储和检索 Windows Ink 笔划数据

总结

恭喜,你已完成了“输入:在 Windows 应用中支持墨迹”教程! 我们向你展示了在 Windows 应用中支持墨迹所需的基本代码,以及如何提供 Windows Ink 平台支持的一些更加丰富的用户体验。

示例