--- url: /index.md --- # 全能型屏幕批注工具 *** ## 集锦(软件介绍) *** ::: tip 迈向 Inkeys3,UI 设计和绘图库将得到极大进步,Coming Soon~ ::: --- --- url: /community.md --- # 社区名片 > 智绘教Inkeys 前行路上,我们由衷的感谢所有的支持智绘教的朋友们! ## 社区伙伴 还有他们:\ [ALTaleX](https://github.com/ALTaleX531) 🤔 💻 💡\ [Leafuke](https://github.com/Leafuke) 🤔\ [Darion](https://github.com/Darion) 🤔\ [Supra4E8C](https://github.com/LTbinglingfeng) 🤔\ [2,2,3-三甲基戊烷](https://github.com/2-2-3-trimethylpentane) 🤔 📝 📖 🌍\ [Jursin](https://github.com/Jursin) 🤔 🎨 > 还有许多朋友直接或间接的为 智绘教Inkeys 提供了帮助,也一并感谢他们。 > **关于本站**\ > [Jursin](https://github.com/Jursin) 为本站的设计和维护付出了很多,[2,2,3-三甲基戊烷](https://github.com/2-2-3-trimethylpentane) 为本站编写了 Inkeys2 的教程,还有许多朋友对本站提供过帮助。在这里一并感谢他们! > **关于服务器**\ > 软件更新服务器(线路一)由 [智教联盟](https://forum.smart-teach.cn/) 提供。 ## 赞助者 ::: tip 提示 赞助者只有联系 AlanCRL 后才会在列表中显示,然而还有许多热心的匿名赞助者,在这里也一并感谢他们! ::: * `郑子杰` * `bin` * `路人甲` * `启幕` * `B站游大伟` * `HettyBig` * `建俊` * `LEON - 小清新` * `2,2,3-三甲基戊烷` * `凌汛` * `Krouis` * `XT-XHM` ## 赞助我们 ![](/SettingSponsor.png) 成功赞助后,可以联系作者将您的昵称和赞助的金额添加到社区名片中以表示感谢。 --- --- url: /download.md --- # 开始下载 ::: tip 提示 前往 [快速上手](https://wiki.inkeys.top/start/start/),查看更加详细的下载并使用步骤。 ::: ::: tip 超前体验 Inkeys3 ? Inkeys3 将会先在 Canary 通道推出供体验,属于早期开发版本,不建议日常使用。[了解更多并下载](/inkeys3)\ ::: ## 版本介绍 **智绘教Inkeys**的官方版本主要分为两种,**正式版本**和**预览版本**。 **正式版本LTS** 是最新的稳定版本,经过开发者和公测用户的验证,具有较高的稳定性。\ **预览版本Insider** 是最新的功能版本,由智绘教Inkeys开发者AlanCRL直接推送,并未进行广泛验证。\ 程序内的自动更新通道分为 **正式通道(LTS)** 和 **预览通道(Insider)** 也和上方相互对应。 第三方开发者提供的**修改版**和**定制版**等不属于智绘教Inkeys的官方版本,但可以参与智绘教Inkeys的**自动更新**,和通过软件内**修复功能**将软件修复为官方版本。 --- --- url: /jabber.md --- # 碎碎念 智绘教Inkeys,原本专注于教学环境下的屏幕绘制软件,是更推荐在教师一体机上安装的软件,拥有其独特的丰富功能和细节设定,也得到了许多用户以及同类软件开发者的支持。随着用户群体不断变大,日活跃用户不断增多。我逐渐意识到,必须将智绘教当做一款真正的产品来开发了。**智绘教Inkeys,是专注于多场景下的全能型屏幕批注工具!** 所以本篇文章将通过一下几个方面,全方位地介绍一下智绘教,以及我眼中未来的智绘教。 ## 软件起源 智绘教严格意义上起源于 2022 年 5 月,当时我只是有想法尝试开发一些屏幕的画板工具用于 OI 竞赛。我进行了一些尝试,并通过在网上查找资料学习了抗锯齿绘图方法和一些数学知识(比如贝塞尔曲线)。2019 年我从小学五年级的寒假接触了 EasyX 这个绘图库,这个库很容易上手。当时我主要通过这个绘图库做一些游戏,已经算是比较熟悉这个库了。加上我当时刚起步搞 OI(信息学奥林匹克竞赛),EasyX 同样也是使用的 C++,这就是一个很方便的选择。后来我也尝试过 EGE,但是它的文档对于那时小学的我来说太深奥了,所以并没有深入。 到了 2022 年 8 月,我认识了 huidong 大佬,以及他所开发的 HiEasyX 库(可以当做 EasyX 的拓展库),这个库拥有许多丰富的功能,以及可以实现我之前难以实现的许多功能,我迅速了解了这个库,并上手使用。 可以说,HiEasyX 对于智绘教拥有至关重要的作用,我在后来对智绘教的开发中,我成为了 HiEasyX 的一位贡献者,我一边开发智绘教,一边完善 HiEasyX,智绘教的许多需求,都是在 HiEasyX 中实现的。 2023 年 2 月,智绘教正式立项。一次班上的数学老师在使用 AiClass 的屏幕画板时,由于操作失误。导致辛苦写了一节课的笔迹灰飞烟灭,也没法撤回……所以我要开发一个工具,提高课堂效率,使屏幕批注更容易。 ## 初期起步 我最初仿照的是 AiClass 的 UI 设计,主要是为了让数学老师习惯使用。我开始实现了最基础的几个功能。并一针见血解决了当下的问题,添加了恢复画板的功能。并以此向各课老师推荐,并得到了肯定和支持。 ## 发展理念 智绘教从一开始就不是追求丰富功能,或者界面有多么高大上。一切都是从极致化的体验出发,专注于解决当下主要软件的痛点。软件的设计从一开始就遵从触摸屏的操作逻辑,目前来看对于 PC 鼠标不是非常友好,这也是需要改进的。许多细节的设计汇水成河,打造了优势壁垒,切实地提高了课堂效率。 智绘教初期的应用场景是: * Word/PDF 等屏幕批注 * PPT 演示批注 * 未来的 PC 网课演示 有人会想让我加个白板等等,我只能说这不是智绘教的重心,智绘教的重心工作还不够完美,还得深造。 ## 艰辛探索 智绘教构建于 C++ 和 HiEasyX 绘图库,界面 UI 和绘图绘制均是手写实现的。不同于 Ink Canvas、Inkways 等成熟工具,其使用的是 C# 语言,对于界面的开发较简单。我需要花费许多时间,用于 UI 设计上,尽管还不是非常完美。从最开始的两个程序到如今一个程序的多窗口绘图,从最当初的简陋 UI 当目前的 UI2.0 丝滑动画……智绘教发展了很多,有着翻天覆地的变化。 *** ::: tip 上方内容完成于 2024 年 4 月 ::: *** ![](/ui20.png) 现在时间来到了 2025 年 8 月,Inkeys2 基本结束了,接下来是制作 Inkeys3。 ## 为什么开发进度缓慢? 时间经过了一年多,似乎只有选项界面有了非常大的改变,其他都是一些拓展的功能。其实吧,写功能还是挺快的,唯一感觉拖后腿的就是界面的设计与开发。 不同于 .NET 和 QT 中可以轻松上手的 UI 库,智绘教的主栏依然采用的是自制的简易框架自绘 UI,写起来需要考虑很多。不然后期维护很麻烦。而选项界面就使用的是 Dear Imgui,这个库非常方便,但是它并不是为了这种用户交互场景所设计,所以样式一般,并且内存占用大。 之前的选项界面过于简陋,所以从 2025 年初开始,我就将选项页面的风格开始朝着 fluent2 模仿,而且使用 Dear Imgui 模仿,难度较高。加上 imgui 的传参不是很统一,所以我也不好封装。例如最简单的开关控件,我也搞了十几行来实现风格样式的调节。 ## 为什么现阶段内存占用还是那么大? 只能说早期在 1080P 下对内存占用不是很敏感,并没有预先打算。绘图方面则采用逻辑较为简单的位图方案(也就是用图片表示画布,而不是用数字表示墨迹的矢量方案),而矢量方案就可以解决很多内存,但是实际写起来也不是那么轻松。加上目前还有 5 个窗口,每个窗口都需要一个背景画布,而且这些窗口是全屏的,也就是说分辨率越高占用越大。 > 简单来说,一个 4K 的画布就要花费 32MB 左右,这个数字不小了。 Dear Imgui 新版本带来的优化:在它 1.92.0 版本之后,引入了动态字体绘制,我通过升级到 1.92.1,让内存减少了 150+ MB(在 1080P 下),属于巨大提升了。 后期当然要对这个进行优化,期望在 1080P 下,内存占用 < 150MB 吧。 ::: tip To be continue …… 上方内容完成于 2025 年 8 月 ::: --- --- url: /link.md --- # 相关链接 ## 联系我们 * QQ 用户群:[`618720802`](https://qm.qq.com/q/wZnY4enpmw) * 开发者 QQ:[`2685549821`](https://tool.gljlw.com/qq/?qq=2685549821) * 开发者 Email: [`alan-crl@foxmail.com`](mailto:alan-crl@foxmail.com) * [问题/建议反馈](https://www.wjx.cn/vm/mqNTTRL.aspx#) ## 其他 *** *** > 本站基于 Vuepress 2 的 [Plume](https://theme-plume.vuejs.press/) 主题构建。感谢优秀的 Web 技术搭建了眼前这么出色的网站! --- --- url: /standard/blocks/canvas.md --- # Canvas 块 * Type ID: 2 * Type: Map * Required Canvas 是扁平内容流中的页面图层记录。使用显式注册表时,它通过 GUID 分别引用 Workspace 与 Device;使用隐式单例时,它省略对应 GUID。Canvas 后面的 Ink、Shape 和 Media 归属该 Canvas,作用域在下一个 Canvas 或文件末尾结束。 ## 字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `type` | uint16 | Required | 固定为 `2` | | `workspaceGuid` | string(36) | Conditional | 使用显式 Workspace 注册表时必填 | | `deviceGuid` | string(36) | Conditional | 使用显式 Device 注册表时必填 | | `pageGuid` | string(36) | Required | 逻辑页面的永久 UUID | | `pageIndex` | uint32 | Required | Workspace 内从 0 连续的当前页序 | | `pageNumber` | uint32 | Required | 用户界面显示页码,不参与排序 | | `layerIndex` | uint32 | Required | 同一设备页面内从 0 连续的图层索引 | | `layerNumber` | uint32 | Required | 用户界面显示图层号,不参与排序 | | `slideId` | int32 | Conditional | PPT Workspace 必填的 PowerPoint COM `SlideID` | | `viewport` | Map | Conditional | 仅 `layerIndex = 0` 可以保存;Device 可见区域对应的 Canvas 世界坐标与统一缩放 | | `extra` | Map | Optional | 私有扩展 | Canvas 不保存自身边界几何,其显示视口始终填满对应的显式或隐式 Device。Ink、Shape 与 Media 使用平台无关的 Canvas 逻辑像素;`viewport` 只决定这些世界坐标如何映射到 Device 局部逻辑像素,不修改内容本身的坐标。 ## Viewport Map | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `x` | float32 | Required | Device 左上角对应的 Canvas 逻辑 X,可为负数 | | `y` | float32 | Required | Device 左上角对应的 Canvas 逻辑 Y,可为负数 | | `scale` | float32 | Required | Device 逻辑像素 / Canvas 逻辑像素,必须为有限正数 | `viewport.x/y` 使用 Canvas 世界坐标。它们与 Display Device 的系统绝对 `x/y`、Window Device 的父级相对 `x/y` 没有继承或换算关系。 Canvas 世界坐标到 Device 局部坐标的映射为: ```text deviceX = (canvasX - viewport.x) * viewport.scale deviceY = (canvasY - viewport.y) * viewport.scale ``` 反向映射为: ```text canvasX = deviceX / viewport.scale + viewport.x canvasY = deviceY / viewport.scale + viewport.y ``` `scale = 1` 表示一 Canvas 逻辑像素对应一 Device 逻辑像素,`2` 表示放大两倍,`0.5` 表示缩小到一半。Device 当前可见的 Canvas 世界宽高分别为 `Device.width / scale` 与 `Device.height / scale`。物理像素和 DPI 不参与该公式。Device 或窗口尺寸改变时保持 viewport 左上角不变,并向右下改变可见范围。 `viewport` 缺失时默认 `{ x: 0, y: 0, scale: 1 }`。UInk 1.0 不注册视口旋转、错切或 X/Y 非等比缩放。 ### 页面归属与权威层 为避免显式 GUID 与隐式单例产生歧义,本文使用以下逻辑键:`workspaceKey` 是显式 `workspaceGuid` 或文件内隐式 Workspace 单例,`deviceKey` 是显式 `deviceGuid` 或文件内隐式 Device 单例。`viewport` 归属于 `(workspaceKey, deviceKey, pageGuid)`。同一页面在不同 Device 上可以使用不同 `viewport`。 只有同页同 Device 的 `layerIndex = 0` Canvas 可以保存 `viewport`,其他图层必须省略并继承第 0 层。第 0 层缺失 `viewport` 或 `viewport` 无效时,所有图层统一使用默认值。读取器遇到非第 0 层的 `viewport` 时忽略该字段并警告,不得用它覆盖第 0 层状态。 `viewport` 适用于所有 Workspace 类型。软件可以禁止用户在屏幕批注、白板或 PPT 中平移缩放,但合法的非默认 `viewport` 必须按照相同公式解释。 ## 页面身份、排序与唯一性 * `pageGuid` 在整个 UInk 文件中永久唯一,在完整保存或页面重排时保持不变;复制为新页面时必须生成新 UUID。 * 复制页面时,新页面继承源页面的 `viewport`;软件可以在复制后调整并保存新的最终值。 * 同一逻辑页跨设备、跨图层共享 `pageGuid`。 * 同一 Workspace 内,`pageGuid` 与 `pageIndex` 严格一一对应,`pageIndex` 从 0 开始且无空洞。 * 每个 `(workspaceKey, deviceKey, pageGuid)` 下的 `layerIndex` 从 0 开始且无空洞;不同 Device 允许具有不同图层数量。 * `(workspaceKey, deviceKey, pageGuid, layerIndex)` 是 Canvas 唯一键,在同一文件内不得重复。 * 同页同 Device 中 `layerIndex` 越大越靠前;该合成顺序不依赖 Canvas 的物理排列。 * `pageNumber` 与 `layerNumber` 仅供显示,允许跳号或重复。 * Canvas 块在对象流中的排列不决定合成顺序。为便于流式读取和人工检查,写入器应依次按 Workspace 注册顺序、`pageIndex`、Device 注册顺序和 `layerIndex` 排列 Canvas;隐式单例只有一个注册顺位。 ## 多显示器白板 同步翻页使用同一个 Workspace:同一页在多个 Device 上具有相同 `pageGuid` 和 `pageIndex`,但每个 Device 使用独立 Canvas、独立 Ink/Shape/Media、独立 `contentId` 与 `undoId`。UInk 不同步不同屏幕上的绘制内容。 同一逻辑页在不同 Device 上可以保存不同 viewport;每个 Device 内由第 0 层保存唯一 viewport。 各屏幕独立翻页时使用多个 Workspace,每个 Workspace 维护自己的页面序列。 ## PPT 锚定 `workspaceType = 2` 时,Canvas 必须保存 `slideId`。读取器使用 `Slides.FindBySlideID` 定位幻灯片。定位失败时,读取器必须保留该 Canvas,将其标记为未绑定并提示宿主绑定失效;不得按 `pageIndex`、当前页或其他幻灯片自动重新附着。用户或宿主可以通过显式重新绑定流程选择新幻灯片,随后执行完整保存。 同一 PPT 页面跨设备显示时共享 `pageGuid` 和 `slideId`,但仍使用独立 Canvas 内容。 ## 示例 ```jsonc { "type": 2, "workspaceGuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "deviceGuid": "11111111-1111-4111-8111-111111111111", "pageGuid": "cccccccc-cccc-4ccc-8ccc-cccccccccccc", "pageIndex": 0, "pageNumber": 1, "layerIndex": 0, "layerNumber": 0, "slideId": 256, "viewport": { "x": -320.0, "y": 180.0, "scale": 1.5 }, "extra": {} } ``` 该 Canvas 可以不包含任何 Ink/Shape/Media,用于保存用户已创建但尚未绘制的空白页或图层。每个显式 Workspace 至少应包含一个 Canvas。 ## 容错 使用显式注册表时,如果 `workspaceGuid` 或 `deviceGuid` 缺失或无法解析,读取器可以构造仅供本次加载使用的临时 Workspace 或根 Device,并报告警告。页面身份或 `pageIndex` 缺失或无效时,读取器可以按 Canvas 在对象流中的先后顺序生成临时独立页面;`layerIndex` 缺失或无效时,应在对应临时页面下按对象流顺序生成临时图层。上述临时身份只用于本次加载。 第 0 层 `viewport` Map 缺少任一必填字段、`x/y` 包含 NaN/Infinity,或 `scale` 非正、包含 NaN/Infinity 时,整个 `viewport` 无效并回退默认值。非第 0 层 `viewport` 一律忽略。所有默认值、继承和容错结果均不得自动回写源文件。 --- --- url: /standard/blocks/device.md --- # Device 结构 * Type: Map * Registry Entry Device 是 [Header Extension](headerExtension) 的 `devices` 数组中的显示面注册项,不是顶级块,也不形成文件流作用域。使用显式 Device 注册表时,Canvas 通过 `deviceGuid` 引用一个 Device;注册表缺失时,省略 `deviceGuid` 的 Canvas 使用文件内隐式 Device 单例。Canvas 的显示视口始终填满对应显示面。Device 与 Canvas 坐标统一使用平台无关的逻辑像素。 Device 只描述显示面在系统或父 Device 中的位置与大小,不保存页面正在查看的 Canvas 世界坐标。Canvas 的平移和缩放状态由 [Canvas.viewport](canvas#viewport-map) 保存;Device 的 `x/y` 不得作为 `viewport` 的默认值或替代值。 ## 公共字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `guid` | string(36) | Required | Device 的永久 UUID | | `deviceType` | int32 | Required | Device 类型 | | `name` | string | Optional | 显示名称 | | `hardware` | Map | Optional | 物理显示器匹配信息 | | `extra` | Map | Optional | 私有扩展 | | 值 | 名称 | 说明 | | --- | --- | --- | | `0` | Display | 物理显示器在系统虚拟桌面中提供的逻辑显示区域 | | `1` | Window | 相对父 Device 的窗口或板中板区域 | | `2`–`127` | Reserved | UInk 后续版本保留 | | `128` 及以上 | Private | 软件私有显示面 | `128+` 私有编号没有全局厂商命名空间,只保证预先约定的实现之间互操作。读取器遇到未知 `deviceType` 时,应将对应 Device 作为仅供本次加载使用的根显示面,并报告警告;不得把该容错结果自动写回文件。 ## Display Device Display 增加以下必填字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `x` | int32 | 系统虚拟桌面的逻辑 X 原点,可为负数 | | `y` | int32 | 系统虚拟桌面的逻辑 Y 原点,可为负数 | | `width` | uint32 | 显示区域逻辑宽度,必须大于 0 | | `height` | uint32 | 显示区域逻辑高度,必须大于 0 | ### Hardware Map `hardware` 的所有字段均为可选匹配信息: | 字段 | 类型 | 说明 | | --- | --- | --- | | `name` | string | 硬件报告的显示名称 | | `id` | string | 平台提供的硬件标识 | | `identifiers` | `Map` | 其他硬件标识;键和值都必须是 string | | `physicalWidth` | uint32 | 原生物理像素宽度,存在时必须大于 0 | | `physicalHeight` | uint32 | 原生物理像素高度,存在时必须大于 0 | | `scaleFactor` | float32 | 物理像素 / 逻辑像素,存在时必须为有限正数 | 物理像素、DPI 或缩放因子不参与 Canvas 线格式坐标计算,也不得覆盖 Display 保存的逻辑几何。硬件标识无法匹配时,读取器仍应使用保存的逻辑几何或当前渲染目标继续加载。 ## Window Device Window 增加以下必填字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `parentDeviceGuid` | string(36) | 父 Display 或 Window 的 UUID | | `x` | float32 | 相对父 Device 的逻辑 X | | `y` | float32 | 相对父 Device 的逻辑 Y | | `width` | float32 | 窗口逻辑宽度,必须大于 0 | | `height` | float32 | 窗口逻辑高度,必须大于 0 | | `zIndex` | uint32 | 同一父 Device 下的合成顺序,越大越靠前 | Window 可以嵌套 Window。`zIndex` 越大越靠前;出现相同 `zIndex` 时按 `devices` 数组从前到后合成,后项位于前项之上。Window 可以部分越出父区域,宿主负责裁剪不可见部分。 Device 树禁止循环。`parentDeviceGuid` 无法解析或父引用形成循环时,读取器应断开该父引用,把对应 Window 作为仅供本次加载使用的临时根显示面,并报告警告。 ## 示例 ```jsonc [ { "guid": "11111111-1111-4111-8111-111111111111", "deviceType": 0, "name": "Primary Display", "x": 0, "y": 0, "width": 3840, "height": 2160, "hardware": { "id": "DISPLAY\\ACR1234", "identifiers": { "serial": "12345678" } } }, { "guid": "22222222-2222-4222-8222-222222222222", "deviceType": 1, "name": "板中板", "parentDeviceGuid": "11111111-1111-4111-8111-111111111111", "x": 120.0, "y": 80.0, "width": 1280.0, "height": 720.0, "zIndex": 10 } ] ``` ## 相关说明 * [Canvas 块与 viewport](canvas) * [墨迹主文件](../file/main) --- --- url: /standard/blocks/header.md --- # Header 块 * Type ID: 0 * Type: Array Header 是墨迹主文件的固定首块,保存文件身份、规范版本以及最近一次完整保存时的统计快照。 ## 结构 ```text Header = array(7) ``` | 索引 | 字段 | 类型 | MessagePack 类型 | 负载字节长度 | | --- | --- | --- | --- | --- | | 0 | `type` | uint16 | uint16 | 2 bytes | | 1 | `version` | uint16 | uint16 | 2 bytes | | 2 | `guid` | string(36) | str8 | 36 bytes | | 3 | `deviceNum` | uint32 | uint32 | 4 bytes | | 4 | `workspaceNum` | uint32 | uint32 | 4 bytes | | 5 | `pageNum` | uint32 | uint32 | 4 bytes | | 6 | `time` | uint64 | uint64 | 8 bytes | ::: warning 固定布局 写入器必须严格保持 `array(7)`、字段顺序、表中声明的数值宽度以及 `guid` 的 str8 编码,不得使用 MessagePack 的最小整数自动编码替代固定宽度类型。 读取器必须验证数组长度、字段顺序和 36 字符 UUID 字符串。数值字段可以按[公共数值容错规则](../type#messagepack-编码)接受可无损转换的其他 MessagePack 编码。 ::: ## 字段说明 :::: field-group ::: field type @required 固定为 `0`,参见[块类型](../type)。 ::: ::: field version @required 当前 UInk 1.0 Beta 使用规范版本号 `10`,参见[规范版本](../version)。 ::: ::: field guid @required UInk 文件首次创建时生成的 36 字符 UUID,格式为 `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`。 `guid` 标识同一个逻辑 UInk 文件。增量写入、完整保存、移动或重命名文件时均不得改变它;“另存为”新的逻辑文件时必须生成新的 UUID。 ::: ::: field deviceNum @required 最近一次完整保存时的 Device 逻辑项总数。显式注册表统计 Display 与 Window;使用隐式默认 Device 时固定为 `1`。 ::: ::: field workspaceNum @required 最近一次完整保存时的 Workspace 逻辑项总数。使用隐式默认 Workspace 时固定为 `1`。 ::: ::: field pageNum @required 最近一次完整保存时各 Workspace 逻辑页数之和。同一 Workspace 中共享 `pageGuid` 的多个设备或图层只计一页;空白页也必须计入。 ::: ::: field time @required 最近一次完整保存完成时的 Unix UTC 时间戳,单位为秒。 ::: :::: ## 示例 ```json [ 0, 10, "5fe30f46-be92-49b6-b921-a60706febf10", 2, 1, 12, 1700000000 ] ``` ## 快照与实际对象流 增量追加期间不得原地修改 Header。追加新页面后,`pageNum` 和 `time` 可以暂时落后于实际对象流。读取器必须从完整有效的 Header Extension、Canvas 和内容块重算当前状态,并将 Header 统计仅作为快照使用;不得因快照不一致拒绝文件,也不得按 Header 计数进行不受限预分配。 完整保存时,写入器必须重新计算所有快照字段,把 Header 与其余对象写入临时主文件,再用临时主文件整体替换目标文件。同一逻辑文件的完整保存不得改变 `Header.guid` 或 `Header.version`。 --- --- url: /standard/blocks/headerExtension.md --- # Header Extension 块 * Type ID: 1 * Type: Map * Optional Header Extension 保存文件说明,并注册 Canvas 可以引用的 Device 与 Workspace。Device 树描述显示空间,Workspace 树描述逻辑页面与宿主关系,两棵树彼此独立。任一注册表缺失时,由文件内唯一的对应隐式单例代替。 ## 位置与字段 Header Extension 最多出现一次;若存在,必须紧跟 Header。Header Extension 之后只能是第一个 Canvas 或文件末尾。Ink、Shape 和 Media 必须出现在某个 Canvas 之后。 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `type` | uint16 | Required | 固定为 `1` | | `name` | string | Optional | 文件显示名称 | | `explanation` | string | Optional | 文件说明 | | `devices` | `Array` | Optional | Device 注册表 | | `workspaces` | `Array` | Optional | Workspace 注册表 | | `extra` | Map | Optional | 文件级私有扩展 | `devices` 和 `workspaces` 中的 `guid` 在各自注册表内不得重复。注册表出现循环、重复 UUID 或损坏条目时,读取器应报告警告,并只在内存中建立供本次加载使用的修复结果。读取器不得把容错结果自动写回源文件。 ## 隐式默认项 Header Extension 整体缺失,或者 `devices` / `workspaces` 注册表缺失或为空时,读取器必须为缺失的注册表建立一个隐式默认项: * Device 使用当前渲染目标的根显示区域; * Workspace 使用 `workspaceType = 0` 的通用屏幕批注工作区; * Canvas 可以省略对应的 `deviceGuid` 或 `workspaceGuid`; * Header 中对应的 `deviceNum` 或 `workspaceNum` 必须写为 `1`。 隐式默认项是当前文件内部唯一的逻辑单例,不具有可序列化 UUID。Canvas 唯一键、viewport 归属、页面计数和内容作用域在缺失 GUID 时都使用该单例;不同读取器不得为它生成并回写随机 UUID。 某一注册表包含显式条目时,Canvas 必须写入该类条目的 GUID,且该 GUID 必须能解析到注册项。同一个 Device 或 Workspace 注册表内不得混用显式条目与隐式默认项。一个注册表使用显式条目、另一个注册表使用隐式单例是合法的。 ## Workspace 注册项 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `guid` | string(36) | Required | Workspace 的永久 UUID | | `workspaceType` | int32 | Required | 工作区类型 | | `name` | string | Optional | 工作区显示名称 | | `parentWorkspaceGuid` | string(36) | Optional | 父 Workspace UUID | | `hostId` | string | Optional | PPT、白板等宿主的稳定匹配字符串 | | `currentPageIndex` | uint32 | Optional | 保存时正在显示的页,缺失时为 `0` | | `extra` | Map | Optional | Workspace 私有扩展 | | `workspaceType` | 场景 | 说明 | | --- | --- | --- | | `0` | Screen Annotation | 屏幕批注 | | `1` | Whiteboard | 白板 | | `2` | Presentation | PPT / 演示文稿 | | `3`–`127` | Reserved | UInk 后续版本保留 | | `128` 及以上 | Private | 软件私有类型 | `128+` 私有编号没有全局厂商命名空间,只保证预先约定的实现之间互操作。读取器遇到未知 `workspaceType` 时,必须按通用白板加载并保留 Canvas 与内容,但不得执行无法识别的宿主绑定。`currentPageIndex` 缺失或没有对应页面时,读取器回退到第 0 页并报告警告。 Workspace 可以多级嵌套。合成与容错规则如下: 1. 子 Workspace 跟随父 Workspace 的可见性和生命周期,并合成在父 Workspace 之上。 2. 同级 Workspace 按 `workspaces` 数组顺序从前到后合成;数组中的后项位于前项之上。 3. 父子 Workspace 不要求引用相同的 Device,也不要求所引用的 Device 具有父子关系。 4. 父引用形成循环时,读取器应断开产生该循环的父引用,将对应 Workspace 作为仅供本次加载使用的临时根项,并报告警告。 每个显式 Workspace 至少应有一个 Canvas;没有内容的 Canvas 表示已经创建的空白首页。 ::: note PPT 宿主绑定 PPT Workspace 推荐把稳定标识写入 `Presentation.Tags`,并在 `hostId` 保存同一值。每个 PPT Canvas 仍使用 COM `SlideID` 定位具体幻灯片。 ::: ## 示例 ```jsonc { "type": 1, "name": "课堂白板与演示", "devices": [ { "guid": "11111111-1111-4111-8111-111111111111", "deviceType": 0, "x": 0, "y": 0, "width": 3840, "height": 2160 } ], "workspaces": [ { "guid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "workspaceType": 2, "name": "课程演示", "hostId": "INKKEYS-PPT-7B58E2A1", "currentPageIndex": 3 }, { "guid": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb", "workspaceType": 1, "name": "演示内白板", "parentWorkspaceGuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" } ], "extra": {} } ``` `extra` 是字符串键到任意 MessagePack 值的 Map。写入器必须把私有文件级字段放入 `extra`;读取器仍应忽略未知顶层键。UInk 不为私有键提供全局命名空间,跨软件使用前必须自行约定。 --- --- url: /standard/blocks/ink.md --- # Ink 块 * Type ID: 3 * Type: Map Ink 表示一条完整墨迹。擦除、普通笔、荧光笔和高级荧光笔都是 Ink 的渲染类型,不再使用独立的 `penType` 或 Eraser 顶层块。 ## 字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `type` | uint16 | Required | 固定为 `3` | | `contentId` | uint32 | Required | Canvas 内 Ink/Shape/Media 共享的连续内容编号 | | `undoId` | uint32 | Required | Canvas 内非递减的撤回操作分组编号 | | `inkType` | int32 | Required | 墨迹渲染类型 | | `color` | Color Map | Required | 块级颜色与 HDR 回退信息 | | `opacity` | float32 | Required | 块级透明度,范围 `0`–`1` | | `texture` | int32 | Required | 纹理编号 | | `points` | `Array` | Required | 至少一个轨迹点 | | `renderOnlyWhenLatest` | bool | Optional | 缺失时为 `false` | | `extra` | Map | Optional | 私有扩展 | `contentId` 与 Shape/Media 共用同一编号空间,并严格按照顶层对象流中的先后顺序从 0 连续递增。`undoId` 从 0 开始且只允许不递减;对象流中 `undoId` 相同且连续的内容块构成一次撤回操作。 `contentId` 只标识当前文件版本中当前 Canvas 的对象流顺序。完整保存会重新整理编号,其他文件、外部元数据或后续文件版本不得把它当作稳定对象身份。 ## `inkType` | 值 | 名称 | 语义 | | --- | --- | --- | | `0` | Erase | 擦除墨迹 | | `1` | Pen | 普通笔 | | `2` | Highlighter | 荧光笔 | | `3` | Advanced Highlighter | 高级荧光笔 | | `4`–`127` | Reserved | UInk 后续版本保留 | | `128` 及以上 | Private | 软件私有墨迹类型 | `128+` 私有编号没有全局厂商命名空间,只保证预先约定的实现之间互操作。其他读取器遇到未知或不支持的 `inkType` 时,必须保留基础几何并按 `inkType = 1` 普通笔回退。 ### 四种通用渲染规则 * Erase 保存完整擦除形状,并按对象流顺序作用于同一 Canvas 中位于它之前的 Ink 与 Shape,不作用于 Media。具体裁剪、透明和背景效果由软件决定。 * Pen 使用块级 `color` 和 `opacity`。笔刷外形、线帽和连接方式仍由软件决定,不以是否支持透明度区分普通笔与荧光笔。 * Highlighter 使用块级 `color` 和 `opacity`。渲染器必须先把整条笔迹生成一次完整覆盖,再将该覆盖作为一个整体以 alpha source-over 合成到画布;不得逐采样段反复合成而在段间重叠处累加透明度。 * Advanced Highlighter 使用相同的“整条覆盖后合成一次”规则,但部分点可以提供颜色与透明度锚点;没有任何点级样式时使用块级样式。 ## Color Map Ink 的颜色字段使用公共 [Color Map](../common/color),同时提供基础 SDR 回退色和可选 HDR 色彩空间数据。该结构也供 Shape 的填充和描边使用。 ## `texture` | 值 | 语义 | | --- | --- | | `0` | 默认普通纹理 | | `1`–`127` | UInk 标准纹理保留区 | | `128` 及以上 | 软件私有纹理 | 读取器不认识某个纹理时必须按 `texture = 0` 回退,不得丢弃整条 Ink。 ## 轨迹点 每个点使用 Map: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `x` | float32 | Required | 首点为绝对 X,后续点为相对前一点的 X 位移 | | `y` | float32 | Required | 首点为绝对 Y,后续点为相对前一点的 Y 位移 | | `width` | float32 | Required | 该点处笔迹的完整直径,必须大于 0 | | `color` | Color Map | Conditional | 高级荧光笔的点级颜色 | | `opacity` | float32 | Conditional | 高级荧光笔的点级透明度 | 点级 `color` 和 `opacity` 必须成对出现。首个样式锚点之前沿用首个锚点的样式,最后一个锚点之后沿用最后一个锚点的样式;锚点之间必须平滑过渡,但具体插值方法由软件决定。 点列定义有序中心位置和完整直径,不注册唯一曲线、包络、线帽、连接或宽度插值算法。读取器必须保持点顺序、位置和宽度语义,但自由墨迹的最终轮廓可以因实现而不同;单点 Ink 也由软件按同一笔刷语义呈现。 UInk 1.0 不注册压力、时间、倾斜、朝向、速度、加速度或预测点。读取器必须忽略不认识的点键,以便后续版本增加可选输入参数。 ::: tip float32 范围 float32 足以覆盖 16K 和多显示器坐标,并保持优于 0.1 px 的精度。首点绝对、后续相对的设计用于减少位移数值范围,同时仍保留亚像素精度。 ::: ## 条件渲染与撤回 Ink 和 Shape 共享 `renderOnlyWhenLatest` 规则。读取器必须对当前 Canvas 执行以下判定: 1. 从最后一个内容块开始反向扫描。 2. 遇到 Media 时直接越过;Media 不加入末尾最新组,也不终止扫描。 3. 遇到 `renderOnlyWhenLatest = true` 的 Ink/Shape 时,将其加入末尾最新组并继续反向扫描。 4. 遇到第一个未标记或标记为 `false` 的 Ink/Shape 时停止扫描。文件中更早的标记 Ink/Shape 不属于末尾最新组。 5. 正常显示末尾最新组和所有未标记的 Ink/Shape,隐藏不属于末尾最新组的标记 Ink/Shape。末尾最新组可以为空。 该机制适用于形状修正:软件先保存多条原始 Ink/Shape,并将它们的 `renderOnlyWhenLatest` 设为 `true`,再保存未标记的结果 Shape。结果 Shape 存在时,反向扫描会在该未标记 Shape 处停止,因此标记原稿隐藏。撤回结果并执行完整保存后,原稿成为末尾最新组并重新显示。 末尾最新组只影响显示,不合并或修改 `undoId`。撤回结果后,用户仍按原稿各自的 `undoId` 逐步撤回。隐藏但未撤回的原稿是当前有效内容,完整保存必须保留;UInk 不承诺在保存并关闭后保留 Redo 历史。 ## 擦除模型 ### 擦除墨迹 `inkType = 0` 保存完整的擦除轨迹,可以像其他 Ink 一样在抬笔后追加。追加 Erase Ink 不要求修改此前的内容块。读取器按对象流顺序,将 Erase Ink 作用于同一 Canvas 中位于它之前的 Ink 与 Shape;Media 始终不受影响。 ### 普通板擦 软件也可以采用会修改或切断既有 Ink/Shape 的普通板擦。写入器必须把擦除结果归一化为当前有效的完整对象,并执行完整保存;不得通过追加使旧对象与新片段同时存在。由同一次擦除产生的多个结果片段可以共享同一个 `undoId`,以便一步撤回全部片段。 ## 示例 以下均为 MessagePack Map 的可读伪 JSON 表示。 ::: tabs @tab 普通笔 ```jsonc { "type": 3, "contentId": 0, "undoId": 0, "inkType": 1, "color": { "fallback": 255 }, "opacity": 0.4, "texture": 0, "points": [ { "x": 120.0, "y": 240.0, "width": 6.0 }, { "x": 4.5, "y": 1.0, "width": 6.2 } ] // 普通笔使用块级 opacity,此处按 0.4 绘制 } ``` @tab 高级荧光笔与 HDR ```jsonc { "type": 3, "contentId": 1, "undoId": 1, "inkType": 3, "color": { "fallback": 16776960 }, "opacity": 0.35, "texture": 0, "points": [ { "x": 100.0, "y": 100.0, "width": 24.0, "color": { "fallback": 16763904, "space": "scrgb", "components": [1.8, 0.65, 0.1] }, "opacity": 0.25 }, { "x": 12.0, "y": 3.0, "width": 25.0 }, { "x": 10.0, "y": 4.0, "width": 26.0, "color": { "fallback": 65535 }, "opacity": 0.6 } ] } ``` @tab 擦除墨迹 ```jsonc { "type": 3, "contentId": 2, "undoId": 2, "inkType": 0, "color": { "fallback": 0 }, "opacity": 1.0, "texture": 0, "points": [ { "x": 320.0, "y": 180.0, "width": 32.0 }, { "x": 8.0, "y": -2.0, "width": 32.0 } ] } ``` ::: ## 容错 * 有限但越界的 `opacity` 应钳制到 `0`–`1`;NaN/Infinity 使对应字段无效。 * Ink 没有点、点结构损坏或缺少必填字段时,读取器应跳过该 Ink,报告警告并继续读取后续内容。 * 写入器必须把块级私有字段放入 `extra`;读取器仍应容错忽略未知顶层键。 ## 相关说明 * [墨迹主文件与混合顺序](../file/main) * [增量写入](../incremental) * [Canvas 块](canvas) * [Shape 块](shape) * [Color Map](../common/color) --- --- url: /standard/blocks/media.md --- # Media 块 * Type ID: 4 * Type: Map Media 在墨迹主文件中保存资源引用、顺序、撤回分组和呈现参数。实际资源位于对应的 `.uink.extra` ZIP;ZIP 只是资源容器,不包含额外索引。 ## 基础字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `type` | uint16 | Required | 固定为 `4` | | `contentId` | uint32 | Required | Canvas 内 Ink/Shape/Media 共享的连续内容编号 | | `undoId` | uint32 | Required | 与 Ink/Shape 共享的撤回操作分组 | | `path` | string | Required | `.uink.extra` 内的安全相对路径 | | `mimeType` | string | Required | 资源声明的 MIME 媒体类型 | | `extra` | Map | Optional | 私有扩展 | `contentId` 按 Ink、Shape 与 Media 在顶层对象流中的先后顺序从 0 连续递增。对象流中 `undoId` 相同且连续的 Ink/Shape/Media 构成同一步撤回。 `contentId` 只标识当前文件版本中当前 Canvas 的对象流顺序,完整保存后不得作为稳定外部引用。 ## 资源路径 `path` 是 UTF-8 字符串,写入前必须规范化为 Unicode NFC,并相对于 `.uink.extra` 根目录使用 `/` 分隔。路径必须满足: * 不以 `/` 开头,不是 URI、盘符路径或其他绝对路径; * 不包含 `\`、NUL、控制字符、空路径段、`.` 或 `..`; * 每个 ZIP 条目也使用相同的 NFC 规范化路径; * 规范化后的 ZIP 条目路径不得重复。重复条目使相关资源不可用,读取器不得选择“第一个”或“最后一个”静默继续。 读取器不得把不受信任的 ZIP 直接解压到工作目录。每个资源必须按以下顺序处理: 1. 在读取条目、分配缓冲区或启动解码器前,检查实现定义的资源预算。预算至少覆盖条目数、单条目大小、总解压大小和压缩比;UInk 不规定统一数值。 2. 流式读取、解压和解码时持续累计实际消耗,不得只信任 ZIP 声明大小或其他预先元数据。 3. 实际输出超过任一预算时,立即停止处理当前资源,并把该资源视为缺失;不得影响基础 Ink/Shape 或后续内容块。 `.uink.extra` 资源包不存在,或者 `path` 指向的 ZIP 条目不存在时,读取器必须保留 Media 的布局与顺序,并提示媒体缺失;是否绘制可见占位符由软件决定。`mimeType` 未知、声明类型与安全嗅探结果明显不一致,或者解码器拒绝内容时,读取器都必须把该资源视为不可用,并继续读取后续块。 SVG 必须按非活动图像处理。默认禁用脚本、事件处理器、外部网络资源、外部文件引用和其他可执行内容;无法安全降级时不渲染该资源。 ## 视觉媒体 图片、SVG、视频和 PDF 页面等视觉媒体增加: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `width` | float32 | Required | 变换前的 Canvas 逻辑宽度,必须大于 0 | | `height` | float32 | Required | 变换前的 Canvas 逻辑高度,必须大于 0 | | `transform` | `Array(6)` | Optional | 二维仿射矩阵,缺失时为单位矩阵 | | `opacity` | float32 | Optional | 范围 `0`–`1`,缺失时为 `1` | 视觉媒体的本地几何是左上角为 `(0, 0)`、右下角为 `(width, height)` 的 Canvas 逻辑像素矩形,随后应用 transform。 矩阵按 `[a, b, c, d, e, f]` 保存: ```text x' = a*x + c*y + e y' = b*x + d*y + f ``` 矩阵统一负责缩放、旋转、错切和平移。矩阵缺失、长度错误或包含非有限数时,读取器使用单位矩阵并报告警告。 ## PDF 文档媒体 UInk 1.0 注册 `application/pdf` 为标准文档媒体。Word、PowerPoint 等格式可以作为软件私有扩展使用,但本版本不保证跨软件互操作。 PDF Media 是一个单页视觉视口,使用视觉媒体的 `width`、`height`、`transform` 与 `opacity` 控制当前页面。可以增加: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `pageCount` | uint32 | Optional | 文档总页数,存在时必须大于 0 | | `pageIndex` | uint32 | Optional | 当前页面的 0 起始索引,缺失时为 `0` | 能解析 PDF 资源时,实际页数具有最高优先级;与 `pageCount` 不一致时采用实际页数并警告。非法 `pageCount` 应被忽略,越界 `pageIndex` 应钳制到实际有效范围。 资源缺失时,读取器可以使用 `pageCount` 和 `pageIndex` 显示页数占位信息;缺少 `pageCount` 时仍应保留 Media 的布局占位,不得影响基础墨迹。 ## 音视频播放 音频和视频可以包含: | 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `autoplay` | bool | `false` | 加载 Canvas 时自动播放 | | `loop` | bool | `false` | 循环播放 | | `volume` | float32 | `1` | 音量,范围 `0`–`1` | | `startTime` | float64 | `0` | 媒体内部起播偏移,单位秒 | | `playbackRate` | float32 | `1` | 播放速度,必须为有限正数 | `startTime` 小于 0 时钳制到 0,大于媒体时长时钳制到媒体末尾。非法 `playbackRate` 回退到 1。 自动播放可以受平台权限、静音策略或用户设置限制。读取器不能因为无法执行 `autoplay` 而拒绝 Media。 ## 示例 ::: tabs @tab 图片 ```jsonc { "type": 4, "contentId": 2, "undoId": 1, "path": "images/diagram.png", "mimeType": "image/png", "width": 800.0, "height": 450.0, "transform": [1.0, 0.0, 0.0, 1.0, 120.0, 80.0], "opacity": 0.9 } ``` @tab 音频 ```jsonc { "type": 4, "contentId": 3, "undoId": 2, "path": "audio/explanation.mp3", "mimeType": "audio/mpeg", "autoplay": false, "loop": false, "volume": 0.8, "startTime": 2.5, "playbackRate": 1.0 } ``` @tab PDF 单页视口 ```jsonc { "type": 4, "contentId": 4, "undoId": 3, "path": "documents/lesson.pdf", "mimeType": "application/pdf", "width": 1280.0, "height": 720.0, "transform": [1.0, 0.0, 0.0, 1.0, 80.0, 60.0], "opacity": 1.0, "pageCount": 24, "pageIndex": 5 } ``` ::: ## 容错与扩展 有限但越界的 `opacity` 和 `volume` 应钳制到 `0`–`1`。Media 缺少 `path`、`mimeType` 或当前媒体类型要求的视觉尺寸时,读取器应跳过该 Media 并报告警告,不得影响同一 Canvas 的后续内容。 写入器必须把私有块级字段放入 `extra`;读取器仍应容错忽略未知顶层键。私有字段没有全局厂商命名空间,只保证预先约定的实现之间互操作。 存在 Media 资源时,完整保存先准备并提交 `.uink.extra`,最后原子替换 `.uink` 主文件。新资源包必须暂时保留旧主文件和新主文件引用资源的并集;主文件提交后才可以清理多余 ZIP 条目或整个无用资源包。主文件是当前有效 Media 引用的权威来源,缺失条目按资源不可用处理。完整步骤参见[完整保存提交顺序](../incremental#完整保存提交顺序)。 外部导入或包含未知内容的文件默认另存为。用户明确确认可能丢失未知内容后,软件才可以覆盖原文件。 --- --- url: /standard/blocks/shape.md --- # Shape 块 * Type ID: 5 * Type: Map Shape 表示一个可编辑的参数化图形。它与 Ink、Media 并列存在于 Canvas 内容流中,保存几何、单色填充和单色描边。Shape 不是 Ink 的 `inkType`,也不复用 Ink 的轨迹点。 ## 字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `type` | uint16 | Required | 固定为 `5` | | `contentId` | uint32 | Required | Canvas 内 Ink/Shape/Media 共享的连续内容编号 | | `undoId` | uint32 | Required | Canvas 内非递减的撤回操作分组编号 | | `shapeType` | int32 | Required | 几何类型 | | `geometry` | Map | Required | 由 `shapeType` 决定的几何数据 | | `stroke` | Map | Conditional | 描边样式;Line/Polyline 必填 | | `fill` | Map | Conditional | 闭合 Shape 的填充样式 | | `renderOnlyWhenLatest` | bool | Optional | 与 Ink 共用的尾部显示标记,缺失时为 `false` | | `extra` | Map | Optional | 软件私有扩展 | Shape 至少必须有 `stroke` 或 `fill` 之一。Line/Polyline 必须有 `stroke`,不得有 `fill`。 ## `shapeType` | 值 | 名称 | 语义 | | --- | --- | --- | | `0` | Line | 由两个端点定义的单个线条对象 | | `1` | Polyline | 由至少两个点定义的单个折线对象 | | `2` | Rectangle | 可非等比缩放的矩形 | | `3` | Square | 保持等比语义的正方形 | | `4` | Ellipse | 可非等比缩放的椭圆 | | `5` | Circle | 保持等比语义的圆 | | `6` | Polygon | 至少三个点的闭合多边形 | | `7`–`127` | Reserved | UInk 后续版本保留 | | `128` 及以上 | Private | 软件私有图形类型 | `128+` 私有编号没有全局厂商命名空间,只保证预先约定的实现之间互操作。读取器遇到未知 `shapeType` 时,应跳过该完整 Shape,报告警告并继续读取后续内容。不能把未知几何安全地回退为其他几何时,不得伪造一个不同的 Shape。 `shapeType` 只描述底层几何,不描述线条是否连续。Line/Polyline 的实线、虚线、点线等外观由同一个 Stroke Map 的 `dashArray` 控制,始终作为一个 Shape、一个 `contentId` 和一个可整体编辑的对象保存,不得把可见短线拆成多个 Shape。 ## 几何 ### Point Map Polyline 和 Polygon 的每个点使用 Map: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `x` | float32 | Required | Canvas 绝对 X 坐标 | | `y` | float32 | Required | Canvas 绝对 Y 坐标 | 坐标必须是有限数。Shape 点全部使用绝对坐标,不采用 Ink 的首点绝对、后续点相对编码。 ### Line、Polyline 与 Polygon 这三种几何使用 `points`: * Line 必须恰好有两个点; * Polyline 至少有两个点; * Polygon 至少有三个点,读取器按顺序连接并隐式连接末点与首点;写入器不得重复保存首点。 Polygon 用于三角形等基础多边形,不注册独立 Triangle 类型。Polygon 的填充使用非零环绕规则;软件不得依赖自交多边形获得未定义的填充结果。 ### Rectangle 与 Ellipse Rectangle 和 Ellipse 的 `geometry` 字段为: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `centerX` | float32 | Required | 几何中心 X | | `centerY` | float32 | Required | 几何中心 Y | | `width` | float32 | Required | 最终宽度,必须大于 0 | | `height` | float32 | Required | 最终高度,必须大于 0 | | `rotation` | float32 | Optional | 弧度,Canvas 坐标系正值顺时针,缺失为 `0` | Rectangle 和 Ellipse 允许 `width` 与 `height` 不相等。旋转后仍以这组最终 Canvas 几何显示,不使用通用仿射矩阵。 ### Square Square 的 `geometry` 字段为: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `centerX` | float32 | Required | 几何中心 X | | `centerY` | float32 | Required | 几何中心 Y | | `size` | float32 | Required | 正方形边长,必须大于 0 | | `rotation` | float32 | Optional | 弧度,缺失为 `0` | Square 使用独立类型,以便编辑器在缩放时保持宽高比例。 ### Circle Circle 的 `geometry` 字段为: | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `centerX` | float32 | Required | 圆心 X | | `centerY` | float32 | Required | 圆心 Y | | `radius` | float32 | Required | 半径,必须大于 0 | Circle 不保存 rotation,因为旋转不会改变圆的几何。Circle 使用独立类型,以便编辑器在缩放时保持等比。 ## Stroke Map Stroke 在同一个 Shape 内使用一种颜色、透明度和固定宽度,不支持逐点宽度或颜色。 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `color` | Color Map | Required | 描边颜色,支持 SDR/HDR 回退 | | `opacity` | float32 | Required | 描边透明度,范围 `0`–`1` | | `width` | float32 | Required | 最终可见的 Canvas 描边宽度,必须大于 0 | | `dashArray` | `Array` | Optional | 实际 dash/gap 长度,缺失或空数组为实线 | | `dashOffset` | float32 | Optional | dash 起始偏移,缺失为 `0` | | `startMarker` | int32 | Optional | 起点端头,缺失为 `0` | | `endMarker` | int32 | Optional | 终点端头,缺失为 `0` | `width`、`dashArray` 和 `dashOffset` 使用保存时最终可见的 Canvas 长度。软件缩放 Shape 时可以自行决定是否改变它们,但写入器必须保存换算后的实际结果。读取器不得通过额外几何变换再次缩放这些值。 非空 `dashArray` 必须包含偶数个非负有限值,且总和大于 0。非法 `dashArray` 或非法 `dashOffset` 时,读取器按实线处理。具体线帽、连接处和抗锯齿外观由软件决定,UInk 不注册 `lineCap`、`lineJoin` 或 `miterLimit`。 ### Marker | 值 | 名称 | 语义 | | --- | --- | --- | | `0` | None | 无端头 | | `1` | OpenArrow | 开放式箭头语义 | | `2`–`127` | Reserved | UInk 后续版本保留 | | `128` 及以上 | Private | 软件私有端头 | Marker 只保存类型编号,不保存 Path、尺寸或固定比例。端头的具体外形由软件自行决定。未知 Marker 必须按 None 回退,不得丢弃主体 Line/Polyline。 `startMarker` 和 `endMarker` 只允许用于 Line/Polyline。闭合 Shape 中出现 Marker 时读取器忽略这些字段并警告。 软件内部可以用主线加两条端头线绘制箭头;写入 UInk 时应归一化为一个 Line/Polyline 及其 Marker。Marker 不产生额外的 Shape、`contentId` 或 `undoId`。 ## Fill Map Fill 首版只支持单色填充,渐变、纹理和图片填充留待后续版本或私有扩展。 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `fillType` | int32 | Required | `0` 为 Solid,`1`–`127` 保留,`128+` 私有 | | `color` | Color Map | Required | 填充颜色,支持 SDR/HDR 回退 | | `opacity` | float32 | Required | 填充透明度,范围 `0`–`1` | 未知 `fillType` 时,读取器使用 `color` 和 `opacity` 按 Solid 回退。Line/Polyline 不得保存 Fill;闭合 Shape 可以只保存 Fill、只保存 Stroke 或同时保存两者。 ## 内容流、撤回与增量写入 Shape 与 Ink、Media 按顶层对象流中的先后顺序混合处理。三者共享当前 Canvas 的连续 `contentId`;`undoId` 从 0 开始且只允许不递减,对象流中 `undoId` 相同且连续的内容块构成一次撤回操作。 `contentId` 只标识当前文件版本中当前 Canvas 的对象流顺序,完整保存后不得作为稳定外部引用。 完整 Shape 可以追加到文件末尾最后一个 Canvas。修改、移动、缩放或删除既有 Shape 时必须执行完整保存,不得通过追加重复既有 Shape。完整保存后,写入器重新整理各 Canvas 的 `contentId` 和 `undoId`。 Erase Ink 按对象流顺序作用于同一 Canvas 中位于它之前的 Shape 与 Ink,不作用于 Media;具体裁剪、透明和背景效果由软件决定。读取器不得因为块类型不同而重新排序。 Shape 与 Ink 共用 `renderOnlyWhenLatest`。读取器从 Canvas 尾部反向扫描,越过所有 Media,收集连续且标记为 `true` 的 Ink/Shape,直到遇到第一个未标记的 Ink/Shape。只有收集到的末尾最新组显示,其他标记内容隐藏;未标记内容正常显示。该分组不改变 `undoId`。完整算法参见 [Ink 条件渲染与撤回](ink#条件渲染与撤回)。 未标记的形状修正结果存在时,标记原稿隐藏。撤回结果后,原稿成为末尾最新组并重新显示,随后仍按各自 `undoId` 逐步撤回。隐藏但未撤回的原稿必须在完整保存时保留。 ## 容错与兼容 * 缺少 `type`、`contentId`、`undoId`、`shapeType`、`geometry` 或必要样式时跳过该 Shape,报告警告并继续读取。 * 坐标、尺寸、`rotation`、描边 `width`、`dashArray`、`dashOffset` 或 `opacity` 无效时,先使用本页为对应字段明确规定的回退。没有已定义回退时,包含无效字段的几何或样式无效;如果最终无法得到有效几何,或者 Line/Polyline 没有有效 Stroke,或者闭合 Shape 的 Stroke 与 Fill 都无效,则跳过整个 Shape。 * Shape 的未知 `shapeType`:跳过整块。 * Stroke 的未知 Marker:按 None 回退并保留主体几何。 * Fill 的未知 `fillType`:使用 Color Map 和 opacity 按 Solid 回退。 * 不支持 Shape 的读取器遇到未知 Type ID `5` 时,可以跳过当前完整 MessagePack 对象并继续读取后续块。 * 外部导入或包含未知块的文件默认另存为;用户明确确认可能丢失未知内容后才允许覆盖源文件。 ## 示例 ### 虚线双向箭头 ```jsonc { "type": 5, "contentId": 2, "undoId": 1, "shapeType": 0, "geometry": { "points": [ { "x": 120.0, "y": 240.0 }, { "x": 420.0, "y": 240.0 } ] }, "stroke": { "color": { "fallback": 255 }, "opacity": 1.0, "width": 4.0, "dashArray": [16.0, 8.0], "startMarker": 1, "endMarker": 1 } } ``` ### 旋转正方形与 HDR 填充 ```jsonc { "type": 5, "contentId": 3, "undoId": 2, "shapeType": 3, "geometry": { "centerX": 320.0, "centerY": 220.0, "size": 180.0, "rotation": 0.3926991 }, "stroke": { "color": { "fallback": 255 }, "opacity": 1.0, "width": 5.0 }, "fill": { "fillType": 0, "color": { "fallback": 16763904, "space": "scrgb", "components": [1.8, 0.65, 0.1] }, "opacity": 0.5 } } ``` ## 相关说明 * [块类型](../type) * [Color Map](../common/color) * [墨迹主文件](../file/main) * [Canvas 块](canvas) * [Ink 块](ink) * [增量写入](../incremental) --- --- url: /standard/common/color.md --- # Color Map Color Map 同时提供基础 SDR 回退色和可选 HDR 色彩空间数据。Ink、Shape 的填充和 Shape 的描边都使用同一结构。 ## 字段 | 字段 | 类型 | 要求 | 说明 | | --- | --- | --- | --- | | `fallback` | uint32 | Required | `0xRRGGBB` sRGB 回退色 | | `space` | string | Conditional | 与 `components` 成对出现 | | `components` | `Array(3)` | Conditional | 颜色空间中的三个分量 | 注册的 `space`: * `srgb`:三个分量范围为 `0`–`1`; * `scrgb`:三个分量使用线性 float32,可使用大于 `1` 的 HDR 值,只要求为有限数。 读取器按以下顺序选择颜色: 1. `space` 和 `components` 都缺失时,使用 `fallback`。 2. 两个扩展字段只出现一个时,扩展颜色无效,使用 `fallback`。 3. `space` 未知、`components` 长度不是 3、任一分量包含 NaN/Infinity,或者 `srgb` 分量超出 `0`–`1` 时,使用 `fallback`。 4. `space` 和 `components` 均有效时,使用扩展颜色;`scrgb` 分量允许大于 `1`,但必须是有限数。 写入器必须确保 `fallback` 不超过 `0xFFFFFF`,并让它表达扩展颜色在 SDR 中的预期回退外观。容错读取到更大的 uint32 时,可以只取低 24 位。`fallback` 缺失或类型无效时,包含该 Color Map 的必填颜色或样式无效;读取器按所属 Ink/Shape 的容错规则处理。 `srgb` 使用标准 sRGB 传递函数,`scrgb` 使用线性分量。显示到具体 HDR/SDR 设备时的色域映射和 tone mapping 由软件决定。Color Map 同时携带扩展颜色和 SDR 回退意图,但不承诺不同显示设备获得像素级一致的结果。 ```jsonc { "fallback": 16763904, "space": "scrgb", "components": [1.8, 0.65, 0.1] } ``` ## 相关说明 * [Ink 块](../blocks/ink) * [Shape 块](../blocks/shape) --- --- url: /standard/conformance.md --- # 实现一致性与样例 本页汇总第三方 UInk 1.0 Beta(`Header.version = 10`)读取器和写入器必须共同遵守的冻结线格式边界。本文将一个顶层 MessagePack 对象称为“块”;各块页面仍是字段语义和块级容错的权威定义。 ## 规范性术语 * **必须**:实现不满足时不属于当前 UInk 1.0 Beta 的兼容实现。 * **不得**:禁止行为,与“必须不”具有相同约束力。 * **应 / 应当**:推荐行为;偏离时需要保证不会造成错误附着、静默丢失或安全风险。 * **可以**:不影响基础互操作的可选行为。 字段表中的要求列使用以下含义: * **Required**:字段必须存在并通过字段校验。 * **Optional**:字段可以省略;存在时仍须通过字段校验或按页面定义的容错规则处理。 * **Conditional**:字段是否必需或是否允许出现,由该字段所在页面列出的条件决定。 ## 编码检查 * 首对象必须是 `array(7)` Header,Type ID 为 `0`,version 为 `10`。 * 写入器必须使用字段表声明的精确 MessagePack 类型和位宽。 * 读取器只有在数值不变、目标类型可精确表示且字段范围有效时,才能接受其他 MessagePack 数值编码;完整规则参见[块类型与编码](type#messagepack-编码)。 * Map 中重复的任一已知键使包含该 Map 的当前完整块无效。未知键可以忽略,但不得改变已知字段的解释。 * `contentId` 只在当前文件版本的 Canvas 内有效;完整保存后不具备稳定身份。 * Header 计数是最近一次完整保存快照,实际对象流具有更高优先级。 ## 读取流程 1. 读取并验证首对象的 Header 固定布局。Header 无效时,拒绝按当前规范解析文件。 2. 读取紧随 Header 的可选 Header Extension。为缺失或空的 Device/Workspace 注册表分别建立文件内隐式单例。 3. 从下一个顶层对象开始顺序解码。每遇到 Canvas 就开始新的内容作用域;后续 Ink/Shape/Media 归属最近的 Canvas。 4. 未知 Type ID 跳过当前完整对象。能完整解码但字段无效的已知块,按对应块页面的规则跳过或回退。 5. EOF 位于最后一个对象内部时,丢弃该不完整对象。解析非末尾对象或对象间字节失败时,停止读取余下字节,不尝试重同步。 6. 使用有效对象流重算页面与内容状态,并检查 Header 快照差异。Header 计数不得作为不受限内存分配依据。 ## 保存边界 1. 增量追加只修改文件尾部,不修改 Header。恢复后的文件必须先截断无效尾部,再允许追加。 2. 完整保存先确定新主文件引用的资源集合。存在资源时,先准备暂时包含旧、新引用资源并集的临时资源包,再生成并校验临时主文件。 3. 提交时先替换资源包,最后原子替换主文件。主文件提交后才能清理多余资源。 4. 完整保存移除已撤回内容,但保留被末尾最新组规则隐藏、仍可通过撤回结果恢复的原稿。 5. 软件自己创建且确认所有对象都能理解的文件可以直接覆盖。外部导入或含未知内容的文件默认另存为;只有用户明确确认可能丢失未知内容后,软件才能覆盖原文件。 ## 公开样例 所有样例文件及其可读清单均通过 [`fixtures.json`](/standard/uink-v10/fixtures.json) 发布。清单保存用途、十六进制和 SHA-256;`.uink` 条目还保存可完整解码的对象及 `expectedObjects`,`.uink.extra` 条目保存 ZIP `entries`。[`SHA256SUMS.txt`](/standard/uink-v10/SHA256SUMS.txt) 可用于下载后校验。 | 文件 | 验证目标 | | --- | --- | | [implicit-single-canvas.uink](/standard/uink-v10/implicit-single-canvas.uink) | 无 Header Extension 的隐式 Device/Workspace 单例 | | [explicit-multilayer.uink](/standard/uink-v10/explicit-multilayer.uink) | 显式注册表、多 Device/Workspace、`layerIndex = 0` 的 viewport | | [mixed-latest.uink](/standard/uink-v10/mixed-latest.uink) | Ink/Shape/Media 混合顺序与末尾最新组的撤回语义 | | [incremental-tail.uink](/standard/uink-v10/incremental-tail.uink) | Header 快照落后于追加页面,读取器重算状态 | | [truncated-tail.uink](/standard/uink-v10/truncated-tail.uink) | 最后一个对象被截断,仅丢弃不完整尾块 | | [unknown-block.uink](/standard/uink-v10/unknown-block.uink) | 跳过完整未知 Type ID 并继续读取 | | [numeric-compat.uink](/standard/uink-v10/numeric-compat.uink) | 读取可无损转换的非规范数值编码 | | [media-safe.uink](/standard/uink-v10/media-safe.uink) | 安全 Media 路径和资源引用 | | [media-safe.uink.extra](/standard/uink-v10/media-safe.uink.extra) | 包含安全 PNG/SVG 条目的资源包 | ## 第三方实现检查表 * \[ ] 写入精确声明类型,并只容错读取能够无损转换且通过字段校验的数值编码。 * \[ ] 不依赖 Header 计数分配不受限内存。 * \[ ] 能恢复不完整尾块并在再次追加前截断无效字节。 * \[ ] 按 `layerIndex`、Workspace 和 Window Device 规则确定合成顺序。 * \[ ] 只从 `layerIndex = 0` 读取 viewport,并正确处理隐式单例。 * \[ ] 判断 Ink/Shape 末尾最新组时跳过 Media,并正确执行逐步撤回和隐藏原稿持久化。 * \[ ] 不把 Erase 应用于 Media,不把失配 PPT Canvas 自动附着到 `pageIndex`。 * \[ ] 在读取 ZIP 资源前完成路径、安全和资源预算检查。 * \[ ] 对含未知内容的外部文件默认使用另存为。 --- --- url: /standard/file/main.md --- # 墨迹主文件 墨迹主文件(`filename.uink`)是连续的 MessagePack 对象流。可选 Header Extension 注册显式 Device 与 Workspace;任一注册表缺失时,使用文件内唯一的对应隐式单例。后续 Canvas 通过 GUID 或隐式单例关联两者。每个 Canvas 以及紧随其后的 Ink、Shape 和 Media 构成一个内容作用域。 ## 文件结构 ```mermaid flowchart TB H["Header · Type 0"] --> HE["Header Extension · Type 1
可选且最多一个"] H -. "无扩展" .-> C1 HE --> C1["Canvas · Type 2"] C1 --> B1["Ink / Shape / Media · Type 3 / 4 / 5"] B1 --> C2["Canvas · Type 2"] C2 --> B2["Ink / Shape / Media · Type 3 / 4 / 5"] B2 --> EOF["File EOF"] ``` 结构规则: 1. Header 必须位于文件开头。 2. Header Extension 可选且最多一个;存在时必须紧跟 Header。 3. Device 只存在于 Header Extension 的 `devices` 注册表,不是顶级块。 4. Ink/Shape/Media 归属于前一个 Canvas;Canvas 作用域在下一个 Canvas 或文件末尾结束。 5. 第一个 Canvas 前不得出现 Ink/Shape/Media。 6. Canvas 可以为空,用于保存空白页或空白图层。 ## 两棵注册树与扁平 Canvas Device 树描述显示空间:Display 是系统虚拟桌面中的绝对显示区域,Window 是相对父 Device 的窗口或板中板区域。Workspace 树描述场景、宿主、页面序列和父子生命周期。两棵树彼此独立。使用显式注册表时,Canvas 分别用 `deviceGuid` 与 `workspaceGuid` 连接它们;任一注册表缺失时,省略对应 GUID 的 Canvas 连接到文件内隐式单例。 一个文件可以同时包含多个白板、屏幕批注或 PPT Workspace。子 Workspace 合成在父项之上;同级 Workspace 按注册表从前到后合成,后项位于前项之上。Canvas 的显示视口始终填满所引用的 Device,但 Canvas 可以通过可选 viewport 保存该 Device 正在查看的世界坐标区域。 同一页面和 Device 内,`layerIndex` 越大越靠前。Window Device 按 `zIndex` 合成,同值时后注册项位于前注册项之上。以上顺序不依赖 Canvas 的物理排列。 ## Device 与 Canvas viewport Device 回答“显示视口位于屏幕或父 Device 的哪里”,`Canvas.viewport` 回答“该视口正在查看 Canvas 世界坐标的哪里”。两者的 `x/y` 属于不同坐标空间,不得混用。 Device 局部坐标和 Canvas 世界坐标都使用平台无关的逻辑像素。`Canvas.viewport` 使用左上角 Canvas 世界坐标 `x/y` 和统一 `scale`;`scale = 1` 时一 Canvas 单位对应一 Device 逻辑像素。内容坐标不随 viewport 改变。 `viewport` 归属于 `(workspaceKey, deviceKey, pageGuid)`;两个 Key 分别表示显式 GUID 或文件内对应的隐式单例。同页同 Device 仅 `layerIndex = 0` 保存 `viewport`,其他图层继承第 0 层的值。不同 Device 可以分别保存自己的最终视口;第 0 层缺失或无效时,所有图层按 `{ x: 0, y: 0, scale: 1 }` 加载。 ## 页面与多显示器 `pageGuid` 是页面的永久身份,`pageIndex` 是 Workspace 内可重排的当前顺序。同一 Workspace 中,跨设备或跨图层表示同一逻辑页的 Canvas 必须共享二者。 * 同步白板:多个 Device 引用同一 Workspace 和同一页面身份,只同步页序与翻页;各 Canvas 的绘制内容独立。 * 独立白板:不同 Device 使用不同 Workspace,各自维护页面序列。 * PPT:Workspace 保存宿主 `hostId`,Canvas 保存 `slideId`;跨设备的同一幻灯片共享 `pageGuid` 和 `slideId`。 `Header.pageNum` 是最近一次完整保存时各 Workspace 不重复 `pageGuid` 的总数。空白页计数,同页多设备或多图层不重复计数;增量追加后,读取器以实际 Canvas 重算当前页数。 ## 内容与撤回顺序 同一 Canvas 中,Ink、Shape 与 Media 按顶层对象流中的先后顺序混合处理,`contentId` 按该顺序从 0 连续递增。擦除 Ink 只作用于同一 Canvas 中位于它之前的 Ink 与 Shape;读取器不得按块类型重新排序。 `undoId` 在同一 Canvas 的 Ink/Shape/Media 间共享,从 0 开始且只允许不递减。对象流中 `undoId` 相同且连续的内容块构成一次撤回操作。撤回或重做后必须执行完整保存;保存后的文件只包含当前有效内容和末尾最新组规则要求保留的隐藏原稿。 Ink 和 Shape 可以使用 `renderOnlyWhenLatest`。读取器判断末尾标记组时跳过所有 Media,Media 既不加入该组,也不终止扫描。只有位于 Canvas 尾部、连续标记为 `true` 的 Ink/Shape 显示;其他标记内容隐藏。未标记的 Ink/Shape 终止反向扫描,但仍按普通内容显示。该规则不合并 `undoId`;被结果隐藏但未撤回的原稿仍是完整保存必须保留的有效内容。 ## `.uink.extra` `Media.path` 引用对应 `.uink.extra` ZIP 内的资源。ZIP 没有额外索引;资源顺序、几何、播放、PDF 页状态和撤回信息均由 Media 块决定。完整保存时,先提交暂时包含旧、新主文件所引用资源并集的资源包,最后原子替换 `.uink` 主文件。只有主文件提交成功后,才可以清理多余 ZIP 条目。主文件始终是当前有效内容的权威来源。 资源包缺失时基础墨迹必须正常加载。视觉媒体保留布局占位;PDF 还可以使用可选的 `pageCount` 和 `pageIndex` 显示页数占位信息。 ## 容错 读取器先按以下对象流规则确定可读取范围: 1. EOF 位于最后一个对象内部时,丢弃该不完整尾块,保留此前所有完整对象。 2. 解析某个非末尾顶层对象时出现无法解码的字节,或者任意对象之间存在无法解码的字节时,保留该失败对象或字节段开始之前已经完成的对象,并停止读取余下字节;不得按字节搜索新的对象边界。 3. 遇到未知 Type ID 时,跳过当前完整 MessagePack 对象并继续读取。 4. 遇到能完整解码但字段无效的已知块时,按对应块页面的规则跳过或回退,并继续读取。 建立逻辑模型时再应用以下容错: * 未知 `workspaceType`:按通用白板加载,不执行未知宿主逻辑。 * 未知 `deviceType`:按仅供本次加载使用的临时根显示面加载。 * Device/Workspace 循环:断开产生循环的父引用,把对应项作为临时根项加载。 * Canvas 引用缺失:构造临时 Workspace 或根 Device,并报告警告。 所有临时容错结果都不得自动写回源文件。 外部导入或包含未知对象的文件默认应另存为。用户明确确认可能丢失未知内容后,软件可以按当前能够理解的有效内容覆盖原文件。 ## 多显示器 PPT 可读示例 ```jsonc [0, 10, "5fe30f46-be92-49b6-b921-a60706febf10", 2, 1, 1, 1700000000] { "type": 1, "devices": [ { "guid": "11111111-1111-4111-8111-111111111111", "deviceType": 0, "x": 0, "y": 0, "width": 3840, "height": 2160 }, { "guid": "22222222-2222-4222-8222-222222222222", "deviceType": 0, "x": 3840, "y": 0, "width": 1920, "height": 1080 } ], "workspaces": [ { "guid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "workspaceType": 2, "hostId": "INKKEYS-PPT-7B58E2A1", "currentPageIndex": 0 } ] } { "type": 2, "workspaceGuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "deviceGuid": "11111111-1111-4111-8111-111111111111", "pageGuid": "cccccccc-cccc-4ccc-8ccc-cccccccccccc", "pageIndex": 0, "pageNumber": 1, "layerIndex": 0, "layerNumber": 0, "slideId": 256, "viewport": { "x": -320.0, "y": 180.0, "scale": 1.5 } } // 第一个 Canvas 的 Ink / Shape / Media { "type": 2, "workspaceGuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "deviceGuid": "22222222-2222-4222-8222-222222222222", "pageGuid": "cccccccc-cccc-4ccc-8ccc-cccccccccccc", "pageIndex": 0, "pageNumber": 1, "layerIndex": 0, "layerNumber": 0, "slideId": 256, "viewport": { "x": 0.0, "y": 0.0, "scale": 1.0 } } // 第二个 Canvas 的独立 Ink / Shape / Media ``` 以上是连续 MessagePack 对象的可读表示,文件本身没有包裹这些对象的外层 Array。 ## 其他关键场景 * **Window Device 上的画布**:在 `devices` 注册 Window,并让 Canvas 引用其 GUID;Canvas 不重复保存 Device 的 x/y/width/height,只用 viewport 保存窗口左上角对应的 Canvas 世界坐标与统一缩放。 * **嵌套白板**:子 Workspace 使用 `parentWorkspaceGuid`,其空间位置由 Canvas 引用的 Device 决定。 * **空白页**:只写 Canvas,不跟随 Ink/Shape/Media。 * **PDF 缺失**:保留 Media 的 width/height/transform 以及可选页信息,继续渲染其他内容。 * **HDR 回退**:Ink 的未知或无效色彩空间使用 Color Map 的 fallback。 ## 相关页面 * [块类型](../type) * [增量写入](../incremental) * [实现一致性与样例](../conformance) * [Header Extension](../blocks/headerExtension) * [Device 结构](../blocks/device) * [Canvas 块](../blocks/canvas) * [Ink 块](../blocks/ink) * [Shape 块](../blocks/shape) * [Media 块](../blocks/media) --- --- url: /standard/incremental.md --- # 增量写入 UInk 的增量写入是可选的当前画布崩溃保护。它只向既有对象流末尾追加完整 MessagePack 对象,不替代正常关闭、显式保存或结构变化时的完整保存;软件可以完全不实现增量写入。 本文将“重建全部有效对象、写入临时文件并替换目标文件”的保存方式统一称为**完整保存**。 ## 可以追加的内容 目标 Workspace 与 Device 已由 Header Extension 显式注册,或者文件按 Header Extension 规则使用隐式单例时,可以追加: * 文件末尾最后一个 Canvas 中已经完整结束的 [Ink](blocks/ink)、[Shape](blocks/shape) 或 [Media](blocks/media); * 引用既有 Workspace 与 Device 的新 [Canvas](blocks/canvas),随后逐个追加完整 Ink/Shape/Media;新 Canvas 为 `layerIndex = 0` 时可以保存最终 viewport,其他图层必须省略 viewport。 尚未完成的轨迹不得写入;写入器不得只写入 MessagePack Map 的一部分后等待补齐。只有文件末尾最后一个 Canvas 可以继续追加内容。写入器不得在文件末尾重复既有 Canvas,以模拟对旧页、旧图层或既有 viewport 的补丁。 ## Header 快照 增量写入不得原地更新 Header。Header 的 `deviceNum`、`workspaceNum`、`pageNum` 和 `time` 保持最近一次完整保存的值,读取器从实际有效对象流重算当前逻辑状态。 追加新页面后,`Header.pageNum` 可以暂时小于实际页数;该差异不是文件损坏。只有完整保存才重新计算 Header 快照。 ## 顺序要求 * 新内容的 `contentId` 承接当前 Canvas 的 Ink/Shape/Media 共享序列。 * `undoId` 不得小于此前内容的 `undoId`。 * 新 Canvas 的 `(workspaceKey, deviceKey, pageGuid, layerIndex)` 不得与既有 Canvas 重复;两个 Key 分别表示显式 GUID 或文件内对应的隐式单例。 * 追加同一逻辑页在另一 Device 上的 Canvas 时复用 `pageGuid` 和 `pageIndex`;逻辑页数不变,Header 快照也不更新。 * 如果目标不是文件末尾最后一个 Canvas,则必须执行完整保存。 ## 崩溃恢复 读取器逐个解析顶层 MessagePack 对象: 1. EOF 恰好位于对象边界时,文件正常结束。 2. EOF 位于最后一个对象内部时,丢弃该不完整对象并保留此前所有完整对象。 3. 解析某个非末尾对象或对象间字节时出现解码错误,保留失败对象或字节段开始之前的完整对象,并停止读取余下字节;不尝试搜索后续对象边界。 4. 能完整解码但字段无效的对象按对应块的容错规则跳过,并继续读取下一对象。 恢复读取并不自动修改源文件。软件准备再次追加时,必须执行以下步骤: 1. 确定安全追加边界:不完整尾块取该对象的起始偏移;中间解码错误取读取器开始尝试解析失败对象或字节段时的偏移;末尾连续的完整但无效已知块取第一个无效尾块的起始偏移。 2. 把文件截断到安全追加边界。 3. 检查截断后的最后一个有效 Canvas。该 Canvas 没有内容时,新内容从 `contentId = 0`、`undoId = 0` 开始;存在内容时,新内容使用前一块 `contentId + 1`,且 `undoId` 不得小于前一块的值。 4. 如果完整但无效的块位于后续有效块之前,改为执行完整保存;不得在文件中间截断后直接追加。 ## 必须完整保存的情况 * 新增、删除或修改 Device/Workspace 注册项; * 修改 Workspace 宿主绑定、父子关系或当前页; * 撤回或重做; * 返回旧页、旧图层或更早 Canvas 修改; * 普通板擦切断已经保存的旧 Ink/Shape; * 修改、移动或删除既有 Ink、Shape、Media; * 切换既有 PDF 的 `pageIndex`; * 修改既有页面的 Canvas `viewport`; * 改变页面、图层、`pageIndex` 或 `pageGuid` 结构; * 任何无法保证追加结果与当前画面一致的情况。 新增 Workspace 时,必须在同一次完整保存中注册 Workspace,并写入该 Workspace 的至少一个 Canvas。 完整保存只移除真正已经撤回的块。带 `renderOnlyWhenLatest = true`、当前被修正结果隐藏但尚未撤回的 Ink/Shape 仍是有效内容,必须保留。写入器必须重新整理各 Canvas 的 `contentId` 与 `undoId`,并重新计算 Header 快照。完整保存不得改变文件永久 `Header.guid`、既有 Workspace/Device GUID 或既有页面 `pageGuid`。 完整保存只在同页同 Device 的 `layerIndex = 0` Canvas 保存最终 viewport。viewport 不产生 `contentId` 或 `undoId`,也不属于 Ink/Shape/Media 的撤回历史。软件在撤回内容时是否调整 viewport 由软件决定。复制页面时,新页面继承源页面 viewport。 ## 完整保存提交顺序 完整保存必须使用临时文件,并按以下顺序准备和提交: 1. 确定完整对象流以及新主文件将引用的资源集合。 2. 存在资源时,先生成并校验临时 `.uink.extra`。该资源包必须暂时包含旧主文件仍引用的资源与新主文件将引用的资源的并集。 3. 生成并校验临时 `.uink` 主文件,但尚不替换目标主文件。 4. 如果生成了临时资源包,先用它替换目标资源包;然后原子替换 `.uink` 主文件。主文件必须最后提交,以保证提交前的旧主文件仍能找到所需资源。 5. `.uink` 是当前有效内容的权威来源。主文件提交成功后,才可以删除不再引用的 ZIP 条目或整个无用资源包;崩溃产生的多余资源允许延后清理,缺失资源按 Media 缺失规则加载。 一次完整保存不得直接在原主文件上边解析边覆盖,以免失败时同时失去旧文件和新文件。 ::: warning 两种擦除模式 Erase Ink 是新的完整 Ink,可以直接追加;会切断既有 Ink/Shape 的普通板擦必须执行完整保存。Erase 不作用于 Media。 ::: ## 推荐保存策略 运行期间可以在当前末尾 Canvas 抬笔后追加,以减少崩溃造成的数据丢失。正常关闭、显式保存、撤回、切换旧页修改或出现结构变化时执行完整保存。 参见[墨迹主文件](file/main)和[实现一致性与样例](conformance)。 --- --- url: /standard/intro.md --- # UInk 规范 UInk 规范用于解决本地绘图软件的墨迹存储与跨端预览问题。规范优先保证数据语义、内容布局和基础呈现一致;自由墨迹曲线、Marker 外形、抗锯齿以及复杂擦除效果可以因软件实现而不同。 ::: tip UInk 1.0 Beta 当前规范版本号为 `10`,发布状态为 UInk 1.0 Beta,线格式已经冻结。本文档是 version `10` 的首个 Beta 兼容基线,并取代此前所有同版本预 Beta 草案;旧草案文件不属于兼容范围,读取器无须支持。 ::: [规范版本号](version) ## 特点 1. 一个文件可以注册多个屏幕批注、白板或 PPT Workspace,并支持父子工作区、多显示器、多页面和多图层。 2. 支持可选的[增量写入](incremental),在当前文件末尾 Canvas 中追加完整内容,用于降低运行中崩溃造成的数据丢失。 3. 墨迹主文件使用连续 MessagePack 对象流,兼顾读写性能、体积和扩展性。 4. Ink、Shape 与 Media 按它们在顶层对象流中的先后顺序混合处理,并共享内容编号和撤回分组。 5. Device 与 Canvas 解耦:Device 描述显示区域,Canvas 使用逻辑像素保存内容,并可通过 `viewport` 保存平移与缩放状态。 6. 擦除、普通笔和两类荧光笔统一使用 [Ink 块](blocks/ink),未知样式可以安全回退。 ## 文件 ### 墨迹文件 UInk 格式由必需的墨迹主文件和可选的墨迹扩展文件组成。 ::: file-tree * filename.uink MessagePack * filename.uink.extra ZIP * \*.png * \*.svg * \*.mp3 * \*.pdf * …… ::: * 墨迹主文件(`filename.uink`)使用 [MessagePack](https://msgpack.org/) 对象流,保存 Ink、Shape、Media、Canvas 和元数据。 * 墨迹扩展文件(`filename.uink.extra`)使用 ZIP 格式打包,保存由 [Media 块](blocks/media) 引用的图片、SVG、音视频和 PDF 等资源。 两个文件使用相同的基础文件名,其中墨迹扩展文件是可选的。`.uink` 主文件始终是当前有效内容的权威来源;资源包缺失或资源不可用时,基础 Ink/Shape 仍必须正常加载。 #### 墨迹文件的定位 * 墨迹主文件用于快速加载、基础预览和内容交换。 * 墨迹扩展文件只是资源容器,不保存内容顺序、几何或撤回信息。 * UInk 可以保存编辑与撤回所需的当前有效内容,但不承诺在关闭后保留 Redo 历史。 ### 墨迹扩展文件 资源路径必须是 ZIP 根目录内经过规范化的安全相对路径。媒体的 MIME、几何、播放参数、PDF 页状态和顺序全部保存在 `.uink` 主文件中,详细安全要求参见 [Media 块](blocks/media)。 ## 第三方实现 第三方读取器和写入器必须遵守字段类型、对象顺序、容错与保存边界。实现前应先阅读[实现一致性与样例](conformance),并使用公开样例验证基础互操作。 ## 相关链接 * [规范版本](version) * [块类型与编码](type) * [实现一致性与样例](conformance) * [墨迹主文件](file/main) * [Device 结构](blocks/device) * [Canvas 块](blocks/canvas) * [Ink 块](blocks/ink) * [Shape 块](blocks/shape) * [Media 块](blocks/media) * [Color Map](common/color) --- --- url: /standard/type.md --- # 块类型(Type ID) Type ID 用于识别墨迹主文件中的顶层 MessagePack 对象。本文将一个顶层 MessagePack 对象简称为“块”,将这些对象在文件中的先后顺序称为“对象流顺序”。 | Type ID(uint16) | 块 | MessagePack 类型 | | --- | --- | --- | | `0` | [Header 块](blocks/header) | Array | | `1` | [Header Extension 块](blocks/headerExtension) | Map | | `2` | [Canvas 块](blocks/canvas) | Map | | `3` | [Ink 块](blocks/ink) | Map | | `4` | [Media 块](blocks/media) | Map | | `5` | [Shape 块](blocks/shape) | Map | [Device](blocks/device) 是 Header Extension 注册表中的嵌套 Map,不具有 Type ID,也不出现在顶级对象流中。 ## MessagePack 编码 写入器必须遵守以下规则: 1. 使用字段表声明的精确 MessagePack 类型和位宽。例如,`uint16` 不得写成正整数 fixint,`float32` 不得写成 float64。 2. 对 Header 额外遵守固定数组布局,参见 [Header 块](blocks/header)。 3. 重新保存读取时容错接受的数值时,将其规范化为字段表声明的类型。 读取器可以容错接受其他 MessagePack 数值编码,但必须依次满足以下条件: 1. 源值是数值,且目标字段也是数值;`bool` 不属于数值编码。 2. 转换不会改变数值。整数目标要求源值是数学意义上的整数;浮点目标要求源值能由目标浮点类型精确表示。 3. 转换后的值通过目标类型范围和字段自身的有效性校验。 `bool`、`string`、Array 和 Map 不允许用其他类型代替。Map 中重复出现任一已知键时,包含该 Map 的当前块无效;未知键仍按各块的扩展规则忽略。 ::: warning `type` 与 `inkType` Ink 顶层 `type` 固定为 `3`;块内 `inkType` 才表示擦除、普通笔、荧光笔或高级荧光笔。不存在独立 Eraser 顶层块,也不存在 `penType` 二级字段。 ::: 各字段声明的 `128+` 私有编号没有全局厂商命名空间,也不配套 `vendorId`;只有预先约定相同编号语义的实现之间能够互操作。 ## 未知对象与保存 读取器遇到未知 Type ID 时,如果当前 MessagePack 对象能够完整解码,必须跳过该对象并继续读取下一块,不得仅因一个未知块拒绝整个文件。如果无法确定未知对象的结束边界,则按[损坏恢复规则](incremental#崩溃恢复)停止读取余下字节。 UInk 不要求写入器原样保留未知对象。软件自己创建且确认所有对象都能理解的文件可以直接覆盖;外部导入或包含未知内容的文件默认应另存为新文件,只有用户明确确认可能丢失未知内容后才可以覆盖原文件。具体流程参见[实现一致性与样例](conformance)。 --- --- url: /standard/version.md --- # 规范版本 本页定义 `Header.version` 使用的规范版本号。 | 规范版本号 | 说明 | 状态 | | --- | --- | --- | | `10` | UInk 1.0 Beta | Beta,线格式已冻结 | ::: tip version 10 Beta 冻结边界 当前文档定义 version `10` 的首个 Beta 兼容基线。Header 布局、已注册 Type ID、字段类型与既有字段语义、对象作用域、排序规则以及保存恢复契约不得再做不兼容修改。 不改变既有对象解释的文字澄清和可选扩展可以继续使用 version `10`。任何要求现有兼容读取器改变既有数据解释或无法按当前容错规则安全处理的修改,都必须使用新的 `Header.version`。 ::: 当前 Beta 使用 Header `array(7)`、Header Extension 注册表以及 Type ID `0`–`5`,其中 Type ID `5` 为 Shape。此前 Header `array(6)`、顶级 Device 或 Type ID `5` 为 Media 的文件均视为已废弃的预 Beta 草案。 UInk 不注册额外的 magic 标识。`.uink` 扩展名只用于文件识别;读取器还必须同时验证首对象是 Header、Header 数组长度为 `7`、Type ID 为 `0` 且 `version = 10`。任一条件不满足时,读取器必须拒绝按当前规范解析该文件。 同一逻辑 UInk 文件执行完整保存时,不得改变 `Header.guid`、既有 Workspace/Device GUID 或既有页面 `pageGuid`。“另存为”新的逻辑文件时,必须生成新的 `Header.guid`。 version `10` 已随 UInk 1.0 Beta 正式冻结。冻结前的草案调整不提供迁移保证;今后的不兼容修改必须使用新的 `Header.version`。 --- --- url: /tos/en-us.md --- # Inkeys Terms of Use [简体中文](./zh-cn) | **English** *** **Version:** 1.0\ **Release Date:** November 28, 2025\ **Effective Date:** November 28, 2025 **These *Inkeys Terms of Use* (hereinafter referred to as "these Terms") constitute a legally binding agreement between you ("User" or "You") and the Inkeys Development Team (hereinafter referred to as "We" or "Us") regarding your downloading, installation, copying, or other use of the "Inkeys" software (including its updates, upgrades, related documentation, and auxiliary components, collectively referred to as "the Software").** **Before you download, install, or use the Software, please be sure to read these Terms carefully and fully understand them, especially the clauses marked in bold, which may concern your rights, obligations, or limitations of liability.** **If you do not agree to any part of these Terms, please do not download, install, or use the Software.** **By downloading, installing, copying, running, or otherwise using the Software, you acknowledge that you have read and agree to be bound by these Terms and any updated versions thereof.** Specifically, when you launch the Software for the first time, the Software will guide you to read this Agreement. By checking the checkbox representing "Agree" and proceeding to the next step, you confirm that you fully understand and accept all terms of this Agreement. If you are using the Software on behalf of a company, organization, or other entity, you represent and warrant that you have full authority to bind that entity to these Terms, and in such case, "You" refers to that company, organization, or other entity. *** ### I. Service Description 1. The Software is developed and provided by Us, aiming to provide users with screen annotation, marking, drawing, and related auxiliary tools. Specific functions and interfaces may change with version updates. 2. The Software is primarily intended for general users worldwide, including educators, students, creators, and individuals or organizations requiring screen annotation functionality. The Software is **not specifically designed or certified for any specific industry, region, or regulatory field**. If you use the Software in high-risk scenarios, you shall evaluate its suitability independently and assume all associated risks. 3. We may add, remove, or modify the functions of the Software, or suspend, pause, or terminate the maintenance and updates of the Software within a reasonable scope, based on product planning, technical conditions, or legal and regulatory requirements. We will endeavor to notify you of significant changes via the official website, project homepage, or in-software notifications (to the extent technically and legally permissible). 4. The Software is **provided free of charge**. ### II. User Eligibility, Rights, and Obligations 1. **User Eligibility** 1.1 You confirm that when using the Software, you possess full civil capacity and are capable of independently assuming legal liability. 1.2 If you are a minor under the age of 18, or a minor as defined by the laws of your jurisdiction, you should use the Software only after your guardian has read and agreed to these Terms and the relevant Privacy Policy. Use of the Software by a minor shall be deemed to be with the consent and guidance of their guardian. 1.3 If you use the Software on behalf of a company, organization, or other entity, you represent and warrant that you have the authority to bind such entity to these Terms. 2. **User Rights** Subject to your compliance with these Terms and applicable laws and regulations, you enjoy the following rights: 2.1 You have the right to download, install, and use the Software within the scope permitted by these Terms and applicable open-source licenses. 2.2 You have the right to use the functions of the Software in personal, educational, research, and commercial scenarios, provided that you comply with applicable laws, regulations, and these Terms. For parts subject to open-source licenses such as GPLv3, you must also comply with the requirements of the respective open-source licenses. 2.3 To the extent permitted by applicable law, you have the right to exercise rights regarding your personal information, such as access, correction, deletion, restriction of processing, and withdrawal of consent. Please refer to Part III, "Privacy Policy," of these Terms for details. 2.4 If you do not agree to these Terms (including subsequent revisions), you have the right to stop using and uninstall the Software. Uninstalling the Software does not automatically extinguish any rights, obligations, or liabilities incurred by you during your prior use of the Software. 3. **User Obligations** When using the Software, you undertake and agree to: 3.1 Comply with applicable laws, regulations, these Terms, and other rules related to the Software. You shall not use the Software to engage in any illegal, non-compliant, or infringing acts, including but not limited to: * Infringing upon the intellectual property rights, privacy rights, reputation rights, or other legitimate rights and interests of others; * Transmitting, storing, or publishing illegal, harmful, or prohibited content; * Engaging in fraud, cyberattacks, malicious intrusion, disruption of computer information systems, etc. 3.2 Not use the Software in any manner that could damage, disable, overburden, or impair the normal operation of the Software, or interfere with any other party's use of the Software. 3.3 Not intentionally transmit viruses, trojans, or other malicious programs through the Software. 3.4 Not forge, tamper with, or delete copyright notices, trademarks, or other proprietary notices in the Software. 3.5 Carefully check any error reports, logs, memory dump files, or other technical information before proactively submitting them to Us to ensure they do not contain sensitive content you do not wish to disclose (e.g., trade secrets, personal privacy). 3.6 Properly safeguard your device and system environment configuration and not intentionally provide a device installed with the Software to others for use in illegal activities. 4. **Breach of Terms** 4.1 If We have reasonable grounds to believe that you have violated these Terms or applicable laws and regulations, We have the right to take reasonable measures to the extent permitted by law, including but not limited to: * Requiring you to immediately cease the relevant violation; * Restricting or terminating the provision of relevant services to you (e.g., online updates, technical support) and prohibiting you from using official releases bearing Our trademarks and digital signatures to the extent permitted by law; * Reporting to relevant competent authorities and cooperating with investigations where necessary. 4.2 Provided there is no conflict with applicable open-source licenses (such as GPLv3), the above measures do not prejudice any other rights or remedies We may have under the law or other agreements. ### III. Privacy Policy We respect and protect the personal privacy rights of all users of the Software. We are committed to minimizing data collection and processing information only to the extent necessary to achieve essential functions and improve services, in compliance with applicable data protection laws. **Unless otherwise stated in these Terms or a separately published Privacy Policy, the core functions of the Software are performed primarily on your local device. We do not proactively read, upload, or store personal sensitive information related to the content of your creations.** > In the event of any inconsistency between these Terms and the Privacy Policy updated and published separately by Us from time to time, the latest published Privacy Policy shall prevail. #### 1. Information We Collect and How We Use It To improve product functionality, perform software updates, and provide technical support, We may collect and process the following information within the **minimum necessary scope**. We will not use it for purposes unrelated to the Software. | Information Name | Purpose of Collection | Collection and Processing Method | | :--- | :--- | :--- | | **IP Information** and **Desktop OS Information (e.g., OS version, locale)** | 1. To determine compatibility and software update strategies for different regions and system versions;2. To understand the system distribution of the user base for planning future development and optimization. | Automatically captured and recorded via network requests when you check for updates or access Our update servers. We focus on statistical analysis and will not attempt to directly link this to personally identifiable information. | | **Unique User ID (User ID)** | 1. To accurately count active users and avoid duplicate counting;2. To correlate configuration statistics, crash statistics, etc., where necessary, to improve the product. | We generate a **GUID locally on your device** by obtaining hardware information such as motherboard UUID and CPUID, and use the **SHA256 hash** of it as the User ID. This identifier is designed not to contain direct identification information such as your name or account, and We will not attempt to reverse engineer your real identity based on this identifier. | | **Software Settings Status (e.g., feature toggles, preferences)** | 1. To evaluate the overall usage of various functions to guide future functional adjustments and optimizations;2. To provide more reasonable default settings and experiences for different user groups. | We may statistically analyze the status of certain settings in the Software (e.g., whether a function is enabled) and associate it with the User ID anonymously for overall analysis. The default values of some settings may refer to your system settings (e.g., system language, theme color); this reading operation is performed locally only, and We will not upload the raw details of your system settings. | **We will not use the above information for automated decision-making or user profiling, nor will we use it for cross-site or cross-service tracking.** #### 2. Telemetry and Error Reporting (User Initiated) When the Software crashes or encounters a serious error, the Software may generate an error report on your local device to assist in analyzing the problem. We handle such data based on the principle of **completely voluntary and explicit consent**: * **Error reports are not uploaded automatically.**\ We will only receive relevant information when you are explicitly aware of it and **choose to send it proactively**. * Before clicking "Send," you can usually view or locate the error report file; We recommend that you check it yourself before sending to ensure it does not contain sensitive content you do not wish to share. * Depending on the specific error type, the error report may contain the following information (content may vary): * **System Configuration Information**: e.g., CPU info, graphics card info, memory info, screen parameters (e.g., resolution, refresh rate, EDID, etc.); * **Software Logs and Memory Dump Files**: Used to analyze the internal state of the program when the crash occurred; * **Relevant Process Information (e.g., process name, basic process info)**: Used to troubleshoot compatibility issues with other processes. **Our sole purpose in receiving such error reports is to locate and fix issues and improve the stability and performance of the Software.**\ Unless required to meet mandatory legal or regulatory requirements, or necessary to protect the significant legitimate rights and interests of you or others, We will not use error reports for purposes unrelated to failure analysis. #### 3. Localization and Content Data We specifically declare and promise: 1. The main functions of the Software (including screen annotation, drawing, screenshot processing, etc.) run on your local device. 2. Any content created or processed by you during use, including but not limited to: * Screenshots; * Annotation content (text, graphics, handwriting, etc.); * Canvas files or project files; * Materials displayed by you during teaching, presentation, or creative activities, are stored by default **only on your local device or storage locations of your choice (e.g., local disks, third-party cloud drives configured by you)**. 3. We will not access, collect, or upload the above content through backdoors or hidden functions of the Software, nor will We transfer content stored locally by you to Our servers without your explicit consent. 4. If future versions add functions such as online synchronization, cloud backup, or online collaboration, We will inform you of the types of data to be collected and processed in a conspicuous manner **before you enable the relevant functions** and obtain your separate consent. #### 4. Data Storage, Cross-Border Transfer, and Security 1. **Data Storage Location** 1.1 Under the current product design, the Software and related online services are primarily provided to users located **within the territory of the People's Republic of China (PRC)**. We primarily store limited telemetry statistical data and error reports proactively sent by you on servers located **within the PRC**. 1.2 We may use third-party service providers (e.g., code hosting platforms, log or error tracking services) to assist Us in processing the above data. We select service providers that operate servers **within the PRC** and comply with legal and regulatory requirements to process data related to the Software; under the current business architecture, this data will not be transferred to or stored on overseas servers. 1.3 If cross-border data transfer becomes necessary due to business development or compliance requirements in the future, We will fully inform you of the relevant purpose, data type, recipient, and protection measures in advance within the scope required by applicable law, and proceed only after obtaining necessary authorization or fulfilling statutory procedures. 2. **Data Encryption and Security Measures** 2.1 During transmission, We will use industry-standard security measures (e.g., TLS/HTTPS) to the extent possible to protect data from unauthorized access or tampering. 2.2 During storage, We will take technical and management measures within a reasonable scope to prevent data from unauthorized access, use, disclosure, modification, or loss. 2.3 Although We have made reasonable efforts to improve security, data transmitted over the Internet and stored electronically **cannot be guaranteed to be absolutely secure**. You understand and accept the inherent risks associated with the Internet. 3. **Data Retention Period** 3.1 We generally retain your relevant data only for the shortest period necessary to achieve the purposes stated in these Terms. 3.2 When the data is no longer necessary for the stated purposes, or when the law no longer requires Us to retain it, We will delete, anonymize, or otherwise handle such data in accordance with applicable laws. 4. **Data Sharing and Disclosure** We may share or disclose data in the following circumstances, provided it complies with legal and regulatory requirements and is within a necessary and reasonable scope: * Sharing relevant data with third-party service providers who provide technical services to Us for limited purposes such as error analysis, log hosting, or statistical analysis; We will require them to comply with confidentiality obligations and data protection requirements; * Providing relevant data to competent authorities when necessary to comply with applicable laws, regulations, court orders, or requirements of competent authorities, or to enforce applicable government regulatory measures; * In connection with a merger, division, asset transfer, or similar corporate transaction, if the transfer of personal data is involved, We will require the new recipient to continue to be bound by these Terms and applicable laws, or re-obtain your consent if necessary. 5. **What We Will Not Do** * We will **not** sell or rent your personal data to third parties for their independent commercial purposes; * We will **not** create cross-service user profiles for the purpose of pushing third-party targeted advertising to you. #### 5. Protection of Minors 1. We do not proactively provide the Software to minors as a specific target audience, nor do We proactively collect personal information from minors. 2. If you are a minor user, please use the Software with the consent and under the guidance of your guardian. 3. If We discover that We have collected personal information from a minor without guardian consent, We will take reasonable measures to delete or anonymize such information as soon as possible after becoming aware of it (unless applicable law requires Us to retain it). #### 6. Updates to These Terms We may update these Terms as the Software's functions expand, applicable laws and policies change, or data processing methods are adjusted. We will notify you of material changes by updating the "Modification Date" on this page, via in-software pop-ups, or through other reasonable means (to the extent technically and legally permissible). **Your continued use of the Software after the update takes effect constitutes your reading, understanding, and agreement to be bound by the updated Terms.**\ If you do not agree to the updated content, you have the right to stop using the Software and uninstall it. ### IV. Open Source License and Third-Party Components #### 1. Open Source License of the Software The core source code of the Software is released under the **GNU General Public License v3.0 (GPLv3)**. Subject to compliance with the terms of the GPLv3: * You are free to view, use, copy, modify, and distribute the source code of the Software; * If you modify, redistribute, or integrate the source code of the Software into other software (constituting a "derivative work"), you generally need to: * License the entire derivative work in a manner compatible with GPLv3; and * Provide the recipient with the complete source code or a way to obtain the source code when distributing it to others; * Any content in these Terms of Use that conflicts with the terms of the GPLv3 shall be superseded by the provisions of the GPLv3 within the scope of the conflict. The complete source code and build process are located in the GitHub repository (hereinafter referred to as the "Official Repository"): * Official Repository: > A mirror repository is located at GitCode: .\ > There may be a time delay in synchronization between the mirror repository and the official repository. In case of inconsistency in terms or license information, the official repository shall prevail. For the complete text of the GPLv3 license, please refer to: * > These Terms of Use primarily apply to: > > * The use of the **compiled executable programs**, installation packages, documentation, websites, and related services you obtain; > > While the copying, modification, and redistribution of the source code itself are primarily governed by the GPLv3 agreement. #### 2. Code Signing and Integrity To improve the security and credibility of released versions, the Software digitally signs official executable files. * We may use the trusted third-party certificate authority **SignPath Foundation** to provide code signing support, and We collaborate with SignPath on release process security audits; * The code signing, build, and release processes are integrated into the CI/CD workflow of GitHub Actions; * You can verify the digital signature to confirm whether the downloaded installation package or executable file comes from an official release channel and whether it has been tampered with during transmission. For relevant information, please see: * SignPath Project Page: > Even though the Software is open-source software, We strongly recommend that you **obtain executable files only from officially announced release pages or trusted channels** and verify signatures where possible to reduce the risk of malicious tampered versions. #### 3. Third-Party Open Source Components The development of the Software uses and integrates multiple third-party open-source libraries.\ These third-party components are subject to their respective independent open-source licenses, which are usually included in the Software's source code repository or distribution package. We hereby express our gratitude to these open-source projects and their contributors. The following are some major third-party components and their licensing information (summary only; specific constraints are subject to the license text accompanying each component): | Component Name | License | Copyright / Notes | | :--- | :--- | :--- | | **[abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)** | Apache License 2.0 | | | **[aksalj/hashlibpp](https://github.com/aksalj/hashlibpp)** | See LICENSE / Readme in lib | Copyright (c) 2007–2011 Benjamin Gr¸delbach | | **[Alan-CRL/DesktopDrawpadBlocker](https://github.com/Alan-CRL/DesktopDrawpadBlocker)** | GNU General Public License v3.0 | | | **[cameron314/concurrentqueue](https://github.com/cameron314/concurrentqueue)** | See LICENSE / Readme in lib | Copyright (c) 2013–2016, Cameron Desrochers. All rights reserved. | | **[efficient/libcuckoo](https://github.com/efficient/libcuckoo)** | See LICENSE / Readme in lib | Copyright (C) 2013, Carnegie Mellon University and Intel Corporation | | **[gabime/spdlog](https://github.com/gabime/spdlog)** | MIT License | Copyright (c) 2016 Gabi Melman. | | **[google/ink-stroke-modeler](https://github.com/google/ink-stroke-modeler)** | Apache License 2.0 | | | **[martinus/unordered\_dense](https://github.com/martinus/unordered_dense)** | MIT License | Copyright (c) 2022 Martin Leitner-Ankerl | | **[mohabouje/WinToast](https://github.com/mohabouje/WinToast)** | MIT License | Copyright (C) 2016–2023 WinToast v1.3.0 - Mohammed Boujemaoui | | **[nothings/stb](https://github.com/nothings/stb)** | MIT License | Copyright (c) 2017 Sean Barrett | | **[ocornut/imgui](https://github.com/ocornut/imgui)** | MIT License | Copyright (c) 2014–2025 Omar Cornut | | **[openssl/openssl](https://github.com/openssl/openssl)** | Apache License 2.0 | Copyright (c) 1998–2025 The OpenSSL Project Authors. Copyright (c) 1995–1998 Eric A. Young, Tim J. Hudson. All rights reserved. | | **[open-source-parsers/jsoncpp](https://github.com/open-source-parsers/jsoncpp)** | MIT License | Copyright (c) 2007–2010 Baptiste Lepilleur and The JsonCpp Authors | | **[sammycage/lunasvg](https://github.com/sammycage/lunasvg)** | MIT License | Copyright (c) 2020–2025 Samuel Ugochukwu | | **[sammycage/plutovg](https://github.com/sammycage/plutovg)** | MIT License | Copyright (c) 2020–2025 Samuel Ugochukwu | | **[yhirose/cpp-httplib](https://github.com/yhirose/cpp-httplib)** | MIT License | Copyright (c) 2017 yhirose | | **[Zip Utils](https://www.codeproject.com/Articles/7530/Zip-Utils-Clean-Elegant-Simple-Cplusplus-Win)** | See project page and license | | | **[zouhuidong/HiEasyX](https://github.com/zouhuidong/HiEasyX)** | MIT License | Copyright (c) 2022 zouhuidong | For the **complete list** of all third-party libraries used by the Software and their corresponding license texts, please consult: * **Notice of Major Components (NOTICE)**:\ * **Summary of Third-Party License Files**:\ > In the event of any conflict or inconsistency between these Terms of Use and the licenses of the aforementioned third-party components, the specific terms of the respective third-party licenses shall prevail regarding the use, copying, modification, and distribution of such third-party components. #### 4. Other Third-Party Components and Proprietary Licensing In addition to the open-source components mentioned above, the Software may also use certain third-party libraries or tools licensed under other terms during development and operation. We likewise express our gratitude to the authors and maintainers of these projects. The following is a summary of some non-open-source (or partially open-source) components currently used and their licensing information (if any): | Component Name | Licensing / Usage Note | | :--- | :--- | | **[EasyX](https://easyx.cn/)** | Used in accordance with the licensing terms published on the official EasyX website. Specific rights and obligations are subject to the latest official EasyX licensing terms. | > Our use of third-party components does not constitute any claim of ownership over their projects.\ > When you independently use the above third-party software, libraries, or services, you should still carefully read and comply with their respective terms of use and licenses. ### V. Intellectual Property #### 1. Proprietary Intellectual Property Except for the source code and third-party open-source components authorized under open-source licenses as described in Article IV of this Agreement, other intellectual property rights related to the Software, including but not limited to: * The Software name, logo, icons (excluding parts of third-party icon fonts belonging to their copyright owners), interface design, and visual elements; * The overall interaction design, layout, and organizational structure of the Software; * Official documentation, manuals, help content, tutorials, sample data, demo videos, promotional materials, etc., released by the Software; * Images, graphic materials, icons, and other design resources independently created by Us and provided with the Software, which are not subject to third-party proprietary license restrictions; The copyright, trademark rights, patent rights, and other relevant rights of the above content belong to **Us (Inkeys Development Team)** or have been legally authorized by their rights holders. Provided there is no conflict with applicable open-source licenses (e.g., GPLv3), without Our prior written permission, you may not in any way: * Remove, hide, or alter copyright notices, trademarks, logos, or other rights notices displayed in the Software; * Use names, logos, or branding elements identical or confusingly similar to "Inkeys" in a manner that may cause confusion; * Use the Software's name, logo, or interface to promote products or services not associated with Us or not authorized by Us; * Sell or distribute the Software and various intellectual property rights related to the Software for profit. > If any statement regarding intellectual property rights in this Agreement conflicts with open-source licenses (e.g., GPLv3) within the scope of source code usage, the terms of the respective open-source license shall prevail regarding the source code part. #### 2. Third-Party Fonts and Design Resources The Software uses certain third-party fonts and icon fonts as design resources in its interface display, such as (including but not limited to): * **HarmonyOS Sans** series fonts; * **Douyu Font**, etc.; * **Segoe Fluent Icons / Segoe Fluent UI** and other icon fonts or related icon sets. Regarding the above third-party fonts and design resources, please understand and agree that: 1. **Ownership of Rights** * The copyright, trademark rights, and other rights of the above fonts, icon fonts, and related design resources belong to their respective owners; * We use them for interface display and other purposes of the Software only within the scope permitted by their respective licensing terms; * Nothing in these Terms of Use should be construed as transferring or licensing any rights or interests in these third-party fonts or design resources to you. 2. **Restrictions on Your Use** * You must not extract these third-party fonts or design resources from the Software independently for separate distribution, sale, rental, or download; * If you wish to use the above fonts or icon fonts independently outside of the Software (including but not limited to commercial scenarios), you should consult and comply with the relevant licensing terms from their rights holders or official channels and obtain separate authorization if necessary; * For third-party design resources that We do not have the right to sublicense, We do not provide any form of sublicense commitment or legal guarantee to you. 3. **Relation to the Open Source Nature of the Software** * The source code of the Software (within the scope of GPLv3) is open source; * However, certain fonts, icon fonts, or other design resources contained in the Software may **not be licensed under an open-source license along with the source code**; * If you redistribute or perform secondary development based on the Software, **it is your responsibility to verify and comply with the licensing terms of these third-party resources** and replace them with resources you are legally entitled to use if necessary. #### 3. Copyright Notice Copyright © 2023–2025 **AlanCRL (Chen Runlin) Studio**\ All Rights Reserved (within the scope permitted by applicable open-source licenses). Third-party fonts, icon fonts, and other resources subject to third-party licenses are the property of their respective rights holders. ### VI. DISCLAIMER TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, YOU UNDERSTAND AND AGREE TO THE FOLLOWING TERMS: 1. **PROVIDED "AS IS"** THE SOFTWARE AND RELATED SERVICES ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS.\ WE MAKE NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, REGARDING THE SOFTWARE, INCLUDING BUT NOT LIMITED TO: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE; * CONTINUOUS AVAILABILITY, ABSENCE OF ERRORS OR DEFECTS; * FULL COMPATIBILITY WITH SPECIFIC HARDWARE, SYSTEMS, OR SOFTWARE ENVIRONMENTS; * ANY WARRANTIES NOT EXPRESSLY STATED IN THIS AGREEMENT OR APPLICABLE OPEN-SOURCE LICENSES. 2. **LIMITATION OF LIABILITY** TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WE, OUR CONTRIBUTORS, AND PARTNERS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERRUPTION, LOSS OF DATA, DAMAGE TO GOODWILL, OR OTHER INTANGIBLE LOSSES) ARISING OUT OF OR RELATED TO ANY OF THE FOLLOWING: * YOUR ACCESS TO, DOWNLOAD, INSTALLATION, OR USE OF THE SOFTWARE; * YOUR FAILURE TO USE THE SOFTWARE CORRECTLY IN ACCORDANCE WITH THE DOCUMENTATION OR INSTRUCTIONS; * MODIFICATION, REPACKAGING, REDISTRIBUTION, OR INTEGRATION OF THE SOFTWARE BY THIRD PARTIES; * ANY SECURITY INCIDENTS, VULNERABILITIES, OR ERRORS RELATED TO THE SOFTWARE. 3. **THIRD-PARTY CONTENT AND SERVICES** THE SOFTWARE MAY INTERACT OR INTEGRATE WITH THIRD-PARTY SERVICES, WEBSITES, LIBRARIES, OR CONTENT (E.G., THIRD-PARTY OPEN-SOURCE LIBRARIES, THIRD-PARTY APIS, WEBSITE LINKS).\ WE ASSUME NO RESPONSIBILITY FOR THE AVAILABILITY, SECURITY, ACCURACY, OR LEGALITY OF SUCH THIRD-PARTY CONTENT OR SERVICES, NOR ARE WE LIABLE FOR ANY LOSS INCURRED BY YOUR USE OF SUCH THIRD-PARTY CONTENT OR SERVICES.\ YOU SHOULD REVIEW AND COMPLY WITH THE RELEVANT THIRD-PARTY TERMS OF USE AND PRIVACY POLICIES BEFORE USE. 4. **NON-EXCLUSION OF MANDATORY LEGAL RIGHTS** SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OF LIABILITY FOR CERTAIN DAMAGES. THE ABOVE DISCLAIMERS AND LIMITATIONS OF LIABILITY MAY NOT APPLY TO YOU IN WHOLE OR IN PART IN SUCH JURISDICTIONS.\ IN SUCH CASES, THESE TERMS APPLY ONLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW AND DO NOT AFFECT ANY MANDATORY RIGHTS YOU MAY HAVE UNDER LOCAL LAW. ### VII. Update and Effectiveness of the Agreement 1. **Updates** We reserve the right to modify, update, or supplement this Agreement when necessary. These modifications may be due to reasons including but not limited to: * Adapting to changes in applicable laws, regulations, and regulatory policies; * Reflecting adjustments to the Software's functions, service models, or technical architecture; * Improving user experience, security, or compliance levels. 2. **Method of Notification** When material changes occur to this Agreement, We will notify you of the updated content through one or more reasonable means: * Displaying via pop-up windows or prompts upon Software launch; * Posting announcements on the official website or project homepage (e.g., GitHub repository). 3. **Acceptance and Rejection** * From the effective date stated in the updated version or notification, **your continued downloading, installation, or use of the Software constitutes your full reading, understanding, and acceptance of the updated Agreement content**; * If you do not agree to the updated Agreement content, you must immediately stop using the Software and uninstall the installed version. > To stay informed of the latest terms, We recommend that you check the page where this Agreement is located or relevant files in the official repository from time to time. ### VIII. Governing Law and Dispute Resolution 1. **Governing Law** The conclusion, execution, interpretation, and dispute resolution of these Terms shall be governed by the laws of the People's Republic of China (for the purpose of these Terms, excluding the Hong Kong Special Administrative Region, the Macau Special Administrative Region, and the Taiwan region). If the laws of the People's Republic of China do not provide for a matter or the provisions are unclear, reference shall be made to commercial practices or general industry rules. 2. **Exceptions for Local Law (Consumer Protection)** Notwithstanding the foregoing, if you are a consumer in the European Union, the United Kingdom, the United States, or other jurisdictions, and local laws explicitly provide for mandatory consumer protection rights that cannot be excluded by contract (e.g., the right to sue in the consumer's place of residence), the jurisdiction clause in these Terms shall not deprive you of such rights under mandatory local laws. In such cases, other parts of these Terms shall remain in full force and effect. 3. **Language** These Terms may be published in multiple languages. In the event of any conflict or ambiguity between the Chinese version and other language versions, the Simplified Chinese version shall prevail to the extent permitted by applicable law. ### IX. Contact Us If you have any questions, comments, or suggestions regarding this Agreement, the use of the Software, open-source licensing, privacy protection, or other related matters, please contact Us via: * **Project Homepage (GitHub):** * **Contact Email:** * alan-crl@foxmail.com * alancrl1007@gmail.com We will make reasonable efforts to respond to your reasonable inquiries or feedback as soon as possible within the limits of our capacity and resources, but We do not guarantee a response to every correspondence. --- --- url: /tos/zh-cn.md --- # 智绘教Inkeys 使用条款 **简体中文** | [English](./en-us) *** **版本** 1.0\ **发布日期:** 2025年11月28日\ **生效日期:** 2025年11月28日 **本《智绘教Inkeys 使用条款》(以下简称“本条款”)是您(“用户”或“您”)与智绘教Inkeys 开发团队(下称“我们”)之间关于您下载、安装、复制或以其他方式使用“智绘教Inkeys”软件(包括其更新、升级、相关文档及附属组件,统称为“本软件”)所订立的具有法律约束力的协议。** **在您下载、安装或使用本软件之前,请务必仔细阅读并充分理解本条款,尤其是其中以加粗形式标注的条款,这些条款可能与您的权利义务或责任限制有关。** **若您不同意本条款的任何内容,请不要下载、安装或使用本软件。** **一旦您下载、安装、复制、运行或以其他方式使用本软件,即视为您已阅读并同意受本条款及其不时更新版本的约束。** 特别地,在您首次启动本软件时,本软件将引导您阅读本协议。通过勾选代表“同意”的复选框并继续下一步操作的行为,即表示您确认已完全理解并接受本协议的全部条款。 如您代表某一公司、组织或其他实体使用本软件,则您声明并保证,您已获得充分授权可以使该实体受本条款约束,并且在本条款中,“您”也包括该公司、组织或其他实体。 *** ### 一、服务说明 1. 本软件由我们开发和提供,旨在为用户提供屏幕批注、标记、绘制及相关辅助工具功能。具体功能和界面可能会随版本更新而变化。 2. 本软件主要面向全球范围内的一般用户,包括教育工作者、学生、创作者及其他需要屏幕批注功能的个人或组织使用。本软件**不针对任何特定行业、特定地区或特定监管领域进行专门设计或认证**,如您在高风险领域场景中使用本软件,应自行评估其适用性并自行承担风险。 3. 我们可能根据产品规划、技术条件或法律法规的要求,对本软件的功能进行增加、删除或调整,或在合理范围内中止、暂停或终止对本软件的维护和更新。我们将尽量通过官方网站、项目主页或软件内通知等方式提示重要变更(在技术和法律允许的范围内)。 4. 本软件为**免费提供**。 ### 二、用户资格、权利与义务 1. **用户资格** 1.1 您确认,在使用本软件时,您具有完全民事行为能力,能够独立承担法律责任。 1.2 如您为未满 18 周岁的未成年人,或您所在司法辖区规定的未成年人,您应在监护人阅读并同意本条款及相关隐私条款后使用本软件。未成年人使用本软件的行为,即视为已获得监护人的同意和指导。 1.3 如您代表公司、组织或其他实体使用本软件,您声明并保证您有权使该实体受本条款约束。 2. **用户权利** 在您遵守本条款及适用法律法规的前提下,您享有以下权利: 2.1 您有权在本条款及适用开源许可证允许的范围内下载、安装和使用本软件。 2.2 您有权在个人、教育、科研和商业场景中使用本软件的功能,但应同时遵守适用法律法规以及本条款的各项约定,且对受 GPLv3 等开源许可证约束的部分,须遵守相应开源许可证的要求。 2.3 您有权在适用法律允许的范围内,就您的个人信息向我们行使访问、更正、删除、限制处理、撤回同意等权利,具体方式请参阅本条款第三部分“隐私政策”。 2.4 当您不同意本条款(包括后续的修订版本)时,您有权停止使用并卸载本软件。卸载本软件并不能自动消除您在此前使用本软件期间已经发生的权利义务或责任。 3. **用户义务** 在使用本软件时,您承诺并同意: 3.1 遵守适用的法律法规、本条款及其他与本软件相关的规则,不得利用本软件从事任何违法、违规或侵权行为,包括但不限于: * 侵犯他人的知识产权、隐私权、名誉权或其他合法权益; * 传播、存储或发布违法、有害或受禁止的内容; * 参与欺诈、网络攻击、恶意入侵、破坏计算机信息系统等活动。 3.2 不以可能损害、瘫痪、过载或削弱本软件正常运行的方式使用本软件,或干扰他人对本软件的正常使用。 3.3 不通过本软件故意传播病毒、木马或其他恶意程序。 3.4 不伪造、篡改或删除本软件中的版权声明、商标或其他所有权声明。 3.5 在向我们主动提交错误报告、日志、内存转储文件或其他技术信息前,审慎检查其中是否包含您不希望我们接触的敏感内容(例如商业机密、个人隐私等)。 3.6 妥善保管您的设备和系统环境配置,不得故意将装有本软件的设备提供给他人用于违法活动。 4. **违约处理** 4.1 如果我们有合理理由认为您违反本条款或适用法律法规,我们有权在法律允许的范围内采取合理措施,包括但不限于: * 要求您立即停止相关违规行为; * 限制或终止向您提供相关服务(如在线更新、技术支持),并在法律允许的范围内禁止您使用带有我们商标和数字签名的官方发行版; * 在必要时向相关主管机关报告,并配合其调查。 4.2 在不与适用的开源许可证(如 GPLv3)相冲突的前提下,上述措施不影响我们根据法律或其他协议享有的任何其他权利救济。 ### 三、隐私政策 我们尊重并保护所有使用本软件用户的个人隐私权。我们致力于在遵守适用的数据保护法律的前提下,尽量减少数据收集,仅在实现必要功能和改进服务所需的范围内处理信息。 **除非本条款或单独公布的隐私政策另有说明,本软件的核心功能主要在您的本地设备上完成,我们不会主动读取、上传或存储与您创作内容本身相关的个人敏感信息。** > 如本条款与我们不时更新并单独发布的隐私政策存在不一致之处,以最新发布的隐私政策为准。 #### 1. 我们收集的信息及用途 为了改进产品功能、进行软件更新和提供技术支持,我们可能在**最小必要范围内**收集和处理以下信息。我们不会用于与本软件无关的目的。 | 信息名称 | 收集目的 | 收集与处理方式 | | :--- | :--- | :--- | | **IP 信息** 和 **桌面操作系统信息(如操作系统版本、语言环境)** | 1. 用于判断不同地区、不同系统版本的兼容性和软件更新策略;2. 了解用户群体使用的系统分布,以规划未来的开发方向和功能优化。 | 在您检查更新或访问我们的更新服务器时,通过网络请求自动获取并记录。我们以统计分析为主,不会尝试将其与可识别个人身份的信息直接关联。 | | **唯一用户标识符 (User ID)** | 1. 准确统计活跃用户数量,避免重复计数;2. 在必要时关联配置统计、崩溃统计等,以便改进产品。 | 我们通过获取您设备的主板 UUID、CPUID 等硬件信息,在**本地设备上生成一个 GUID**,并对其进行 **SHA256 哈希计算**后作为 User ID 使用。该标识符在设计上不包含您的姓名、账号等直接识别信息,我们不会尝试基于该标识符反向推导您的真实身份。 | | **软件设置项状态(如功能开关、偏好设置等)** | 1. 评估各项功能的整体使用情况,以指导未来的功能调整与优化;2. 为不同用户群体提供更合理的默认设置和体验。 | 我们可能会统计您在软件中的部分设置项状态(例如某个功能是否开启),并与 User ID 进行匿名化关联用于整体分析。部分设置的默认值可能参考您的系统设置(如系统语言、主题颜色);该读取操作仅在本地进行,我们不会上传您系统设置的原始详细信息。 | **我们不会基于上述信息进行自动化决策或用户画像构建,亦不会用作跨站点或跨服务的跟踪。** #### 2. 遥测与错误报告(用户主动发送) 当本软件发生崩溃或严重错误时,软件可能会在您的本地设备上生成一份错误报告,用于协助分析问题。我们对该类数据采取**完全自愿、显式同意**的原则处理: * **错误报告不会自动上传。**\ 只有在您明确知情并**主动选择发送**给我们时,我们才会接收到相关信息。 * 在您点击“发送”之前,您通常可以查看或定位到错误报告文件;我们建议您在发送前自行检查其中是否包含您不希望分享的敏感内容。 * 根据具体错误类型,错误报告中可能包含以下信息(不同情况内容可能不同): * **系统配置信息**:如 中央处理器(CPU)信息、显卡信息、内存信息、屏幕参数(如分辨率、刷新率、EDID 等); * **软件日志和内存转储文件(Dump File)**:用于分析崩溃发生时的程序内部状态; * **相关进程信息(如进程名称、基础进程信息)**:用于排查与其他进程的兼容性问题。 **我们收到此类错误报告的唯一目的是:定位并修复问题,提升软件的稳定性和性能。**\ 除非为满足法律法规的强制要求,或为保护您或他人的重大合法权益所必需,我们不会将错误报告用于与故障分析无关的目的。 #### 3. 本地化处理与内容数据 我们特别声明并承诺: 1. 本软件的主要功能(包括屏幕批注、绘制、截图处理等)均在您的本地设备上运行。 2. 您在使用过程中创建或处理的任何内容,包括但不限于: * 屏幕截图; * 批注内容(文字、图形、手写笔迹等); * 画布文件或项目文件; * 您在教学、演示或创作活动中展示的资料, 在默认情况下**仅存储在您的本地设备或您自主选择的存储位置(如本地磁盘、您自行配置的第三方云盘等)**。 3. 我们不会通过本软件后门或隐藏功能访问、收集或上传上述内容,也不会在未取得您明确同意的情况下将您本地存储的内容传输到我们的服务器。 4. 若未来某些版本新增在线同步、云备份或在线协同等功能,我们会在**您启用相关功能前**另行以显著方式向您说明所需收集和处理的数据类型,并征得您的单独同意。 #### 4. 数据存储、跨境传输与安全 1. **数据存储地点** 1.1 在目前的产品设计下,本软件及相关在线服务主要面向位于**中华人民共和国境内**的用户提供使用。我们主要在位于**中华人民共和国境内**的服务器上存储有限的遥测统计数据和您主动发送的错误报告。 1.2 我们可能使用第三方服务提供商(例如代码托管平台、日志或错误跟踪服务)协助我们处理上述数据。我们仅选择在**中华人民共和国境内**运营服务器、并符合法律法规要求的服务提供商处理与本软件相关的数据;在当前业务架构下,这些数据不会被传输至境外服务器或存储在境外。 1.3 如未来因业务发展或合规要求确有必要进行跨境数据传输,我们将在适用法律要求的范围内,事先向您充分告知相关目的、数据类型、接收方及保护措施,并在取得必要授权或履行法定程序后方可进行。 2. **数据加密与安全措施** 2.1 在传输过程中,我们将尽可能采用行业通用的安全措施(例如 TLS/HTTPS)保护数据不被未授权访问或篡改。 2.2 在存储过程中,我们会在合理范围内采取技术和管理措施,防止数据遭受未经授权的访问、使用、披露、修改或丢失。 2.3 尽管我们已尽合理努力提升安全性,但通过网络传输和电子存储的数据**无法保证绝对安全**。您理解并接受与互联网相关的固有风险。 3. **数据保留期限** 3.1 我们通常仅在实现本条款所述目的所必需的最短期间内保留您的相关数据。 3.2 当数据不再为实现既定目的所必需,或法律不再要求我们继续保留时,我们将根据适用法律的要求删除、匿名化或以其他合理方式处理该等数据。 4. **数据共享与披露** 在符合法律法规要求,并在必要且合理的范围内,我们可能在以下情形中共享或披露数据: * 为实现错误分析、日志托管或统计分析等有限目的,向为我们提供技术服务的第三方服务提供商共享相关数据;我们将要求其遵守保密义务和数据保护要求; * 为遵守适用法律法规、法院判决或有权机关的要求,或为执行适用的政府监管措施,有必要时向相关主管部门提供相关数据; * 在与合并、分立、资产转让或类似的公司交易相关的情况下,如涉及到个人数据的转移,我们将要求新的接收方继续受本条款及适用法律的约束,或在必要时重新征得您的同意。 5. **我们不会的行为** * 我们**不会**将您的个人数据出售或出租给第三方用于其独立的商业目的; * 我们**不会**以向您推送第三方定向广告为目的创建跨服务的用户画像。 #### 5. 未成年人保护 1. 我们不会以未成年人为特定对象主动提供本软件,也不会主动收集未成年人的个人信息。 2. 如您为未成年人用户,请在监护人的同意和指导下使用本软件。 3. 如我们发现未经监护人同意而收集到未成年人的个人信息,我们将在获知后采取合理措施尽快删除或匿名化处理该等信息(除非适用法律要求我们保留)。 #### 6. 本条款的更新 随着本软件功能的扩展、适用法律政策的变化或数据处理方式的调整,我们可能会对本条款进行更新。我们将通过在本页面更新“修改日期”、在软件内弹窗提示或通过其他合理方式通知您重大变更(在技术与法律允许的范围内)。 **在更新生效后,您继续使用本软件,即表示您已阅读、理解并同意受更新后的本条款约束。**\ 如您不同意更新内容,您有权停止使用本软件并卸载本软件。 ### 四、开源协议与第三方组件 #### 1. 本软件的开源许可 本软件的核心源代码以 **GNU General Public License v3.0(GPLv3)** 许可发布。 在遵守 GPLv3 协议条款的前提下: * 您可以自由查看、使用、复制、修改和分发本软件的源代码; * 若您基于本软件源代码进行修改、再发布、或将其整合进其他软件中(构成“派生作品”),则您通常需要: * 以 GPLv3 兼容的方式对整个派生作品进行许可;以及 * 在向他人分发时,向接收方提供完整的源代码或获取源代码的方式; * 任何与 GPLv3 条款相冲突的本使用条款内容,在冲突范围内以 GPLv3 的规定为准。 完整的源代码和构建流程位于 GitHub 仓库(以下简称“官方仓库”): * 官方仓库: > 备用仓库位于 GitCode:。\ > 备用仓库与官方仓库之间的同步可能存在一定时间延迟,在条款或许可证信息不一致时,以官方仓库为准。 完整的 GPLv3 许可证文本,请参阅: * > 本使用条款主要适用于: > > * 您获取的**已编译可执行程序**、安装包、文档、网站和相关服务的使用; > > 而源代码本身的复制、修改和再分发,则主要受 GPLv3 协议约束。 #### 2. 代码签名与完整性 为提高发布版本的安全性和可信度,本软件对官方发布的可执行文件进行数字签名。 * 我们可能使用受信任的第三方证书颁发机构 **SignPath Foundation** 提供代码签名支持,我们与 SignPath 协作进行发布流程安全审核; * 代码签名、构建和发布流程集成在 GitHub Actions 的 CI/CD 流程中; * 您可以通过验证数字签名,确认下载的安装包或可执行文件是否来自官方发布渠道,是否在传输途中被篡改。 相关信息请参见: * SignPath 项目页: > 即使本软件为开源软件,我们仍强烈建议您**仅从官方公布的发布页面或可信渠道获取可执行文件**,并在可能的情况下验证签名,以降低恶意篡改版本的风险。 #### 3. 第三方开源组件 本软件的开发过程中使用并集成了多项第三方开源库。\ 这些第三方组件各自适用其独立的开源许可证,通常包含在本软件的源代码仓库或发行包中。 我们在此对这些开源项目及其贡献者表示感谢。以下为部分主要第三方组件及其许可信息(仅为摘要,具体约束以各组件随附许可证文本为准): | 组件名称 | 许可证 | 版权信息 / 说明 | | :--- | :--- | :--- | | **[abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)** | Apache License 2.0 | | | **[aksalj/hashlibpp](https://github.com/aksalj/hashlibpp)** | 参见库内 LICENSE / 说明文件 | Copyright (c) 2007–2011 Benjamin Gr¸delbach | | **[Alan-CRL/DesktopDrawpadBlocker](https://github.com/Alan-CRL/DesktopDrawpadBlocker)** | GNU General Public License v3.0 | | | **[cameron314/concurrentqueue](https://github.com/cameron314/concurrentqueue)** | 参见库内 LICENSE / 说明文件 | Copyright (c) 2013–2016, Cameron Desrochers. All rights reserved. | | **[efficient/libcuckoo](https://github.com/efficient/libcuckoo)** | 参见库内 LICENSE / 说明文件 | Copyright (C) 2013, Carnegie Mellon University and Intel Corporation | | **[gabime/spdlog](https://github.com/gabime/spdlog)** | MIT License | Copyright (c) 2016 Gabi Melman. | | **[google/ink-stroke-modeler](https://github.com/google/ink-stroke-modeler)** | Apache License 2.0 | | | **[martinus/unordered\_dense](https://github.com/martinus/unordered_dense)** | MIT License | Copyright (c) 2022 Martin Leitner-Ankerl | | **[mohabouje/WinToast](https://github.com/mohabouje/WinToast)** | MIT License | Copyright (C) 2016–2023 WinToast v1.3.0 - Mohammed Boujemaoui | | **[nothings/stb](https://github.com/nothings/stb)** | MIT License | Copyright (c) 2017 Sean Barrett | | **[ocornut/imgui](https://github.com/ocornut/imgui)** | MIT License | Copyright (c) 2014–2025 Omar Cornut | | **[openssl/openssl](https://github.com/openssl/openssl)** | Apache License 2.0 | Copyright (c) 1998–2025 The OpenSSL Project Authors. Copyright (c) 1995–1998 Eric A. Young, Tim J. Hudson. All rights reserved. | | **[open-source-parsers/jsoncpp](https://github.com/open-source-parsers/jsoncpp)** | MIT License | Copyright (c) 2007–2010 Baptiste Lepilleur and The JsonCpp Authors | | **[sammycage/lunasvg](https://github.com/sammycage/lunasvg)** | MIT License | Copyright (c) 2020–2025 Samuel Ugochukwu | | **[sammycage/plutovg](https://github.com/sammycage/plutovg)** | MIT License | Copyright (c) 2020–2025 Samuel Ugochukwu | | **[yhirose/cpp-httplib](https://github.com/yhirose/cpp-httplib)** | MIT License | Copyright (c) 2017 yhirose | | **[Zip Utils](https://www.codeproject.com/Articles/7530/Zip-Utils-Clean-Elegant-Simple-Cplusplus-Win)** | 参见项目页面及随附许可证 | | | **[zouhuidong/HiEasyX](https://github.com/zouhuidong/HiEasyX)** | MIT License | Copyright (c) 2022 zouhuidong | 关于本软件使用的所有第三方库的**完整列表**及其对应的许可证文本,请查阅: * **主要组件声明(NOTICE)**:\ * **第三方许可证文件汇总**:\ > 当本使用条款与上述第三方组件的许可证存在冲突或不一致时,\ > 就相关第三方组件的使用、复制、修改和分发事宜,以相应第三方许可证的具体条款为准。 #### 4. 其他第三方组件与专有授权 除上述开源组件外,本软件在开发和运行过程中还可能使用部分以其他许可方式授权的第三方库或工具。我们同样对这些项目的作者和维护者表示感谢。 以下为目前使用的部分非(或不完全)开源组件及其授权信息摘要(如有): | 组件名称 | 许可授权 / 使用说明 | | :--- | :--- | | **[EasyX](https://easyx.cn/)** | 根据 EasyX 官方网站公布的授权条款使用。具体权利义务以 EasyX 官方的最新授权条款为准。 | > 我们对第三方组件的使用不构成对其项目的任何所有权声明。\ > 您在独立使用上述第三方软件、库或服务时,仍应仔细阅读其各自的使用条款和许可证,并自行遵守。 ### 五、知识产权 #### 1. 自有知识产权 除本协议第四条所述依据开源许可证授权的源代码和第三方开源组件外,本软件相关的其他各项知识产权,包括但不限于: * 本软件名称、标识(Logo)、图标(不含第三方图标字体中属于其版权所有人的部分)、界面设计与视觉元素; * 本软件的整体交互设计、版式布局、组织结构; * 本软件官方发布的文档、说明书、帮助内容、教程、示例数据、演示视频、宣传材料等; * 由我们独立创作并随软件一同提供,且不受第三方专有许可限制的图片、图形素材、图标等设计资源; 上述内容的著作权、商标权、专利权及其他相关权利,均归 **我们(智绘教Inkeys 开发团队)** 所有或已合法取得其权利人的授权。 在不与适用的开源许可证(例如 GPLv3)相冲突的前提下,未经我们事先书面许可,您不得以任何方式: * 去除、隐藏或更改本软件中显示的版权声明、商标、标识或其他权利声明; * 以可能造成混淆的方式使用与“智绘教Inkeys”相同或近似的名称、标识或品牌元素; * 将本软件的名称、标识或界面等用于推广与我们不存在关联或未获我们授权的产品或服务; * 出售或以盈利目的分发本软件及其与本软件相关的各项知识产权。 > 若本协议中关于知识产权的表述与开源许可证(如 GPLv3)在源代码使用范围内存在冲突,则就源代码部分优先适用相应开源许可证的条款。 #### 2. 第三方字体与设计资源 本软件在界面展示中使用了部分第三方字体和图标字体等设计资源,例如(包括但不限于): * **HarmonyOS Sans** 系列字体; * **Douyu Font** 等字体; * **Segoe Fluent Icons / Segoe Fluent UI** 等图标字体或相关图标集。 关于上述第三方字体和设计资源,请您理解并同意: 1. **权利归属** * 上述字体、图标字体及相关设计资源的著作权、商标权及其他权利,均归各自权利人所有; * 我们仅在其各自授权条款允许的范围内,将其用于本软件的界面展示等用途; * 本使用条款中的任何内容,均不应被理解为将这些第三方字体或设计资源的任何权益转让或授权给您。 2. **您的使用限制** * 您不得将这些第三方字体或设计资源从本软件中单独抽取出来,作为独立资源另行分发、出售、出租或提供下载; * 若您希望在本软件之外自行使用上述字体或图标字体(包括但不限于商用场景),应自行向其权利人或官方渠道查阅并遵守相应授权条款,并在必要时单独取得授权; * 对于我们无权再授权的第三方设计资源,我们不向您提供任何形式的再授权承诺或法律保证。 3. **与本软件开源属性的关系** * 本软件的源代码(在 GPLv3 范围内)为开源; * 但本软件中包含的某些字体、图标字体或其他设计资源可能 **不随源代码一起以开源许可证授权**; * 若您基于本软件进行再发行或二次开发,**有责任自行确认和遵守这些第三方资源的授权条款**,必要时应替换为您有权合法使用的资源。 #### 3. 版权声明 Copyright © 2023–2025 **AlanCRL(陈润林)工作室**\ 保留所有权利(在适用的开源许可证允许范围内)。 第三方字体、图标字体以及其他受第三方许可约束的资源,其版权和相关权利归各自权利人所有。 ### 六、免责声明 在适用法律允许的最大范围内,您理解并同意如下条款: 1. **按“现状”提供** 本软件及其相关服务基于“现状”和“可用性”提供。\ 我们不对本软件的以下事项作出任何形式的明示或默示保证或陈述,包括但不限于: * 适销性、特定用途适用性; * 持续可用性、无错误或缺陷; * 与特定硬件、系统、软件环境的完全兼容性; * 任何未在本协议或适用开源许可证中明确说明的保证。 2. **责任限制** 在适用法律允许的最大范围内,即使我们已被事先告知发生此类损害的可能性,对于因下列任一原因而产生或与之相关的任何直接、间接、附带、特殊、惩罚性或后果性损害(包括但不限于利润损失、营业中断、数据丢失、商誉受损或其他无形损失),我们和我们的贡献者、合作方均不承担任何责任: * 您对本软件的访问、下载、安装或使用; * 您未能按照文档或说明正确使用本软件; * 第三方对本软件的修改、重新打包、二次分发或整合; * 任何与本软件相关的安全事件、漏洞或错误。 3. **第三方内容与服务** 本软件可能与第三方服务、网站、库或内容进行交互或集成(例如:第三方开源库、第三方 API、网站链接等)。\ 对于此类第三方内容或服务的可用性、安全性、准确性或合法性,我们不承担责任,亦不对您使用此类第三方内容或服务产生的任何损失负责。\ 您在使用前应自行审阅并遵守相关第三方的使用条款和隐私政策。 4. **强制性法律权利不受影响** 某些司法管辖区不允许排除特定担保或限制对某些损害的责任,上述免责声明和责任限制条款在此类司法管辖区内可能部分或全部不适用。\ 在该等情况下,本条款仅在适用法律允许的最大范围内适用,并且不影响您根据当地强制性法律享有的任何权利。 ### 七、协议的更新与生效 1. **更新** 我们保留在必要时对本协议进行修改、更新或补充的权利。这些修改可能出于以下原因(包括但不限于): * 适应适用法律法规、监管政策的变化; * 反映本软件功能、服务模式或技术架构的调整; * 提升用户体验、安全性或合规水平。 2. **通知方式** 当本协议发生实质性变更时,我们将通过以下一种或多种合理方式向您提示更新内容: * 在软件启动时通过弹窗或提示信息展示; * 在官方网站或项目主页(例如 GitHub 仓库)发布公告。 3. **接受与拒绝** * 自更新版本发布或通知中载明的生效日起,**您继续下载、安装或使用本软件,即视为您已充分阅读、理解并接受更新后的协议内容**; * 如您不同意更新后的协议内容,您应当立即停止使用本软件并卸载已安装的版本。 > 为便于您了解最新条款,建议您不时查阅本协议所在页面或官方仓库中的相关文件。 ### 八、适用法律与争议解决 1. **适用法律** 本条款的订立、执行、解释及争议的解决,均适用中华人民共和国(为本条款之目的,不包括香港、澳门特别行政区及台湾地区)法律。若中华人民共和国法律未作规定或规定不明,则参照商业惯例或行业通用规则。 2. **当地法律的例外(消费者保护)** 尽管有上述约定,如果您是欧盟、英国、美国或其他司法管辖区的消费者,且当地法律明确规定了不可通过合同排除的强制性消费者保护权利(例如必须在消费者居住地起诉),则本条款中的管辖约定不应剥夺您根据当地强制性法律享有的权利。在此情况下,本条款的其他部分仍具有完全的法律效力。 3. **语言** 本条款可能以多种语言发布。若中文版本与其他语言版本存在冲突或歧义,在适用法律允许的范围内,以简体中文版本为准。 ### 九、联系我们 如您对本协议、本软件的使用、开源许可、隐私保护或其他相关事宜有任何疑问、意见或建议,欢迎通过以下方式与我们联系: * **项目主页(GitHub):** * **联系邮箱:** * alan-crl@foxmail.com * alancrl1007@gmail.com 我们将尽合理努力在能力和资源允许的范围内,尽快回复您的合理咨询或反馈,但不保证对所有来信逐一答复。 --- --- url: /tutorial/ppt-admin.md --- # Microsoft Office/PowerPoint 无法以普通用户权限运行的解决方案 ::: tip 提示 本文章同步发布在 CSDN 上,作者均为 AlanCRL。 ::: ## 前言 这些程序运行时就以管理员权限运行了,并且没有兼容性选项卡,接下来教你如何通过修改注册表取消 Office 默认以管理员身份运行。 ## 步骤 ### Win+R 输入 `regedit` ### 打开路径一 打开 `HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers` 看看有没有相关程序,如果有则删除。 ![在这里插入图片描述](/tutorial/ppt-admin/1.png) ### 打开路径二 打开 `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers` 看看有没有相关程序,如果有则删除。 ![在这里插入图片描述](/tutorial/ppt-admin/2.png) ### 最后 重启计算机就可以了。 ## 附件 如果您使用的是 WPS,原理一样。也是在这两个目录中看看有没有包含 ksolaunch.exe 的项,如果有请删除就可以了。 --- --- url: /tutorial/ppt-com.md --- # 程序无法识别 Office/WPS 的 COM 接口失效/无法识别解决方案 ::: tip 提示 本文章同步发布在 CSDN 上,作者均为 AlanCRL。\ ::: ::: note 新功能 智绘教Inkeys 20260102a 引入了 PPT 联动助手 3,**可以在 COM 损坏的情况下依旧可以正常联动**,并且兼容至 Microsoft PowerPoint 2007 和 Kingsoft WPS 2013 及以上版本,欢迎 **[下载体验](/download)**。[PPT 联动助手 3 详细介绍](/version/introduction/pptcom3)。\ ::: ## 前言 当我们在使用依赖于 OfficeCOM 的 C#/VB 等程序(如:智绘教Inkeys)时,COM 很有可能因为多个软件冲突导致注册表错误最终 COM 接口识别不到了。这篇文章将带你解决这个问题。 主要的原因肯定是注册表错误了,但是操作过于复杂了。本篇文章讲述的是适用于大多数人的操作。 **现在先尝试使用管理员权限运行程序试试看能不能检测到 COM**,如果确认任何权限都不行的话就可以开始继续往下看了。但是如果发现管理员权限就可以,并且 Office 无法在普通用户权限下运行,可以参考[这篇文章](ppt-admin)。 ## 适用情况 * Microsoft Office 或 WPS 或二者的 OfficeCOM(Word/PowerPoint/Excel 等) 接口无法使用。 > 无论你是只安装了 WPS 然后 COM 无法使用,还是两者都安装了其中一者的 COM 无法使用,这篇文章都可以通过通用的方式解决。 > Microsoft Office 的任何版本都适用,例如 365、2024、2021、2019、2016 等等。 ## 准备软件 * [Office Tools Plus](https://otp.landian.vip) > 我们主要用它修复注册表和本地文件错误,如果你只安装了 WPS 但 COM 接口错误了,同样也适用。 ## 开始教程 ### 一、卸载所有需要**注册** COM 的软件 #### Microsoft PowerPoint(如果安装有) 无论是 商店版 还是 即点即用Check-To-Run/MSI 安装版,都可以在 设置/控制面板 中卸载。 ![选择 Office 并卸载即可](/tutorial/ppt-com/1.png) 如果常规方案无法卸载,请使用 Office Tools Plus 工具箱中的强力卸载。 ![强力卸载](/tutorial/ppt-com/2.png) #### WPS(如果安装有) 同样也可以通过 设置/控制面板 进行卸载。 需要注意的是,下面选项需要选择“不再使用”,并清除数据。 ![在这里插入图片描述](/tutorial/ppt-com/3.png) #### 畅言智慧课堂(如果安装有) 这个软件安装时会修改 COM 注册表,来阻止其他软件读取 COM,所以也一并卸载了。 ### 二、重启计算机 全部卸载完成后,重启计算机来清理剩余文件。 ### 三、修复注册表和 COM 环境 #### 打开 Office Tools Plus ![在这里插入图片描述](/tutorial/ppt-com/4.png) #### 转到工具箱,并点击 Office 工具中的移除 Office ![在这里插入图片描述](/tutorial/ppt-com/5.png) 完成后就可以进行下一步了。 ### 四、重新安装你所需要的 Office 软件 **非常重要!** 如果你需要安装 Microsoft Office 和 WPS 两者,请务必按照**先**安装 Microsoft Office 后**再**安装 WPS(不能换顺序,不能同时装)。安装 WPS 的时候务必勾选下列选项。(如果忘记勾选则会导致 Microsoft Office 的 COM 接口失效,并且安装后再修改可能会没有作用,则需要重新开始本文章的步骤。) ![在这里插入图片描述](/tutorial/ppt-com/6.png) ### 阶段性总结(基本上这里问题就可以解决了) 如果你发现你的 COM 恢复了,那么恭喜你了。但是如果你发现你的 Microsoft Office 还是不行。(如果你安装了 WPS 32位,会发现 WPS 却可以),那么请跟着教程继续操作。 ### 深入分析更复杂的问题 应该是第三方程序将 32 位的 COM 接口注册表信息搞坏了,但是通常 PPT 安装的都是 64 位或者 ARM64,无法覆盖之前的错误的注册表。而 WPS 通常是 32 位的,就可以正确覆盖并被识别到。WPS 64位版应该也无法识别,所以下面我们就按照步骤开始修复。 ### 五、重复步骤 重复步骤 一 ~ 三,全部卸载、重启然后修复。接下来使用 Office Tools Plus 软件安装 32位/arm(32) 的 Office(我们只是用 32 位版本修复 32 位的注册表,如果你最终打算用 64 位,则在 32 位安装完成后卸载并安装 64 位)。 ### 六、部署 32 位/ arm(32) 的 Microsoft Office 选择部署 32 位 Office 程序(务必勾选基础三件套) ![在这里插入图片描述](/tutorial/ppt-com/7.png) > 如果您只使用 WPS 或 没有Office 的激活,没有关系,我们只是下载用于修复,并不需要激活。 点击部署并耐心等待安装完成。安装完成后打开任意套件并同意许可协议。 ![在这里插入图片描述](/tutorial/ppt-com/8.png) ### 阶段性总结 此时你就会发现新安装的 Office 的 COM 接口正常了,如果你本来的目的就是使用 32 位的 Office,则可以不继续下面的教程了。 ### 七、强制卸载 32 位 Microsoft Office 和步骤三一样,直接使用 Office Tools Plus 卸载,而不用走官方的卸载方式。(因为官方的卸载方式会把安装前备份的注册表还原,这下注册表又变成原来那种错误的了,就等于啥都没做) ![在这里插入图片描述](/tutorial/ppt-com/9.png) ### 八、重新安装你所需要的软件即可 现在可以按照你的需求安装任意架构的 Office 即可。 按照步骤四即可,务必主要安装顺序和 WPS 需要勾选的选项。 ### 阶段性总结 如果你发现你的 COM 恢复了,那么恭喜你了。但是如果你又发现在 32 位 Microsoft 中可以正常使用的 COM,等到我安装 64 位的 WPS 时又不行了,这说明 64 位的 COM 也损坏了。那就从步骤五再重新开始,只不过安装的是 64/arm64 的 Microsoft Office。 最后,希望这篇文章可以帮助到你。 --- --- url: /tutorial/ppt-flash.md --- # Microsoft Office 如何启用和正常播放 Flash 控件 ::: tip 提示 本文章同步发布在 CSDN 上,作者均为 AlanCRL。 ::: 对于新安装的 Office 默认是不支持启用 Flash 组件的,Flash 组件会无法播放或者黑屏。 本片文章就带你解决这个问题,相关资料都在下方连接内。前提概要,教程对应的版本是 mso16,即 Office 2016 及更新版本,以及 365 等。 ### 步骤一 你需要给你的电脑安装 Adobe Flash Player,注意不是 **Flash中心**(如果安装了请先卸载)。如果你已经安装了,或者正确安装了其他版本的 Flash Player(例如 Clean Flash Player 等),可以进入步骤二。 前往官网下载 Flash,你需要安装 ActiveX 和 PPAPI 版本。 *** 打开网址:[点击此处](https://www.flash.cn/download-wins) 注意:**请先看完下方图例,再下载!!!** ![在这里插入图片描述](/tutorial/ppt-flash/1.png) (神的,官网也能这么流氓!) **下滑后**,下载前两个并安装。 ![在这里插入图片描述](/tutorial/ppt-flash/2.png) 安装完成后,请关闭你的 Office(如果 Office 打开)。 ### 步骤二 导入秘制的 REG 注册表文件。 先下载压缩包:[123盘-已经设置免登录不限速](https://www.123912.com/s/duk9-wkQAd) 打开压缩包,依次**将三个都**合入注册表。 ![在这里插入图片描述](/tutorial/ppt-flash/3.png) ### 大功告成 重启你的 Office ,你应该会看到如下提示: ![在这里插入图片描述](/tutorial/ppt-flash/4.png) 勾上“我可以识别此内容。运行播放” 并点击继续。 ![在这里插入图片描述](/tutorial/ppt-flash/5.png) 太好了,Flash 动起来了! *** 接下来就可以正常使用了! ### 附录 小伙伴可能对 reg 的内容不放心,在此提供预览。 ![在这里插入图片描述](/tutorial/ppt-flash/6.png) ![在这里插入图片描述](/tutorial/ppt-flash/7.png) ![在这里插入图片描述](/tutorial/ppt-flash/8.png) 点个赞再走吧~ --- --- url: /tutorial/pptx-video-processing.md --- # PptxVideoProcessing PPT/视频处理 [下载 PptxVideoProcessing](https://www.123865.com/s/duk9-lLoAd)\ [Github 仓库](https://github.com/Alan-CRL/PptxVideoProcessing) 支持 Windows 10 及以上 64 位系统。 *** PptxVideoProcessing 可以直接将 .pptx 文件中的视频直接进行处理,可以自定义编码、帧率、分辨率和音量等。并批量处理 PPT 中的视频文件。 在较老演示设备上播放高质量视频可能会出现卡顿,PptxVideoProcessing 应运而生。可以将视频修改后得到处理过后的 .pptx 文件,PPT 中的视频位置和尺寸和其他放映行为将保持不变。 PptxVideoProcessing 还支持直接处理其他常见的视频文件。同时支持 Intel AMD NVIDIA 硬件加速和系统原生加速。 *** PptxVideoProcessing 使用 C++23 和 .NET8 构建,附带 ffmpeg 7.0。\ --- --- url: /tutorial/tutorial.md --- # 知识库 查找使用教程?前往我们的 [教程](/wiki/wiki) *** 一些 AlanCRL 在开发 智绘教Inkeys 途中顺路编写的非常有价值的博客。 * [程序无法识别 Office/WPS 的 COM 接口失效/无法识别解决方案](ppt-com.md) * [Microsoft Office/PowerPoint 无法以普通用户权限运行的解决方案](ppt-admin.md) * [Microsoft Office 如何启用和正常播放 Flash 控件](ppt-flash.md) *** 一些开发者的其他小项目: * [PptxVideoProcessing](pptx-video-processing) > 提取并处理 Pptx 文件中的视频的编码和帧率,以适用于老设备。 --- --- url: /version/changelog/20240719a.md --- # 20240719a 新版本发布 ## [智绘教20240719a](https://github.com/Alan-CRL/IDT/commit/04a3b368c6a571ad2bad246a49fde6a158878903) `+` PPT 控件可以拖动并自定义缩放\ `+` 兼容自动隐藏任务栏选项\ `-` 修复选择模式下 Ctrl + Q 被占用的问题\ `-` 修复 Ctrl + E 打开穿透过后,无法关闭穿透的问题\ `-` 修复 PPT 最后一页无法长按翻页的问题\ `-` 修复选项窗口名称不正确的问题\ `-` 修复 PPT 潜在的内存泄露的问题\ `-` 修复多屏用户无法在主显示器上绘图的问题 `!` 注意:这是个网络发布版本,LTS通道将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250128a.md --- # 20250128a 新版本发布 ## [Inkeys20250128a](https://github.com/Alan-CRL/IDT/commit/04a3b368c6a571ad2bad246a49fde6a158878903) `+` 全新 设置3.0 界面\ `+` 新 智绘教Inkeys 图标\ `+` 全程序 Unicode 编码化\ `+` 向下兼容至 Windows 7 sp0\ `+` 全新 更新系统3.0 与程序更新 https 加密下载\ `+` 新增 快捷方式保障助手 插件\ `+` 智能绘图新增直线模式下的端点吸附\ `+` 新增重复开启程序提示\ `+` 新增运行程序强制置顶选项\ `+` 细化智能绘图选项,可单独控制抬笔拉直,停留拉直,端点吸附\ `+` 新增预览体验计划模块,申请通过的成员用户可以切换通道到预览通道\ `+` 新增程序修复和预览成员的版本回退功能\ `+` 新增全新问题意见反馈通道\ `+` 自动更新新增更多更新信息反馈\ `+` 修复绘图设备被错误识别的问题\ `+` 新增落笔预备功能\ `+` 新增压感橡皮功能\ `+` PPT控件支持全区域拖动\ `+` PPT控件结束按钮改为抬起触发,并增加拖动功能\ `+` 对 ppt 翻页的 enter 和 backspace 的支持\ `+` 优化点击主栏时误识别为拖动,而无法展开的问题\ `=` 降低 CPU 占用比率\ `=` 降低内存占用比率\ `=` 开机启动设置更简便\ `=` 优化停留拉直的识别准确度\ `=` 优化抬笔拉直的识别准确度\ `=` 优化直线/矩形吸附的准确度\ `=` 去除 CrashedHandler 辅助程序,主程序已经相对稳定\ `=` ImGui dx11 转为使用 dx9,增强系统兼容性\ `=` 程序将从内存中正确加载字体,不依赖本地字体文件\ `=` 提升开机启动优先级\ `=` 画笔粗细选择将随着屏幕大小变化\ `=` 插件设置中增加了一些实用性提示\ `=` 触控库重构\ `=` 用户ID获取方式改用新版,减小冲突\ `=` 修复启动时会错误地抢占焦点的问题\ `=` 龙年迎新皮肤替换为蛇年迎新\ `-` 修复 WPS 放映检测不及时或无法检测到的问题\ `-` 修复快速开关悬浮窗拦截插件会导致插件失效的问题\ `-` 修复 ppt 两侧控件在末页时书写时退出放映是失效的\ `-` 修复图形颜色和粗细在抬笔时错误变化的问题\ `-` 修复了由于引用程序名称包含非ASCII字符导致DWN错误导致应用程序无法启动的问题\ `-` 修复了绘制矩形时点击导致的绘制异常问题\ `-` 修复了 PPT 中部控件缩放无法正确保存的问题\ `-` 修复了通过快捷键切换到画笔时画笔选项栏不会收回的问题\ `-` 修复了通过任务栏关闭选项页面后无法再次打开选项的问题\ `-` 修复在结束放映页时PPT控件下一页按钮图标显示错误的问题\ `-` 修复由于颜色的自动切换,悬浮窗背景颜色会无法切换的问题 `!` 注意:这是个网络发布版本,LTS通道将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250209a.md --- # 20250209a 新版本发布 ## [Inkeys20250209a](https://github.com/Alan-CRL/Inkeys/commit/9b525830060df3dfa538e18dd88440b5db9e60ff) `+` 新增 win64/arm64 架构 `+` 新增软件修复功能 `+` 新增架构提示(在软件架构和系统架构不符时) `+` 新增避免全屏显示功能 `+` 启用更多设置界面的 Fluent 风格 `=` 优化选项界面 `=` 增加自动更新开关 `-` 修复图像加载冲突的问题 `-` 修复了软件更新和软件修复模块可能存在的问题 `!` 注意:这是个网络发布版本,LTS通道将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250403a.md --- # 20250403a 新版本发布 ## Inkeys20250301a #52 `+` 新增创建单次快捷方式按钮 `+` 将选项界面加入置顶序 `+` 为自动更新增添进度显示和更多提示 `+` DDB增加更多精细控制 `=` 优化插件选项界面布局 `=` 选项界面更宽的滚动条 `=` 主栏的自适应的拖动 `=` 启动时遇到错误可以尝试重启一次再报错 `-` 修复了旧版本升级过程中重复下载无法自动更新的问题 `-` 修复窗口创建后意外地获取到焦点的问题 `-` 修复 Ppt 结束放映后小概率光标消失的问题 `-` 修复 Ppt 结束放映确认窗口弹出时无法操控键盘的问题 `-` 修复 Ppt 末页绘制时可能无法帮助退出 Ppt 的问题 `-` 修复 Ppt 动画加载过程中按 esc 退出也会导致鼠标消失的问题 `-` 修复定格时不会排除选项窗口的问题 `-` 修复快捷方式保障助手意外删除桌面快捷方式的问题 `-` 修复定格模式下窗口仍然会穿透窗口的问题 ## Inkeys20250309a #58 `=` 优化窗口置顶逻辑 `=` 优化窗口消息传递逻辑 `=` 优化关闭自动更新选项后的逻辑 `-` 修复选项->插件页面无法下滑的问题 `-` 修复选项->绘制->智能绘图中拉直选项无法单独开关的问题 ## Inkeys20250403a #61 作为预备正式版本,没有任何更新说明 *** `!` 注意:这是个网络发布版本,LTS通道将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250503a.md --- # 20250503a 新版本发布 ## Inkeys20250503a #64 `+` 在绘制窗口中会禁用相关触摸手势(边缘手势,长按手势和笔势),使书写更流畅 `+` 选项界面支持按住滑动翻页 `+` 新增ppt控件缩放同步调节 `+` 新增高性能绘图性能选项 `+` 新增隐藏触摸光标选项 `+` 新增“拖动主栏时收起主栏”和“点击时收起主栏”选项 `+` 新增更新通道提示 `+` 新增更新架构选择 `+` 新增更多实用组件 `+` 选项新增教学安全选项 `+` 选项新增显示ppt加载动画选项 `+` 选项新增保存板块 `=` 当自动更新失败时则会继续运行旧版本 `-` 选色盘意外导致程序崩溃问题 `-` 修复低性能机器上易触发的绘制不跟手及卡顿问题 `-` 修复撤回和超级恢复导致的崩溃问题 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250606a.md --- # 20250606a 新版本发布 Inkeys20250606a #89 (CI/CD:) --------------------------------------------------------------------- `+` 新增:使用 CI/CD 构建版本 `+` 新增:CI/CD 详细信息现在可以在Actions任务页面、发布Package中、发布版本的Tips.txt中和软件内的软件版本中查看 `+` 新增:使用 SHA256 代码签名 `+` 新增:超级置顶插件 `+` 新增:选项新增教学安全选项 `+` 新增:选项新增显示ppt加载动画选项 `+` 新增:选项新增保存板块 `+` 新增:启用配置清理的设置选项 `+` 新增:修复时修正软件架构选项 `+` 新增:在自动更新失败时出现手动更新链接 `+` 新增:选项预设选项卡 `+ ****` 记忆绘制颜色 `+ ****` 记忆绘制粗细 `+ ****` 自适应绘制粗细 `+ ****` 预设默认画笔粗细 `+ ****` 预设默认荧光笔粗细 `=` 修正:系统架构不一致时的提示 `=` 修正:更新通道提示内容 `=` 优化:绘制时光标隐藏的效果 `=` 优化:Ppt联动未勾选记忆控件位置时,将在退出ppt恢复控件位置 `=` 优化:为选项中的拖动条增添了数值反馈 `=` 优化:绘制粗细预设 `-` 缓解:Ppt联动模块导致关闭程序时出现的程序运行错误问题 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250721a.md --- # 20250721a 新版本发布 Inkeys20250721a(LTS) #96 (CI/CD:) --------------------------------------------------------------------- `+` 新增:语言 `English(BETA)`,`繁體中文(BETA)` `=` 优化:选项界面显示效果(下拉框) `=` 优化:启动命令行优化,重构超级置顶逻辑 `=` 优化:社区名片界面 `=` 优化:去除自动关闭游离卡死的wpp选项,优化代码后wpp现在已经可以正常退出 `-` 修复:使用穿透后可能出现的卡顿问题 `-` 修复:ppt 意外结束放映时导致画板状态出现错误的问题 `-` 修复:ppt 绘制下,在末页无法拦住并提示的问题 `-` 修复:提示更新到最新版本时,如果修复并选择了不一样的架构,错误安装不同架构的问题 `-` 修复:可能无法普通置顶的问题 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250822a.md --- # 20250822a 新版本发布 Inkeys20250812a(LTS)\ (CI/CD:https://github.com/Alan-CRL/Inkeys/actions/runs/16906494939)\ `+` 改进:首次启动时根据 dpi 改变选项界面缩放\ `=` 优化:大幅降低选项界面的内存占用\ `=` 处理:更新了自动更新设置,一些设备可能会被阻止自动更新\ `-` 修复:快速点击设置按钮导致设置页面卡死无法点击的问题 Inkeys20250822a(LTS)\ (CI/CD:https://github.com/Alan-CRL/Inkeys/actions/runs/17151401338)\ `+` 新增:SecRandom 和 NamePicker 两款点名器的调用组件\ `+` 更改:启用新的更新地址\ `+` 新增:Canary 更新通道\ `=` 优化:繁体中文下可以正确显示简化字 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20250830a.md --- # 20250830a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > Inkeys3 即将到来 · [兼容性调整说明](https://www.inkeys.top/win7) **Inkeys20250830a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/17344181719)**\ `+` 新增:Ppt 长按翻页新增触摸支持\ `+` 新增:Ppt 操控栏新增触摸支持\ `=` 优化:鼠标和键盘消息处理逻辑,提高可靠性\ `=` 优化:触控库逻辑并提升效率\ `=` 优化:使绘制更加跟手\ `=` 优化:UI字体文件改为从资源文件中直接加载(不再在本地释放文件)\ `=` 调整:win7 用户只会在接受到 Inkeys3 更新时需要手动更新\ `=` 优化:D2D1的工厂,使在 win7 rtm 下更加稳定\ `=` 优化:优化文本UTF8和UTF16在程序内部的转换效率\ `=` 优化:新的崩溃处理逻辑使程序在启动过程中遇到崩溃,则不会无限重启\ `=` 调整:选项中绘图模式的说明方法\ `-` 修复:多屏显示器可能遇到的无法启动的问题\ `-` 修复:Ppt 翻页时无法打断翻页动画的问题\ `-` 修复:WPP 有时候无法正确退出的问题\ `-` 修复:程序崩溃提示重启时,无法点击关闭按钮直接关闭程序的问题 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20251204a.md --- # 20251204a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > [智绘教Inkeys 官方网站](https://www.inkeys.top)\ > [智绘教Inkeys 使用条款](https://www.inkeys.top/tos/zh-cn)\ > Inkeys3 即将到来 · [兼容性调整说明](https://www.inkeys.top/win7) *** ## **Inkeys20251204a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/19918761946)** `+` 新增:DDB 新增拦截目标\ `+` 新增:DDB 中部分拦截目标在白板时的自动恢复功能\ `+` 新增:Ppt 点击页码可以选择页面(BETA)\ `=` 优化:博客文章链接改为 inkeys.top\ `=` 优化:优化设置界面渲染后端\ `-` 修正:Canary标识从其他通道改为早期通道标识\ `-` 修正:一些翻译问题\ `-` 修复:选项页面的一些布局问题\ `-` 修复:Ppt 两侧中部翻页按钮位置无法被记忆的问题 *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20260102a.md --- # 20260102a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > [智绘教Inkeys 官方网站](https://www.inkeys.top)\ > [智绘教Inkeys 使用条款](https://www.inkeys.top/tos/zh-cn)\ > Inkeys3 即将到来 · [兼容性调整说明](https://www.inkeys.top/win7) ## **Inkeys20260102a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/20657467715)** `+` 新增:PPT联动助手 3 Lite\ `=` 优化:一些页面逻辑 [PPT联动助手 3 - 详细介绍](https://www.inkeys.top/version/introduction/pptcom3.html) ![](/changelog/pptcom3.png) *** **Full Changelog**: *** `!` 注意:这是发布的 正式版本,更新通道(正式通道)中的软件版本将于杀软人工审核通过后与此版本同步 --- --- url: /version/changelog/20260206a.md --- # 20260206a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > [智绘教Inkeys 官方网站](https://www.inkeys.top)\ > [智绘教Inkeys 使用条款](https://www.inkeys.top/tos/zh-cn)\ > Inkeys3 即将到来 · [介绍](https://www.inkeys.top/inkeys3) · [兼容性调整说明](https://www.inkeys.top/win7) ## **Inkeys20260206a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/21741277023)** `+` 新增:PE 中以兼容模式运行本软件\ `+` 新增:在 RTS 触控库损坏的时候以鼠标兼容模式运行本软件\ `+` 新增:在放大镜 API 损坏的时候运行本软件(此时无法使用定格相关功能)\ `+` 新增:DDB 3 Lite 发布,新增拦截项\ `=` 优化:在 Ppt 联动未安装 .NET Framework 4.x 版本的时候给出提示\ `=` 优化:DDB 升级匹配机制,识别更加准确\ `=` 优化:DDB 新增窗口追踪关闭窗口更及时\ `=` 优化:全局低级鼠标钩子逻辑,绘制更流畅\ `-` 修复:重启更新阶段,关闭自动更新时还会自动更新的问题\ `-` 修复:重启更新阶段,切换更新目标架构不会重新下载对应架构软件的问题\ `-` 修复:DDB 自动恢复功能异常的问题\ `-` 修复:PPT 组件轮询模式下存在的问题\ `-` 修复:DDB 无法切换为管理员模式的问题 ## **Inkeys20260214a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/22016689927)** `-` 修复:修复了一些问题,并优化体验 *** **Full Changelog**: --- --- url: /version/changelog/20260502a.md --- # 20260502a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > [智绘教Inkeys 官方网站](https://www.inkeys.top)\ > [智绘教Inkeys 使用条款](https://www.inkeys.top/tos/zh-cn)\ > Inkeys3 即将到来 · [介绍](https://www.inkeys.top/inkeys3) · [兼容性调整说明](https://www.inkeys.top/win7) ## **Inkeys20260502a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/25267259639)** `+` 新增:适配 SecRandom 2 的 IPC 和 URL 调用\ `+` 新增:适配 IslandCaller 2 的 URL 调用\ `+` 新增:PPT演示助手支持无文件保存的演示联动\ `+` 更新:DesktopDrawpadBlocker 版本升级至 2.1\ `-` 修复:PPT 联动在 PowerPoint/WPS 忙碌时可能绑定失败或中断的问题\ `-` 修复:切换更新架构后仍可能继续使用已下载旧安装包的问题\ `-` 缓解:PPT按钮无法抬起的问题 *** **Full Changelog**: --- --- url: /version/changelog/20260713a.md --- # 20260713a 新版本发布 ## 感谢 HelloGithub 对本项目的大力支持![详情](https://hellogithub.com/repository/Alan-CRL/Inkeys) > [智绘教Inkeys 官方网站](https://www.inkeys.top)\ > [智绘教Inkeys 使用条款](https://www.inkeys.top/tos/zh-cn)\ > Inkeys3 即将到来 · [介绍](https://www.inkeys.top/inkeys3) · [兼容性调整说明](https://www.inkeys.top/win7) ## **Inkeys20260713a(LTS)** - Inkeys2 · **[CI/CD](https://github.com/Alan-CRL/Inkeys/actions/runs/29267288526)** `=` 优化:PPT 联动组件的多线程访问、异常恢复和自动重试机制,提升联动稳定性\ `-` 修复:同一演示文稿可能被识别为多个实例,导致 PPT 联动反复重新绑定或短暂中断的问题 *** **Full Changelog**: --- --- url: /version/inkeys3.md --- # Inkeys3 即将发布 ::: tip 您的版本是最新的 Inkeys3 LTS 正式版尚未发布,目前最新版本为 Inkeys2 的 `20260214a`。 新动态:Inkeys3 的早期版本已经在 Canary 通道发布!\ ::: 我们现在已经邀请我们的早期伙伴进行测试,新功能正在全力开发中,敬请期待~ *** 一些 Inkeys3 的功能也下放至 Inkeys2 中: * [PPT演示助手 3](introduction/pptcom3) *** 还有一些注意事项: * [兼容性调整](introduction/win7) --- --- url: /version/introduction/pptcom3.md --- # PPT演示助手 3 全新的 **PPT演示助手 3** 已经上线,本次更新使得COM注册损坏的设备也可以成功联动。提升兼容性的同时健壮了代码,适用于更多极端的场景。 ## 重点升级 * \[x] 识别COM注册损坏的PPT。 * \[x] 动态切换,优先绑定最上层的放映窗口。 - \[x] 兼容至 **Microsoft PowerPoint 2007** 和 **Kingsoft WPS 2013**。 * \[x] 升级为轮询和事件注册双模式,应对COM损坏严重无法注册事件的情况。 ## 其他升级 * \[x] 在 WPS 未勾选“兼容第三方系统和软件”的时候连接到 WPS * \[ ] 支持高权限读取到低权限(例如管理员下的 Inkeys 可以读取到普通用户权限的 Powerpoint) ## 技术交流 相信许多开发者朋友对我的解决方案感兴趣,或者其他朋友们好奇我的开发经历。所以接下来我将按照时间顺序,讲述这次的开发过程。 本次更新的开发周期约为 60 小时,过程极为曲折。(毕竟我本以为也就 10 小时顶天了,没想到问题一个接一个)如果您想要借鉴,请遵守 **GNU General Public License v3.0 开源协议** 和 **智绘教Inkeys 使用条款**,尊重他人劳动成果,在您的开源 README 中添加 智绘教Inkeys 的引用标识,并添加 Copyright 标识。否则,具体后果见使用条款。 原先的联动设计是 Inkeys 1 时期(大概 202304)的时候搞出来的。代码还算健壮,并在后期修修补补,得到了不错的体验。 Inkeys 2 时期,我专项突破了超级置顶、UI3、绘图模块3等,是我的代码水平得到了提高。近期我观察到许多用户还是被 PptCom 的问题所困扰,并且其他家开源批注软件也没有更好的方案。(请注意,智绘教拥有便携性定位,所以 VSTO 的方案并非最优解)刚好 202507 我深入学习了 C#,所以经过我对 C# COM 开发的研究,发现似乎真的可以解决这个难题。 ### 早期阶段 说干就干,第一个问题是绑定 PptCom 的问题。一个方案是使用 Running Object Table 进行查找,还有就是通过 WM\_GETOBJECT 消息来获取 COM 对象。ROT 的问题是权限隔离,就和先前用的 GetActiveObject 问题一样。只不过 ROT 可以在对应注册表损坏的情况下自己找到你想要的。而 GETOBJECT 那边一点进度都没有,根本没有成功过。(Beta 测试时期,我又试了一遍,但似乎 PowerPoint 不理我)所以我最终使用 ROT。 ROT 的目标被设置为 PowerPoint.Application 的经典 GUID 和含有类似 .pptx 后缀的十多种放映后缀名的匹配项。(得益于一般 Ppt 会把完整路径名称的 COM 也注册在 ROT 里面)不过由于 KWpp.Application 的 GUID 在不同版本之间都在变,所以 WPS 就没法这样搞。 然后是引入的优先级概念,我将有效优先级分为3个等级。有 Application 和 ActivePresentation 的为 1,有 SlideShowWindow 的为 2,而放映窗口激活或者是焦点的为 3。这里出现了一个问题,就是WPP在非全屏放映下,SlideShowWindow.HWND 的窗口并非焦点窗口,焦点窗口是 WPS 主窗的框架。我打算识别是否为父子窗口,不行。识别为所有者窗口?不行。后面发现都不是同一进程的(一个是 WPP 的,一个是 WPS 的)。于是我改了一下,也就是放映是 WPS 的,前台焦点只要是 WPS 就把优先级设为 3。有人就要问了,那么对应 WPS 多开的情况下,你怎么确定哪一个是真正的焦点放映窗口呢?很简单,妙就妙在还有个 ActivePresentation 的比较,如果当前不是了,就说明前台在别的放映窗口,重新绑定就是。 插一嘴,为啥有了放映窗口激活状态的检查,还需要这个焦点检查?答案是 WPS 的非全屏放映在任何是焦点的时候都是 false。还记得我自己判断焦点的时候遇到的问题吗?当然,WPS 自己都没发现这是个问题,还是想当然认为 SlideShowWindow.HWND 是焦点的时候就激活了,没想到无论用户点哪里,激活的焦点都是 WPS 的框架和里面一个类名是 Rendering 的窗口,而不是真正的一个类名是 qt 开头的窗口。(当然测试环境是 2025冬季更新 的版本) 悄悄告诉你,先别急,WPS 挖的坑不止这一个。 优先级判断写好了,那么动态绑定就迎刃而解了。只要有其他的目标比我当前绑定的这个目标的优先级更高,那么我就解除绑定,然后绑定那个新的。简单来说,动态绑定的逻辑分为两种: * 优先级比较 * ActivePresentation 比较 然后我意识到事件注册来获取页数太脆弱,虽然我之前也写了每3秒没有事件激活的时候,就轮询一下。毕竟这种回调很不靠谱。(就像微信支付SDK让你绝对不要根据支付成功的消息返回来评判用户是否成功支付,一定要自己去查询支付状态)于是我加强了这个逻辑,在事件注册失败的时候,选择500ms轮询一次,而不是3秒。这个决策是在后面过程中认为是十分正确的。 ### Alpha 阶段 这部分开发大约用了 10 小时,我自己跑了一下,看起来非常完美,于是我开启了 Alpha 测试。先给我自己打造了一些不光是 COM 注册表内容损坏的场景,还有本地文件损坏导致 COM 注册损坏的环境。然后绷不住了,根本用不了。 一番捣鼓发现,这个 ROT 获取到的对象,虽然的确是用 Reflection 拿到的 Application,但是和 Microsoft.Interop.PowerPoint.Application 的 TypeID/GUID 不匹配,完全没法早期绑定。通常是混装 WPS 和 PowerPoint 导致的。这使我恍然大悟,之前研究怎么修复注册表来修复 COM 一直毫无进展,而后面研究出的全部卸载重装的方案却有效果,就是因为文件遭到了损坏。而且经过我的研究,并不是说类似文件相互覆盖杂糅的这些损坏,而是注册表中对应的本地dll位置发生了变化,然后某一方修改不彻底。(不用猜了,就是这个 WPS,由于注册修改不完全,和位数问题)这些设备只要没有按照正确顺序安装它们,并勾选兼容第三方的系统和软件,那么多半 COM 就会坏掉。 于是我成功模拟出了一种环境A,wps32 和 mso64 的组合。在这个环境下,智绘教20250830a 表现为 win32 版本可以正确识别二者,而 win64 版本啥都识别不到。然后我卸载 mso64,装上 mso32,结果一切正常了,果然是一些 dll 的问题。在装 mso32 之前,我恢复之前的注册表或者使用 mso 的自我修复,都没效果,看来确实是这样。这个场景确实是由于 WPS 勾选了兼容第三方系统和软件,并且把自身伪装成 Microsoft PowerPoint 并且位数不一样所致。 回归正题,我发现 .NET framework 4.0 引入了一个非常好的 com 利器,也就是 dynamic 来动态调用这些方法和属性。于是我把 ROT 改为获取RCW 并全部存为 dynamic,过程中还有可能转为 object 使用。 噩梦开始,dynamic 完全就是和它名字一样,就是个边用边包装。首先可能目标属性某些不存在,或者是拒绝访问。我搭建的3组测试环境各种问题频出。所以我花了 15 个小时一直在加 try-catch。并且一会这个 dynamic 又失效了,一会那个属性突然挂了,真的让人抓狂。因为他是 dynamic,它竟然给他绑的啥都会自己变。例如 SlideShowWindow 绑好后结束放映再开始放映,这个有时候会失效,有时候变成其他的了。而原来 Interop包 的那个会自动重定向就很方便。于是我给 SlideShowWindow 加了个动态检查和重绑。问题总算好一些了。 问题接踵而至,SlideShowWindow 的 HWND 死活没法用 dynamic 的 .HWND 得到,而 Width 之类的就可以。我尝试使用反射获取,不行。然后费了好大劲去查文档,写了个 IDispatch 去扫了一遍,发现 HWND 的 ID 是 2010,就躺在那里,但是就是死活拿不到。后面发现是被保护的 Protected Properties。不过我就纳闷了,Width 也是一样保护的,为啥别人就行呢?(后面 Beta 测试的时候又发现 Width 也不行了)我写了个简单早期绑定接口,只拿这个 2010,结果会错位,拿到的是 2001 的 Active 属性的。于是我补齐了 2001-2010 的这些。结果前面有个 Application,类型又不对了,气死我了。写了个 Accessible 拿 HWND,不理我。后面想到自己原来是写 Win32 的,直接匹配标题和窗口位置唯一确定,问题解决了。 更严重的问题,这个 RCW 我 . 一下访问一个属性,就给我引用计数加个一,结束的时候GC不能很快回收,即使是你自己搁那疯狂 GC.Collect() 也不行,毕竟是 RCW 自己的引用计数。这个不清空完 PowerPoint 就一直死在后台,并且一定时间内无法打开当前文件。(com 正常情况下是不会出现这个情况的,只是后台会一直留着)我索性使用 FinalReleaseObject,无济于事。发现中间有个 SlideShowWindow.View.SlideIndex,中间还有个引用计数,ActivePresentation 判断那里也会有新的引用计数,还有 ROT 循环那里等。于是我又疯狂加 ReleaseObject,结果问题越来越多。这玩意我把它比做进阶版的cpp指针,首先你增加多少个引用计数,就得精准减少多少个。如果你少减少了,那么最终 PowerPoint 就会一直死那。如果多减少了,这个 RCW 就会提前自动销毁,直接殃及其他正在用这个 RCW 的功能。还有一个就是指针中经典的指针赋值的所有权转让问题了,这种地方需要仔细思考是否需要释放。还好我早年间在 cpp 写原始指针,而不是过早为了方便就用 shared\_ptr和 CComPtr 之类的,不然今天这问题很容易埋下隐患。 ### Beta 阶段 终于问题不多了,(真的吗?)开始 Beta 测试了。 第一个问题是 WPS 返回的 SlideShowWindow 尺寸完全是按照幻灯片来的,4:3 的 PPT 在16:9 的屏幕下放映,返回的是 4:3 的。而 PowerPoint 那边是窗口大小。好不容易想到解决办法了,还记得 WPS 非全屏放映时有个 WPS 的边框吗?没错就是它,又给我一棒。最后改了个标题匹配,仅此而已,如果多个符合,就索性没有 HWND 了毕竟匹配准最重要。cpp 那边这种情况就不设置焦点了。 然后发现 WPS2019 根本就不返回 SlideShowWindow 里面的任何属性(除了View),导致我那个 SlideShowWindow 监测一直说这个不是有效的,就一直失败。刚好获取当前页数就是在 View,改了下检测逻辑。当然这都是故意把 COM 损坏下的极端环境。 然后是 WPS2013 的 Application.Name 返回 Microsoft PowerPoint,笑死我了。导致 HWND 的标题匹配直接失效,但是我想不修了,反正早期的 WPS 用 Activate() 也能让它自己置顶。WPS2007 问题更多,例如可以获取到总页数,但是获取不到当前页,索性不管了。别人 mso2007 都正常的很,连事件都可以正常注册,还是在 Win7 RTM 的环境下。 后面遇到个小概率突然崩的情况,原来是在进入放映的过程中,一瞬间 ActionPresentation 属性会失效,访问就 catch。原来没有是 Interop包 有个等待。于是我加了个重试逻辑,总算解决了。最后我还特地回去测了环境A,完全没问题。 ### 完美阶段 最后,很高兴我终于解决了这个问题!这一切都是值得的,使我对这一技术栈又有了新的理解,并且积累了更加丰富的经验。 有人会问我为啥不用 ai 直接帮我写?当然,期间我尝试使用 Gemini 3 Pro、GPT 5.2、Claude 4.5 分别来帮我找错,肯定是有帮助的,不过感觉很浪费时间,甚至在难题上完全乱说话,每次回答给出的方案都不一样,并且都不能解决问题。所以我认为,现阶段这些ai还是适合给你打打杂,例如写个方法模板,查查文档之类的,编码还得靠自己,就像林大佬说的:“不能让 AI 带着跑,而是带着 AI 跑才能正常开发”。 ## 相关代码 *** 最后,感谢您能阅读到最后! --- --- url: /version/introduction/win7.md --- # Inkeys3 兼容性调整的相关说明 Inkeys3 将会推出全新的 UI 界面与绘图库,使用 D2D1.1 的相关功能。更新的 D2D1.1 可以带来更高的绘图效率和更丰富的绘图效果,但也提高了系统版本的要求。\ 从 Inkeys2 升级到 Inkeys3,兼容性从原来的最低 Windows 7 RTM 调整至 Windows 7 Sp1+。小部分 Windows 7 用户可能在升级后无法启动智绘教,所以我们阻止了这部分用户的自动更新。 *** ::: tip 您的版本是最新的 Inkeys3 LTS 正式版尚未发布,目前最新版本为 Inkeys2 的 `20260214a`。 新动态:Inkeys3 的早期版本已经在 Canary 通道发布!\ ::: ## 系统环境要求 Inkeys3 的最低系统要求是 Windows 7 Sp1+。 * 对于 Windows 8 **及**以上系统版本的用户无需担心,可以直接使用 Inkeys3。 * 对于 Windows 7,则需要 Windows 7 Service Pack 1 和安装 KB2670838 更新。 ### KB2670838 更新是什么 KB2670838 更新增加一些新的系统组件,例如 Inkeys3 所需要的 D2D1.1 的底层组件支持。安装这个更新只是补全系统组件,并不会改动其他内容。\ 有关此更新的[详细内容](https://support.microsoft.com/zh-cn/topic/windows-7-sp1-%E5%92%8C-windows-server-2008-r2-sp1-%E7%9A%84%E5%B9%B3%E5%8F%B0%E6%9B%B4%E6%96%B0-d97da9ca-c15c-b21f-ebb0-838f7be8d9f6)。 需要注意的是:一些电脑可能安装此版本后崩溃(据微软说明),请确认您的硬件是否支持,请先点击**详细内容**查看更新说明。 ::: tip 如何确认系统是否安装了 KB2670838 ? 1. 按下 WIN + R 输入 `powershell` 并按下回车打开 Powershell 2. 输入 `get-hotfix -id KB2670838` 并按下回车 3. 如果看到如下文字,则说明已经安装了 KB2670838 | Source | Description | HotFixID | InstalledBy | InstalledOn | | :- | :- | :- | :- | :- | | <任意值> | Update | **KB2670838** | <任意值> | <任意值> | ::: ### 我是 Windows 7 Sp1 用户该如何安装更新以支持 通过 [下载更新包](https://www.microsoft.com/zh-cn/download/details.aspx?id=36805) 的 msu 文件,打开文件安装即可。 [云盘备份](https://www.123912.com/s/duk9-58EAd) ### 更低版本? 如果没有安装 Windows 7 Service Pack 1,则需要先对系统进行更新。 *** ::: tip 一些杂物 Inkeys3 的相关测试模块构建([#](https://www.123912.com/s/duk9-L8EAd))\ ::: --- --- url: /wiki/guide/basic-guide.md --- # 基础指南 本部分内容将帮助您掌握基本的软件操控方法。(例如如何开始批注以及如何调整批注的画笔颜色和粗细等) ### 打开和收起主栏 当你打开软件主程序时,你会看到一个悬浮窗,点击它即可打开主栏,再次点击即可收起主栏。 ![打开和收起主栏](/wiki/basic-guide/s1-1.gif){ width="50%" } ### 开始批注 点击`画笔`按钮,你会进入到绘制模式,然后你就可以进行批注。再点击一下选择按键即可清空并切换至选择模式。 ![批注](/wiki/basic-guide/s1-2.gif){ width="50%" } ### 使用橡皮擦除墨迹 在绘制模式点击`橡皮`按钮即可进行擦除。 ![橡皮](/wiki/basic-guide/s1-3.gif){ width="50%" } ### 画笔调节、图形和荧光笔 在绘制模式再次点击`画笔`按钮即可调整画笔粗细、颜色等参数。**点击对应的颜色**即可调节,点击旁边的粗细,则可以通过预设粗细或滑动条来调整粗细。 ![画笔调节](/wiki/basic-guide/s1-4.gif){ width="50%" } 软件内置矩形和直线绘图,在再次点击`画笔`按钮时弹出的按钮可以选中并使用。 ![图形](/wiki/basic-guide/s1-5.gif){ width="50%" } 此外,软件自带`荧光笔`,点击对应的按钮即可使用。 ![荧光笔](/wiki/basic-guide/s1-6.gif){ width="50%" } ## 小提示 ### 快速选择颜色 按住绘制图标后上划,可以展开绘制菜单,并**快速选择颜色**。\ ![](/wiki/basic-guide/s2-1.gif){ width="50%" } ### 触发条件收起主栏 可选地,当满足下列条件时,可以自动收起主栏: * 画笔绘制时收起主栏 * 橡皮擦除时收起主栏 * 拖动主栏时收起主栏 * 点击时收起主栏(仅在非选择模式下,点击非主栏区域时生效) ::: tip 提示 相关功能的启用与关闭在 软件选项->常规->其他行为 中设定。 ::: ![](/wiki/basic-guide/s2-2.gif){ width="50%" } *** 还在逐步完善中。\ 更多细分介绍指南,请转到文档进阶指南页面。 --- --- url: /wiki/start/start.md --- # 5 分钟内快速上手 准备好,我们开始了~ *** ## 第一步:下载 智绘教Inkeys 智绘教Inkeys 支持 Windows 7 RTM(sp0) 及以上版本。 ### 下载 1. 选择合适的版本并选择下载 2) 下载完成后会得到一个压缩包。 ![](/wiki/start/3.png){ width="50%" } ### 解压 1. 使用解压软件,将软件解压出来。 ![](/wiki/start/4.png){ width="50%" } 2. 打开解压后的文件夹,即可看到运行文件。 ![](/wiki/start/5.png){ width="50%" } *** CI/CD(自动构建) 包含构建的软件版本,构建时间和构建系统等等。 ![](/wiki/start/6.png){ width="30%" } ## 启动 智绘教Inkeys 双击 `Inkeys.exe` 即可启动程序。 ![](/wiki/start/7.png) 您将看到软件的悬浮窗(在屏幕右下角)。点击后可以展开主栏,那么恭喜您软件安装成功了! ## 转到[基础指南](/wiki/guide/basic-guide)(3 min) --- --- url: /wiki/wiki.md --- # 教程 在这里,教程将帮助你理解 智绘教Inkeys 的使用,亦或是了解并参与开发。 *** 详细的整理文档,可以更好的了解如何使用 智绘教Inkeys。 [基础指南](guide/basic-guide.md)\ [进阶指南(敬请期待)](#) 插件开发攻略等,技术分享也在这里。 [敬请期待](#) *** ::: note 公告 此版块还在持续开发中,敬请期待…… :::