• 重新想象 Windows 8 Store Apps (51)


    [源码下载]


    重新想象 Windows 8 Store Apps (51) - 输入: 涂鸦板



    作者:webabcd


    介绍
    重新想象 Windows 8 Store Apps 之 涂鸦板

    • 通过 Pointer 相关事件实现一个具有基本功能的涂鸦板
    • 通过 InkManager 实现一个功能完善的涂鸦板



    示例
    1、演示如何通过 Pointer 相关事件实现一个只有基本功能的涂鸦板
    Input/Ink/Simple.xaml

    <Page
        x:Class="XamlDemo.Input.Ink.Simple"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Input.Ink"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <Button Name="btnClear" Content="清除" Click="btnClear_Click_1" />
    
                <Canvas Name="canvas" Background="Blue" Width="800" Height="480" HorizontalAlignment="Left" Margin="0 10 0 0" />
    
            </StackPanel>
        </Grid>
    </Page>

    Input/Ink/Simple.xaml.cs

    /*
     * 通过 Pointer 相关事件实现一个只有基本功能的涂鸦板
     */
    
    using System;
    using System.Collections.Generic;
    using Windows.Foundation;
    using Windows.UI;
    using Windows.UI.Input;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Shapes;
    
    namespace XamlDemo.Input.Ink
    {
        public sealed partial class Simple : Page
        {
            // 用于保存触摸点(PointerId - Point)
            private Dictionary<uint, Point?> _dicPoint;
    
            public Simple()
            {
                this.InitializeComponent();
    
                canvas.PointerPressed += canvas_PointerPressed;
                canvas.PointerMoved += canvas_PointerMoved;
                canvas.PointerReleased += canvas_PointerReleased;
                canvas.PointerExited += canvas_PointerExited;
    
                _dicPoint = new Dictionary<uint, Point?>();
            }
    
            void canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
            {
                // 指针按下后,保存此触摸点
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
                _dicPoint[pointerPoint.PointerId] = pointerPoint.Position;
            }
    
            void canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
            {
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
    
                if (_dicPoint.ContainsKey(pointerPoint.PointerId) && _dicPoint[pointerPoint.PointerId].HasValue)
                {
                    Point currentPoint = pointerPoint.Position;
                    Point previousPoint = _dicPoint[pointerPoint.PointerId].Value;
    
                    // 如果指针移动过程中,两个点间的距离超过 4 则在两点间绘制一条直线,以完成涂鸦
                    if (ComputeDistance(currentPoint, previousPoint) > 4)
                    {
                        Line line = new Line()
                        {
                            X1 = previousPoint.X,
                            Y1 = previousPoint.Y,
                            X2 = currentPoint.X,
                            Y2 = currentPoint.Y,
                            StrokeThickness = 5,
                            Stroke = new SolidColorBrush(Colors.Orange),
                            StrokeEndLineCap = PenLineCap.Round
                        };
    
                        _dicPoint[pointerPoint.PointerId] = currentPoint;
                        canvas.Children.Add(line);
                    }
                }
            }
    
            void canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                // 指针释放后,从字典中删除此 PointerId 的数据
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
                if (_dicPoint.ContainsKey(pointerPoint.PointerId))
                    _dicPoint.Remove(pointerPoint.PointerId);
            }
    
            void canvas_PointerExited(object sender, PointerRoutedEventArgs e)
            {
                // 指针离开相当于指针释放
                canvas_PointerReleased(sender, e);
            }
    
            // 清除涂鸦
            private void btnClear_Click_1(object sender, RoutedEventArgs e)
            {
                canvas.Children.Clear();
                _dicPoint.Clear();
            }
    
            // 计算两个点(Point)之间的距离
            private double ComputeDistance(Point point1, Point point2)
            {
                return Math.Sqrt(Math.Pow(point1.X - point2.X, 2) + Math.Pow(point1.Y - point2.Y, 2));
            }
        }
    }


    2、演示如何通过 InkManager 实现一个功能完善的涂鸦板
    Input/Ink/InkRenderer.cs

    /*
     * 开发一个 InkRenderer 类,用于呈现 InkManager 中的内容
     * 
     * 注:InkManager 用于 ink 的管理,但并不负责呈现
     * 
     * 
     * InkStroke - ink 画笔
     *     DrawingAttributes - 画笔的相关属性,一个 InkDrawingAttributes 类型的对象
     *         Color - 颜色
     *         FitToCurve - 使用贝塞尔曲线则为 true,使用直线则为 false,默认值为 true
     *         PenTip - 笔尖的形状(Circle, Rectangle)
     *         Size - 笔尖的尺寸
     *         IgnorePressure - 是否忽略笔尖在触摸屏上的压力
     *     BoundingRect - ink 画笔的边界框
     *     Recognized - 该画笔是否已被文字识别
     *     Selected - 该画笔是否被选中
     *     Clone() - 克隆这个画笔,并返回克隆后的新的 InkStroke 对象
     *     GetRenderingSegments() - 返回 ink 的线段集合,即 InkStrokeRenderingSegment 集合
     *     
     * InkStrokeRenderingSegment - ink 的线段
     *     BezierControlPoint1 - 贝塞尔曲线的第一个控制点的位置
     *     BezierControlPoint2 - 贝塞尔曲线的第二个控制点的位置
     *     Position - 贝塞尔曲线的终点的位置
     */
    
    using System.Collections.Generic;
    using Windows.UI;
    using Windows.UI.Input;
    using Windows.UI.Input.Inking;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Shapes;
    
    namespace XamlDemo.Input.Ink
    {
        public class InkRenderer
        {
            /// <summary>
            /// 呈现 ink 的容器
            /// </summary>
            private readonly Panel _container = null;
    
            /// <summary>
            /// ink 的实时路径(PointerId - Path)
            /// </summary>
            private readonly Dictionary<uint, Path> _dicLivePath = null;
            /// <summary>
            /// ink 的实时路径中所包含的 PolyLineSegment(PointerId - PolyLineSegment)
            /// </summary>
            private readonly Dictionary<uint, PolyLineSegment> _dicLivePolyLine = null;
    
            /// <summary>
            /// InkStroke 所对应三次贝塞尔曲线,用于保存全部涂鸦曲线(包括未被选中的和被选中的)
            /// </summary>
            private readonly Dictionary<InkStroke, Path> _dicInkPath = null;
            /// <summary>
            /// InkStroke 所对应三次贝塞尔曲线,用于保存被选中的涂鸦曲线
            /// </summary>
            private readonly Dictionary<InkStroke, Path> _dicSelectionPath = null;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="panel">用于呈现 ink 的容器</param>
            public InkRenderer(Panel panel)
            {
                _container = panel;
    
                _dicLivePath = new Dictionary<uint, Path>();
                _dicLivePolyLine = new Dictionary<uint, PolyLineSegment>();
    
                _dicInkPath = new Dictionary<InkStroke, Path>();
                _dicSelectionPath = new Dictionary<InkStroke, Path>();
            }
    
            /// <summary>
            /// 开始实时绘制 ink
            /// </summary>
            /// <param name="pointerPoint">当前的触摸点</param>
            /// <param name="inkDrawingAttributes">ink 的 InkDrawingAttributes 数据</param>
            public void EnterLiveRendering(PointerPoint pointerPoint, InkDrawingAttributes inkDrawingAttributes)
            {
                uint pointerId = pointerPoint.PointerId;
    
                var polyLine = new PolyLineSegment();
                polyLine.Points.Add(pointerPoint.Position);
                var figure = new PathFigure();
                figure.StartPoint = pointerPoint.Position;
                figure.Segments.Add(polyLine);
                var geometry = new PathGeometry();
                geometry.Figures.Add(figure);
                var path = new Path();
                path.Data = geometry;
    
                path.Stroke = new SolidColorBrush(inkDrawingAttributes.Color);
                path.StrokeThickness = inkDrawingAttributes.Size.Width;
                path.StrokeLineJoin = PenLineJoin.Round;
                path.StrokeStartLineCap = PenLineCap.Round;
    
                _dicLivePolyLine.Add(pointerId, polyLine);
                _dicLivePath.Add(pointerId, path);
    
                _container.Children.Add(path);
            }
    
            /// <summary>
            /// 更新 ink 的实时绘制
            /// </summary>
            /// <param name="pointerPoint"></param>
            public void UpdateLiveRender(PointerPoint pointerPoint)
            {
                uint pointerId = pointerPoint.PointerId;
    
                _dicLivePolyLine[pointerId].Points.Add(pointerPoint.Position);
            }
    
            /// <summary>
            /// 停止此次 ink 的实时绘制
            /// </summary>
            /// <param name="pointerPoint">涂鸦的停止点</param>
            public void ExitLiveRendering(PointerPoint pointerPoint)
            {
                uint pointerId = pointerPoint.PointerId;
    
                _container.Children.Remove(_dicLivePath[pointerId]);
    
                _dicLivePolyLine.Remove(pointerId);
                _dicLivePath.Remove(pointerId);
            }
    
            /// <summary>
            /// 将 InkStroke 绘制成一条三次贝塞尔曲线
            /// </summary>
            /// <param name="inkStroke">InkStroke 对象</param>
            public void UpdateInkRender(InkStroke inkStroke)
            {
                Path bezierPath = InkStroke2BezierPath(inkStroke);
                _dicInkPath.Add(inkStroke, bezierPath);
                _container.Children.Add(bezierPath);
            }
    
            /// <summary>
            /// 将每一个 InkStroke 都绘制成一条三次贝塞尔曲线
            /// </summary>
            /// <param name="inkStrokes">InkStroke 集合</param>
            public void UpdateInkRender(IEnumerable<InkStroke> inkStrokes)
            {
                foreach (InkStroke inkStroke in inkStrokes)
                {
                    UpdateInkRender(inkStroke);
                }
            }
    
            /// <summary>
            /// 将被选中的 InkStroke 以被选中的样式绘制出来
            /// </summary>
            public void UpdateSelectionRender()
            {
                foreach (var inkPath in _dicInkPath)
                {
                    Path selectionPath = null;
                    bool selectionPathExists = _dicSelectionPath.TryGetValue(inkPath.Key, out selectionPath);
    
                    // 如果 InkStroke 是被选中的状态,但是并没有呈现出选中状态,则呈现这个选中状态
                    if (inkPath.Key.Selected && !selectionPathExists)
                    {
                        inkPath.Value.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width + 2;
    
                        selectionPath = InkStroke2BezierPath(inkPath.Key);
                        selectionPath.Stroke = new SolidColorBrush(Colors.White);
                        selectionPath.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width;
                        _dicSelectionPath.Add(inkPath.Key, selectionPath);
    
                        _container.Children.Add(selectionPath);
                    }
                    // 如果 InkStroke 是未被选中的状态,但是却呈现出选中状态,则去掉这个选中状态的呈现
                    else if (selectionPathExists)
                    {
                        inkPath.Value.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width;
                        _dicSelectionPath.Remove(inkPath.Key);
                        _container.Children.Remove(selectionPath);
                    }
                }
            }
    
            /// <summary>
            /// 清除全部呈现
            /// </summary>
            public void Clear()
            {
                foreach (var path in _dicInkPath.Values)
                {
                    _container.Children.Remove(path);
                }
                foreach (var path in _dicSelectionPath.Values)
                {
                    _container.Children.Remove(path);
                }
                foreach (var path in _dicLivePath.Values)
                {
                    _container.Children.Remove(path);
                }
    
                _dicInkPath.Clear();
                _dicSelectionPath.Clear();
                _dicLivePath.Clear();
                _dicLivePolyLine.Clear();
            }
    
    
    
            /// <summary>
            /// 如果 InkStroke 是一个贝塞尔曲线画笔,则可将其转换成 Path(一条贝塞尔曲线)
            /// </summary>
            /// <param name="inkStroke">InkStroke 对象</param>
            /// <returns>转换后的 Path 对象</returns>
            public static Path InkStroke2BezierPath(InkStroke inkStroke)
            {
                var figure = new PathFigure();
                var segments = inkStroke.GetRenderingSegments().GetEnumerator();
                segments.MoveNext();
    
                figure.StartPoint = segments.Current.Position;
    
                while (segments.MoveNext())
                {
                    var bs = new BezierSegment();
                    bs.Point1 = segments.Current.BezierControlPoint1;
                    bs.Point2 = segments.Current.BezierControlPoint2;
                    bs.Point3 = segments.Current.Position;
                    figure.Segments.Add(bs);
                }
    
                var geometry = new PathGeometry();
                geometry.Figures.Add(figure);
                var path = new Path();
                path.Data = geometry;
    
                path.Stroke = new SolidColorBrush(inkStroke.DrawingAttributes.Color);
                path.StrokeThickness = inkStroke.DrawingAttributes.Size.Width;
                path.StrokeLineJoin = PenLineJoin.Round;
                path.StrokeStartLineCap = PenLineCap.Round;
    
                return path;
            }
        }
    }

    Input/Ink/Demo.xaml

    <Page
        x:Class="XamlDemo.Input.Ink.Demo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Input.Ink"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" FontSize="14.667" />
                
                <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
                    <RadioButton Name="radInk" GroupName="mode" Content="涂鸦模式" Checked="radInk_Checked_1" IsChecked="True" />
                    <RadioButton Name="radSelect" GroupName="mode" Content="选择模式" Checked="radSelect_Checked_1" Margin="10 0 0 0" />
                    <RadioButton Name="radErase" GroupName="mode" Content="删除模式" Checked="radErase_Checked_1" Margin="10 0 0 0" />
                </StackPanel>
    
                <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
                    <Button Name="btnClearAll" Content="清除全部内容" Click="btnClearAll_Click_1" />
                    <Button Name="btnClearSelectedInk" Content="清除被选中的内容" Click="btnClearSelectedInk_Click_1" Margin="10 0 0 0" />
                    <Button Name="btnClearSelectedState" Content="清除选中状态" Click="btnClearSelectedState_Click_1" Margin="10 0 0 0" />
                    <Button Name="btnMoveSelectedInk" Content="移动被选中的内容" Click="btnMoveSelectedInk_Click_1" Margin="10 0 0 0" />
                </StackPanel>
                
                <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
                    <Button Name="btnCut" Content="剪切" Click="btnCut_Click_1" />
                    <Button Name="btnCopy" Content="复制" Click="btnCopy_Click_1" Margin="10 0 0 0" />
                    <Button Name="btnPaste" Content="粘贴" Click="btnPaste_Click_1" Margin="10 0 0 0" />
                </StackPanel>
    
                <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
                    <Button Name="btnSave" Content="保存到文件" Click="btnSave_Click_1" />
                    <Button Name="btnLoad" Content="从文件加载" Click="btnLoad_Click_1" Margin="10 0 0 0" />
                    <Button Name="btnRecognize" Content="文字识别" Click="btnRecognize_Click_1" Margin="10 0 0 0" />
                </StackPanel>
    
                <Canvas x:Name="canvas" Background="Blue" Width="800" Height="360" Margin="0 10 0 0" HorizontalAlignment="Left"
                        PointerPressed="canvas_PointerPressed_1"
                        PointerMoved="canvas_PointerMoved_1"
                        PointerReleased="canvas_PointerReleased_1" />
    
            </StackPanel>
        </Grid>
    </Page>

    Input/Ink/Demo.xaml.cs

    /*
     * 通过 InkManager 实现一个功能完善的涂鸦板
     * 
     * 注:InkManager 用于 ink 的管理,但并不负责呈现,需要自己开发呈现 ink 的类,请参见 InkRenderer.cs
     * 
     * 
     * InkManager - ink 的管理类
     *     包括 ink 的输入模式,复制/粘贴,移动,保存到文件,从文件加载,文字识别等功能
     *     详细说明请参见本 Demo 中的相关代码的注释
     * 
     * InkStroke - ink 画笔
     *     DrawingAttributes - 画笔的相关属性,一个 InkDrawingAttributes 类型的对象
     *         Color - 颜色
     *         FitToCurve - 使用贝塞尔曲线则为 true,使用直线则为 false,默认值为 true
     *         PenTip - 笔尖的形状(Circle, Rectangle)
     *         Size - 笔尖的尺寸
     *         IgnorePressure - 是否忽略笔尖在触摸屏上的压力
     *     BoundingRect - ink 画笔的边界框
     *     Recognized - 该画笔是否已被文字识别
     *     Selected - 该画笔是否被选中
     *     Clone() - 克隆这个画笔,并返回克隆后的新的 InkStroke 对象
     *     GetRenderingSegments() - 返回 ink 的线段集合,即 InkStrokeRenderingSegment 集合
     *     
     * InkStrokeRenderingSegment - ink 的线段
     *     BezierControlPoint1 - 贝塞尔曲线的第一个控制点的位置
     *     BezierControlPoint2 - 贝塞尔曲线的第二个控制点的位置
     *     Position - 贝塞尔曲线的终点的位置
     */
    
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using Windows.Foundation;
    using Windows.Storage;
    using Windows.Storage.Pickers;
    using Windows.UI;
    using Windows.UI.Input;
    using Windows.UI.Input.Inking;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Input;
    using XamlDemo.Common;
    
    namespace XamlDemo.Input.Ink
    {
        public sealed partial class Demo : Page
        {
            // 自己开发的用于呈现 ink 的类
            private InkRenderer _renderer = null;
    
            private InkManager _inkManager = null;
            private InkDrawingAttributes _inkDrawingAttributes = null; // 涂鸦 ink 的样式
            private InkDrawingAttributes _inkDrawingAttributesForSelect = null; // 选择模式时,用于呈现用户的选择路径的 ink 的样式
    
            private int _pointerId = -1; // 当前指针的 pointerId
    
            public Demo()
            {
                this.InitializeComponent();
    
                _inkDrawingAttributes = new InkDrawingAttributes();
                _inkDrawingAttributes.Color = Colors.Orange;
                _inkDrawingAttributes.Size = new Size(5, 5);
                _inkDrawingAttributes.IgnorePressure = true;
                _inkDrawingAttributes.FitToCurve = true;
    
                _inkDrawingAttributesForSelect = new InkDrawingAttributes();
                _inkDrawingAttributesForSelect.Color = Colors.White;
                _inkDrawingAttributesForSelect.Size = new Size(1, 1);
                _inkDrawingAttributesForSelect.PenTip = PenTipShape.Circle;
               
    
                _inkManager = new InkManager();
                // InkManager 一共有三种模式:Inking - 涂鸦;Erasing - 擦除;Selecting - 选择
                _inkManager.Mode = InkManipulationMode.Inking;
                // 设置 InkManager 的默认的画笔属性
                _inkManager.SetDefaultDrawingAttributes(_inkDrawingAttributes);
                // 获取 InkManager 所支持的文字识别的种类
                var inkRecognizers = _inkManager.GetRecognizers();
                var inkRecognizer = inkRecognizers.SingleOrDefault(p => p.Name.Equals("Microsoft 中文(简体)手写识别器"));
                if (inkRecognizer != null)
                {
                    // 设置 InkManager 的默认的文字识别器为“Microsoft 中文(简体)手写识别器”
                    _inkManager.SetDefaultRecognizer(inkRecognizer);
                }
    
                _renderer = new InkRenderer(canvas);
            }
    
            private void canvas_PointerPressed_1(object sender, PointerRoutedEventArgs e)
            {
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
                _pointerId = (int)pointerPoint.PointerId;
    
                switch (_inkManager.Mode)
                {
                    case InkManipulationMode.Erasing: // 擦除模式
                        break;
                    case InkManipulationMode.Inking: // 涂鸦模式
                        _renderer.EnterLiveRendering(pointerPoint, _inkDrawingAttributes);
                        break;
                    case InkManipulationMode.Selecting: // 选择模式
                        _renderer.EnterLiveRendering(pointerPoint, _inkDrawingAttributesForSelect);
                        break;
                    default:
                        break;
                }
    
                // 通知 InkManager 指针已按下
                _inkManager.ProcessPointerDown(pointerPoint);
            }
    
            private void canvas_PointerMoved_1(object sender, PointerRoutedEventArgs e)
            {
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
    
                if (_pointerId == (int)pointerPoint.PointerId)
                {
                    switch (_inkManager.Mode)
                    {
                        case InkManipulationMode.Erasing:
                            // 通知 InkManager 指针移动中,然后会返回一个 Rect 对象,其代表被 Erasing 的矩形范围
                            var erasingRect = (Rect)_inkManager.ProcessPointerUpdate(e.GetCurrentPoint(canvas));
                            if (erasingRect.Height != 0 && erasingRect.Width != 0)
                            {
                                _renderer.Clear();
                                // 通过 InkManager.GetStrokes() 获取 InkManager 包含的全部 InkStroke 对象集合
                                _renderer.UpdateInkRender(_inkManager.GetStrokes());
                            }
                            break;
                        case InkManipulationMode.Inking:
                        case InkManipulationMode.Selecting:
                            if (_inkManager.Mode == InkManipulationMode.Inking || _inkManager.Mode == InkManipulationMode.Selecting)
                            {
                                var intermediatePoints = e.GetIntermediatePoints(canvas);
                                for (int i = intermediatePoints.Count - 1; i >= 0; i--)
                                {
                                    // 通知 InkManager 指针移动中
                                    _inkManager.ProcessPointerUpdate(intermediatePoints[i]);
                                }
    
                                _renderer.UpdateLiveRender(pointerPoint);
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
    
            private void canvas_PointerReleased_1(object sender, PointerRoutedEventArgs e)
            {
                PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
    
                if (_pointerId == (int)pointerPoint.PointerId)
                {
                    _pointerId = -1;
    
                    // 通知 InkManager 指针释放了,返回值:当 Inking 或 Selecting 时返回值为用户此次操作的矩形范围;当 Erasing 时返回值为 0,0,0,0
                    var rect = _inkManager.ProcessPointerUp(pointerPoint);
                    // var inkManagerRect = _inkManager.BoundingRect; // InkManager 所管理 InkStroke 集合的矩形范围(矩形边框)
    
                    switch (_inkManager.Mode)
                    {
                        case InkManipulationMode.Inking:
                            _renderer.ExitLiveRendering(pointerPoint);
                            _renderer.UpdateInkRender(_inkManager.GetStrokes()[_inkManager.GetStrokes().Count - 1]);
                            break;
                        case InkManipulationMode.Selecting:
                            _renderer.ExitLiveRendering(pointerPoint);
                            _renderer.UpdateSelectionRender();
                            break;
                        default:
                            break;
                    }
                }
            }
    
            private async void btnSave_Click_1(object sender, RoutedEventArgs e)
            {
                if (_inkManager.GetStrokes().Count > 0)
                {
                    if (Helper.EnsureUnsnapped())
                    {
                        var savePicker = new FileSavePicker();
                        savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
                        savePicker.FileTypeChoices.Add("GIF", new List<string> { ".gif" });
    
                        StorageFile file = await savePicker.PickSaveFileAsync();
                        if (null != file)
                        {
                            using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                            {
                                // 将 InkManager 中的 InkStroke 对象集合保存为文件
                                await _inkManager.SaveAsync(stream);
                            }
                        }
                    }
                }
            }
    
            private async void btnLoad_Click_1(object sender, RoutedEventArgs e)
            {
                if (Helper.EnsureUnsnapped())
                {
                    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
                    openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
                    openPicker.FileTypeFilter.Add(".gif");
                    StorageFile file = await openPicker.PickSingleFileAsync();
                    if (null != file)
                    {
                        using (var stream = await file.OpenSequentialReadAsync())
                        {
                            // 加载一个文件,从中获取 InkStroke 对象集合,并将其交由 InkManager 管理
                            await _inkManager.LoadAsync(stream);
                        }
    
                        _renderer.Clear();
                        _renderer.UpdateInkRender(_inkManager.GetStrokes());
                    }
                }
            }
    
            private void radInk_Checked_1(object sender, RoutedEventArgs e)
            {
                if (_inkManager != null)
                    _inkManager.Mode = InkManipulationMode.Inking; // 涂鸦模式
            }
    
            private void radSelect_Checked_1(object sender, RoutedEventArgs e)
            {
                if (_inkManager != null)
                    _inkManager.Mode = InkManipulationMode.Selecting; // 选择模式
            }
    
            private void radErase_Checked_1(object sender, RoutedEventArgs e)
            {
                if (_inkManager != null)
                    _inkManager.Mode = InkManipulationMode.Erasing; // 擦除模式
            }
    
            private void btnCut_Click_1(object sender, RoutedEventArgs e)
            {
                // 将 InkManager 中的被选中的 InkStroke 对象集合复制到剪切板
                _inkManager.CopySelectedToClipboard();
                // 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
                _inkManager.DeleteSelected();
    
                _renderer.Clear();
                _renderer.UpdateInkRender(_inkManager.GetStrokes());
            }
    
            private void btnCopy_Click_1(object sender, RoutedEventArgs e)
            {
                // 将 InkManager 中的被选中的 InkStroke 对象集合复制到剪切板
                _inkManager.CopySelectedToClipboard();
            }
    
            private void btnPaste_Click_1(object sender, RoutedEventArgs e)
            {
                // 剪切板中的数据是否是 InkStroke 对象集合
                if (_inkManager.CanPasteFromClipboard())
                {
                    // 将剪切板中的 InkStroke 对象集合粘贴到指定位置,并将此 InkStroke 对象集合交由 InkManager 管理
                    _inkManager.PasteFromClipboard(new Point(10, 10));
    
                    _renderer.Clear();
                    _renderer.UpdateInkRender(_inkManager.GetStrokes());
                    _renderer.UpdateSelectionRender();
                }
            }
    
            private void btnClearAll_Click_1(object sender, RoutedEventArgs e)
            {
                // 通过 InkManager.GetStrokes() 获取 InkManager 包含的全部 InkStroke 对象集合
                foreach (var inkStroke in _inkManager.GetStrokes())
                {
                    // InkStroke 是否被选中
                    inkStroke.Selected = true;
                }
                // 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
                _inkManager.DeleteSelected();
    
                _renderer.Clear();
            }
    
            private void btnClearSelectedInk_Click_1(object sender, RoutedEventArgs e)
            {
                // 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
                _inkManager.DeleteSelected();
    
                _renderer.Clear();
                _renderer.UpdateInkRender(_inkManager.GetStrokes());
            }
    
            private void btnClearSelectedState_Click_1(object sender, RoutedEventArgs e)
            {
                foreach (var inkStroke in _inkManager.GetStrokes())
                {
                    // InkStroke 是否被选中
                    inkStroke.Selected = false;
                }
    
                _renderer.Clear();
                _renderer.UpdateInkRender(_inkManager.GetStrokes());
            }
    
            private void btnMoveSelectedInk_Click_1(object sender, RoutedEventArgs e)
            {
                // 将 InkManager 中的被选中的 InkStroke 对象集合移动指定的距离(本例为向下移动 5 个像素,向右移动 50 个像素)
                _inkManager.MoveSelected(new Point(50, 5));
    
                _renderer.Clear();
                _renderer.UpdateInkRender(_inkManager.GetStrokes());
                _renderer.UpdateSelectionRender();
            }
    
            private async void btnRecognize_Click_1(object sender, RoutedEventArgs e)
            {
                // 对 InkManager 中的内容做文字识别
                //     InkRecognitionTarget.All - 识别全部; 
                //     InkRecognitionTarget.Selected - 识别选中的 InkStroke 集合; 
                //     InkRecognitionTarget.Recent - 识别最近的 InkStroke
                var recognitionResults = await _inkManager.RecognizeAsync(InkRecognitionTarget.All);
                // 将文字识别的结果更新到 InkManager
                _inkManager.UpdateRecognitionResults(recognitionResults);
                // _inkManager.GetRecognitionResults(); 获取 InkManager 中的文字识别的结果
    
                string result = "文字识别的结果:";
                foreach (InkRecognitionResult recognitionResult in recognitionResults)
                {
                    // 获取此文字识别的所有可能的结果集合,集合的第一条数据为最匹配的结果
                    result += " " + recognitionResult.GetTextCandidates()[0];
                }
    
                lblMsg.Text = result;
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    第八次课程作业
    第七次课程作业
    第六次课程作业
    第五次课程作业
    第三次课程作业
    第二次课程作业
    第一次课程作业
    FZU.Software Engineering1816 · First Homework -Preparation
    个人简介
    福大软工1816 · 第二次作业
  • 原文地址:https://www.cnblogs.com/webabcd/p/3258872.html
Copyright © 2020-2023  润新知