示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载本文以 Windows-universal-samples 仓库 archived/Ink 目录下的 Inking sample 为对象系统讲解如何基于Windows.UI.Input.InkingAPI在 Universal Windows PlatformUWP应用中用 JavaScript 完成墨迹笔画的渲染、选择、删除、复制粘贴、ISF 格式保存/加载以及手写识别与识别结果内字符串搜索。读完本文你将掌握InkManager含 Reco 识别 API与InkPresenter两套墨迹编程模型的核心用法并了解本示例两个场景的完整实现细节。示例概览一套代码两种墨迹编程模型本示例位于 archived/Ink是一个基于 WinJS 的 JavaScript UWP 应用通过 Ink.sln 与 Ink.jsproj 组织工程。示例在 sample-configuration.js 中注册了两个可切换的场景Scenario 1/html/scenario1.html演示Ink 与 Reco API核心对象是Windows.UI.Input.Inking.InkManager覆盖渲染、选择、删除、复制粘贴、保存加载、手写识别、识别结果搜索等全部能力Scenario 2/html/scenario2.html演示Ink Presenter API核心对象是InkPresenter及其strokeContainer提供铅笔、荧光笔、擦除三种笔尖模式以及保存、加载、清除、撤销功能。两个场景共用 default.html 作为宿主页面墨迹相关的工具栏命令颜色、宽度、模式切换以 WinJSMenu/Flyout形式集中定义在宿主页面中。Scenario 1基于 InkManager 的完整墨迹工作流Scenario 1 的实现全部位于 scenario1.js它把InkManager作为墨迹数据的唯一事实来源single source of truth所有笔画操作写入、选择、删除、识别、剪贴板、持久化都围绕这一实例展开。三层画布架构与渲染管线页面 scenario1.html 在同一个canvasGroup容器中叠放了三个canvasHighlightCanvas最底层绘制荧光笔笔画与横线笔记纸背景InkCanvas中间层绘制普通墨迹笔画SelectCanvas最顶层绘制套索lasso选择框、擦除轨迹并承接所有 Pointer 事件。这种分层设计让墨迹、高亮和选择框可以独立重绘。renderAllStrokes()先清空三层画布再调用renderPaper()绘制笔记本式背景一条 FireBrick 左边距线 每 55px 一条蓝色横线最后遍历inkManager.getStrokes()依据drawingAttributes.drawAsHighlighter决定把笔画画到哪一层inkManager.getStrokes().forEach(function (stroke) { var att stroke.drawingAttributes; var color toColorString(att.color); var width att.size.width; var hl att.drawAsHighlighter; var ctx hl ? hlContext : inkContext; if (stroke.selected) { renderStroke(stroke, color, width * 2, ctx); // 选中态加粗 var stripe hl ? Azure : White; var w width - (hl ? 3 : 1); renderStroke(stroke, stripe, w, ctx); // 中空条纹效果 } else { renderStroke(stroke, color, width, ctx); } });笔画的实际绘制使用stroke.getRenderingSegments()返回的贝塞尔段通过bezierCurveTo逐段重建笔迹曲线——这正是fitToCurve true时墨迹被平滑拟合为曲线的可视化结果。指针事件驱动从落笔到笔画入库Pointer 事件统一注册在最顶层的SelectCanvas上scenario1.jshandlePointerDown对 pen 或鼠标左键调用inkManager.selectWithLine(pt, pt)清空旧选区然后inkManager.processPointerDown(pt)开启新笔画若pt.properties.isEraser为真笔的橡皮端则临时进入擦除模式handlePointerMove把evt.intermediatePoints自上次移动以来积累的全部采样点按时间顺序喂给inkManager.processPointerUpdate(pts[i])同时在本地 2D context 上同步画线保证所见即所得handlePointerUp/handlePointerOut调用inkManager.processPointerUp(pt)收尾笔画若当前处于 selecting 模式用返回的包围矩形定位SelectionBox最后整体重绘。这里有一个值得注意的工程细节代码用全局penID过滤鼠标误触产生的 move/up 事件——因为用户书写时偶尔会带动鼠标导致产生坐标不一致的鼠标事件流。绘制属性颜色、宽度与高亮墨迹外观由Windows.UI.Input.Inking.InkDrawingAttributes控制。初始化时示例设置了fitToCurve true并通过inkManager.setDefaultDrawingAttributes(drawingAttributes)写入默认值。由于 Stroke API 对drawingAttributes只支持先 get、再改内部字段、最后 put 回去的操作方式示例专门封装了shapeStroke()改宽度和colorStroke()改颜色两个工具函数并在setDefaults()中把当前 canvas 的lineWidth与strokeStyle同步为InkManager的新笔画默认值。颜色值在 HTML 十六进制字符串与Windows.UI.Color结构之间通过toColorString()/toColorStruct()互相转换scenario1.js。工具栏按钮的 ID 直接映射为参数墨迹宽度按钮 ID 为IW2~IW10高亮宽度按钮 ID 为HW10~HW30颜色按钮 ID 为颜色名处理器用evt.currentTarget.id解析取值见 default.html 中的InkWidthFlyout、HighlightWidthFlyout等菜单定义。四种操作模式书写、高亮、选择、擦除InkManager.mode取InkManipulationMode枚举示例通过highlightMode()/inkMode()/selectMode()/eraseMode()四个函数切换inking正常书写或高亮context指向inkContext或hlContextselectingselContext.strokeStyle设为用 images/select.png 平铺出的虚线图案绘制套索erasingselContext.strokeStyle设为全透明套索路径变成擦除轨迹任何被触碰的笔画整体删除。对于带橡皮端的笔示例实现了tempEraseMode()用saveMode()/restoreMode()维护一个深度为 1 的模式栈笔尾擦除结束后自动恢复之前的模式书写/高亮/选择而工具栏的 Erase 按钮则进入持续擦除模式直到用户切换其他功能。选择、移动与删除选择selectWithLine(pt, pt)用零长度线段清除选区套索完成后processPointerUp返回选区包围矩形detachSelection(rect)把一个透明的SelectionBoxdiv 精确覆盖到选中墨迹上移动SelectionBox上注册MSGestureChange手势事件handleSelectionBoxGestureChange中同步调用inkManager.moveSelected({x, y})移动笔画并重绘scenario1.js删除clear()依据anySelected()决定只删选中笔画deleteSelected()还是全选后删除。剪贴板复制与粘贴墨迹copySelectedToClipboard()把选中笔画无选中时先selectAll()以 Windows 墨迹剪贴板格式写入系统剪贴板可粘贴到支持该格式的应用如 Windows Journalpaste()先通过inkManager.canPasteFromClipboard()检查可用性再以{x: 100, y: 60}为插入点调用inkManager.pasteFromClipboard(insertionPoint)识别候选词也可复制点击识别结果菜单中的候选按钮recoClipboard()用DataPackage.setText()把候选文本放入剪贴板。ISF 持久化保存与加载墨迹文件保存流程save()writeInk()使用FileSavePicker文件类型限定为 GIFpicker.fileTypeChoices.insert(GIF file, [.gif])因为 Ink Serialized FormatISF数据以元数据形式嵌入 GIF 文件随后inkManager.saveAsync(saveStream)写入流并在完成后显式close()。加载流程load()readInk()使用FileOpenPicker起始位置为图片库扩展名过滤[.gif]通过inkManager.loadAsync(loadStream)恢复笔画并统计getStrokes().length。代码用openOperationRunning标志防止两个loadAsync并发执行这正是异步 API 在 WinJS promise 链中常见的防重入模式。手写识别与识别结果搜索识别recognize()调用inkManager.recognizeAsync(InkRecognitionTarget.selected)识别范围有三种模式——selected仅选中笔画、remaining上次识别后新增的笔画、all全部笔画。示例刻意不使用all模式因为荧光笔笔画参与全量识别会得到大量星号等噪声结果它先unselectHighlight()排除高亮若无选中则用selectAllNoHighlight()选中全部非高亮笔画后再按selected模式识别。识别完成后调用inkManager.updateRecognitionResults(results)把结果写回 InkManager供后续命中测试与搜索使用。每个InkRecognitionResult代表一个墨迹词通过getTextCandidates()可取得最多 5 个候选文本第 0 个为主候选。hitTest(tx, ty)遍历inkManager.getRecognitionResults()用boundingRect做矩形命中测试命中后弹出RecoFlyout菜单展示该词的候选列表点击任一候选即复制到剪贴板。搜索find()findWord()实现在识别结果中搜索字符串。查找过程对用户输入按空格分词逐词在所有识别结果的全部候选中做大小写不敏感匹配alternates[j].toLowerCase() target命中后把该词对应笔画的selected置为 true 并高亮重绘。因此即使某个词被误识别如把 this 识别成 these只要 this 出现在任一候选中仍可被找到。识别器选择setRecognizerByName()遍历inkManager.getRecognizers()按名称查找并通过setDefaultRecognizer()设为默认示例在初始化时尝试加载 Microsoft English (US) Handwriting Recognizer。快捷键与交互细节keypress处理器为整个应用注册了快捷键Esc依次剥洋葱式关闭识别菜单 → 取消选区 → 回到书写模式CtrlC/CtrlV/CtrlF/CtrlO/CtrlS/CtrlR/CtrlQ分别对应复制、粘贴、查找、加载、保存、识别和退出scenario1.js。所有按钮与菜单均可通过鼠标、笔或触摸操作。Scenario 2基于 InkPresenter 的现代化墨迹编程Scenario 2 的实现位于 scenario2.js代表 Windows 10 引入的新一代墨迹 API不再由应用自行管理笔画数据和事件分发而是通过 Canvas 的ms-ink上下文直接获取系统托管的InkPresenter。获取 InkPresenter 并配置输入设备初始化流程inkInitialize()先把 canvas 尺寸对齐到实际布局尺寸然后inkContext inkCanvas.getContext(ms-ink); inkPresenter inkContext.msInkPresenter; inkPresenter.inputDeviceTypes Windows.UI.Core.CoreInputDeviceTypes.mouse | Windows.UI.Core.CoreInputDeviceTypes.pen;inputDeviceTypes显式声明接受鼠标与笔两种输入源墨迹的采集、渲染全部由系统完成应用无需再监听 Pointer 事件。三种笔尖模式与绘制属性inputProcessingConfiguration.mode取InkInputProcessingMode可切换书写与擦除铅笔模式InkDrawingAttributes.createForPencil()创建铅笔属性ignorePressure false启用压感、fitToCurve true、size {width: 3, height: 3}荧光笔模式drawAsHighlighter true、penTip PenTipShape.rectangle矩形笔尖、ignorePressure true、size {width: 10, height: 10}产生半透明宽笔画效果擦除模式直接置mode InkInputProcessingMode.erasing笔画级擦除。属性更新统一走inkPresenter.updateDefaultDrawingAttributes(drawingAttributes)颜色按钮Black/Blue/Red/Green则先copyDefaultDrawingAttributes()复制当前默认属性、修改color字段后再整体更新。strokeContainer撤销、保存、加载、清除InkPresenter.strokeContainer是系统托管的笔画容器撤销undo()取getStrokes()最后一笔置selected true后deleteSelected()保存/加载对ApplicationData.current.localFolder下的strokes.txt文件分别调用strokeContainer.saveAsync(stream)先flushAsync再关流和strokeContainer.loadAsync(stream)格式即 ISF清除strokeContainer.clear()。此外场景 2 针对页面恢复后墨迹可能不刷新的已知问题在visibilitychange事件中用requestAnimationFrame把 canvas 宽度 1/-1 强制重绘scenario2.js是实战中值得借鉴的兼容处理。使用说明与操作指南依据 README 的说明应用内操作方式如下使用平板笔绘制墨迹笔画工具栏提供颜色选择器、线宽选择器和多种功能按钮Erase擦除模式一条擦除轨迹会删除它所触及的全部笔画若笔带有橡皮端可用笔尾擦除回到笔尖即退出擦除模式Select选择模式套索圈中的笔画全部被选中点击工具栏其他功能即可退出选择模式。墨迹颜色/宽度会应用到所有被选中的普通笔画高亮颜色/宽度会应用到所有被选中的高亮笔画Recognition识别模式对全部或仅选中的笔画执行手写识别完成后在应用底部查看主候选文本点击某个词可查看该词的全部候选使用Find可在识别结果中搜索字符串按Erase按钮可删除全部或仅选中笔画其他命令Copy把选中笔画复制到剪贴板Paste从剪贴板粘贴笔画Save/Load以 ISF 格式读写图片库Pictures或库Libraries文件夹中的墨迹文件。构建与运行若通过 ZIP 下载示例集合务必解压整个压缩包而不仅是本示例所在文件夹以保证共享依赖可用启动 Microsoft Visual Studio 2017选择File Open Project/Solution进入解压目录的archived/Ink/js子文件夹双击解决方案文件 Ink.sln按CtrlShiftB或选择Build Build Solution生成按F5Debug Start Debugging调试运行或按CtrlF5Debug Start Without Debugging免调试运行。运行环境要求客户端 Windows 10、服务端 Windows Server 2016 Technical Preview、手机 Windows 10示例清单 package.appxmanifest 声明目标设备族为Windows.UniversalMinVersion 10.0.17134.0能力仅需internetClient。与当前仓库中其他墨迹示例的关系本示例是 Windows-universal-samples 墨迹系列的基础参考仓库中还有两个更现代的墨迹示例可供对照学习SimpleInk演示基于InkCanvasInkPresenter的基础捕获与识别流程含 C、C# 多语言实现ComplexInk演示选择、擦除、识别、剪贴板等更复杂的墨迹交互。三者对比可以清晰看到墨迹 API 的演进脉络从本示例archived中应用自管笔画数据与渲染的InkManager模型到由系统托管渲染的InkPresenter模型再到 XAMLInkCanvas控件层面的声明式用法。若需要为现代 UWP 应用引入墨迹功能建议优先参考 SimpleInk 与 ComplexInk 的活跃版本实现。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐Windows-universal-samples SimpleInk 指南用 Windows.UI.Input.Inking 实现 UWP 手写输入、识别与墨迹工具栏Windows universal samples SimpleInk 指南用 Windows.UI.Input.Inking 实现 UWP 手写输入、识别与示例工程Rasa 多副本并行部署时如何配置 ConcurrentRedisLockStoreRasa 多副本并行部署时如何配置 ConcurrentRedisLockStore 当 Rasa 以多个副本replicated services并行运行示例工程Windows-universal-samples 中的 BasicFaceDetection 示例使用 FaceDetector 在 UWP 应用中实现静态人脸检测Windows universal samples 中的 BasicFaceDetection 示例使用 FaceDetector 在 UWP 应用中实现静态示例工程上一篇GitHub汉化插件终极指南3分钟让GitHub界面说中文的免费神器下一篇NVIDIA Profile Inspector深度解析如何解锁显卡隐藏性能的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考