编码
Universal Ink Model被序列化为Protocol Buffers v3 message,包含在RIFF container.中 下面的章节描述了容器和protobuf序列化方案。
RIFF Container
Universal Ink Model (UIM)被序列化为RIFF container,包含在@@@中RIFF chunk UIM3. 该数据块包含两个子数据块,分别是HEAD和DATA。 HEAD数据块包含最新版的规范。 该版本使用3字节编码,定义如下:[major-version]-[minor-version]-[patch-version]。
如第8.2节“Protocol Buffers序列化方案”中所述,墨水模型被序列化为Protocol Buffers消息,保存在DATA数据块中。
图1:RIFF 图
Ink Tree
墨水树以一般节点结构构建。
构建树时,depth
属性反映树的深度。
对于树结构的序列化,采用深度优先预排序树序列化,如图3所示。
每个节点都有一个唯一标识符id
,它与语义语句有关,作为主语的标识符。
index
属性关联着路径或传感器数据索引。
groupBoundingBox
是可选项,提供视觉辅助,以方便调试,或高亮显示包含可单击选项的相关区域。
仅当节点的type
为CHUNK
时,属性chunkFromIndex
和chunkToIndex
才会与子索引有关。
图2:深度优先树顺序(红色):F、B、A、D、C、E、G、I、H。
数据压缩
编码
编码过程如下:
**第1步:(可选)**使用外部指定的小数精度将浮点值转换为整数值:
integerValue = floatValue * (10 ^ decimalPrecision);
Note: 第1步仅适用于不是整数的数据类型(例如,@@@UINT32, UINT64, INT32, or INT64).
**第2步:**对转换值执行增量(Delta)编码:
encodedValues[0] = integerValues[0];
for(i = 1; i < n; i++)
{
encodedValues[i] = integerValues[i] - integerValues[i - 1];
}
**注意:在浮点值和定点(整数)值之间转换时,可能会有精度损失。
如果精度对应用功能极为关键,必须予以考虑。
一个可行的解决方案是通过IEEE 754:执行转换,这种情况下,对于每个被转换的值,都应使用合适的decimalPrecision
以及一个在转换过程中保持不变的近似值。
Decoding
要恢复原始值,可按照下面的方法逆转编码过程:
**第1步:**执行增量(Delta)编码,恢复整数值:
integerValues[0] = encodedValues[0];
for(i = 1; i < n; i++)
{
integerValues[i] = integerValues[i - 1] + encodedValues[i];
}
第2步:(可选) Convert integer values to floating-point values using externally-specified decimal precision:
floatValue = integerValue / (10 ^ decimalPrecision)
***注意:***第2步仅适用于不是整数的数据类型。
Protobuf序列化方案
BrushPrototype
刷子的多边形原型定义。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
coordX | float | 重复 | 刷子原型的x坐标列表。 |
coordY | float | 重复 | 刷子原型的y坐标列表。 |
coordZ | float | 重复 | 刷子原型的z坐标列表[用于3D渲染]。 |
indices | uint32 | 重复 | 刷子原型的索引列表[用于3D渲染]。 |
shapeURI | string | 可选 | 唯一标识形状多边形的URI。 |
size | float | 可选 | 定义路径点的原型大小。 |
Brushes
用于墨水光栅化所需的刷子描述。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
vectorBrushes | VectorBrush | 重复 | 已定义的矢量刷子列表。 |
rasterBrushes | RasterBrush | 重复 | 已定义的光栅刷子列表。 |
ChannelData
数据项列表。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
sensorChannelID | string | 可选 | 通过ID引用墨水传感器通道。 |
values | sint32 | 重复 | 使用提供的精度增量编码的样本值。 |
Environment
环境 定义了关于输入环境的所有细节:
- 操作系统:名称、版本等。
- 应用程序:名称、版本等。
- 地理信息:GPS坐标。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希生成的MD5哈希值,符合MD5哈希值唯一标识符生成方案。 |
properties | Property | 重复 | 环境属性,例如操作系统名称、操作系统版本等。 |
Float32
浮点值的包装器,用于避免跨平台零值问题。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
value | float | 可选 | 消息内部包装的浮点值。 |
InkData
包含所有墨水数据。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
strokes | Stroke | 重复 | 用于存储笔画的数据容器。 |
InkInputProvider
输入提供程序类型的定义。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希值生成,符合MD5哈希值唯一标识符生成方案。 |
类型 | InkInputProviderType | 可选 | 使用的硬件类型 - PEN、TOUCH、MOUSE、或控制器。 |
properties | Property | 重复 | InkInputProvider 属性,如 PenID。 |
InkObject
墨水对象作为捕获所有相关数据的基本结构。
- 从输入传感器记录的传感器数据
- 定义所使用的不同刷子类型的刷子配置
- 具有墨水笔 画视觉几何的墨水数据
- 用于结构化墨水数据的墨水树
- 描述作者、文档等的元数据
- 具有语义的知识图
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
inputData | InputData | 可选 | 与墨水输入相关数据的数据容器。 |
inkData | InkData | 可选 | 与墨水相关的墨水数据的数据容器。 |
刷子 | Brushes | 可选 | 光栅化工具。 |
inkTree | Node | 重复 | 墨水树:这是以墨水为中心的数据模型。 |
视图 | View | 重复 | 基于知识图的墨水树的视图列表。 |
knowledgeGraph | TripleStore | 可选 | 知识图。 |
变换 | Matrix4 | 可选 | 变换是应用于所有路径的仿射变换矩阵。 |
properties | Property | 重复 | 文档相关的属性,如 DOCUMENT、AUTHOR、LAST_MODIFIED等。 |
InputContext
捕获墨水设备的上下文,参考环境和 SensorContext。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希值生成,符合MD5哈希值唯一标识符生成方案。 |
environmentID | string | 可选 | 参考环境。 |
sensorContextID | string | 可选 | 参考 SensorContext。 |
InputContextData
上下文和输入定义的容器结构。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
inputContexts | InputContext | 重复 | 输入上下文的列表。 |
inkInputProviders | InkInputProvider | 重复 | 输入提供程序的列表。 |
inputDevices | InputDevice | 重复 | 输入设备的列表。 |
environments | Environment | 重复 | 环境设置的列表。 |
sensorContexts | SensorContext | 重复 | 传感器上下文的列表。 |
InputData
InputData捆绑输入。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
inputContextData | InputContextData | 可选 | 输入上下文数据。 |
sensorData | SensorData | 重复 | 传感器数据的数据容器。 |
InputDevice
InputDevice 与其属性。
属性可以包括:
- 通信协议: USB、BTC、BLE、SPP、WIFI
- 通信ID:VID、PID;MAC;UID;COM_PORT
- 设备名称: Wacom Intuos Pro M、Apple iPad 8、Samsung GalaxyTab 10
- 序列号
- 固件版本(MCU)
- 次要固件版本 (BT、WIFI)-不同模块提供其自身的版本
- 方向: PORTRAIT、LANDSCAPE、PORTRAIT_REVERSE、LANDSCAPE_REVERSE 或 0、90、180、270
- 传感器尺寸
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希值生成,符合MD5哈希值唯一标识符生成方案。 |
properties | Property | 重复 | InputDevice 属性。 |
Matrix4
4x4仿射矩阵的表示
| m00 m01 m02 m03 | | m10 m11 m12 m13 | | m20 m21 m22 m23 | | m30 m31 m32 m33 |
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
m00 | float | 可选 | |
m01 | float | 可选 | |
m02 | float | 可选 | |
m03 | float | 可选 | |
m10 | float | 可选 | |
m11 | float | 可选 | |
m12 | float | 可选 | |
m13 | float | 可选 | |
m20 | float | 可选 | |
m21 | float | 可选 | |
m22 | float | 可选 | |
m23 | float | 可选 | |
m30 | float | 可选 | |
m31 | float | 可选 | |
m32 | float | 可选 | |
m33 | float | 可选 |
Node
用于定义树结构的节点消息。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 节点唯一标识符 |
depth | uint32 | 可选 | 在层次结构中的深度 |
index | uint32 | 可选 | 在InkData.paths 或 InkData.sensorData 数据持有者中的索引 |
Type | NodeType | 可选 | (路径和传感器数据节点仅限)节点类型 |
groupBoundingBox | Rectangle | 可选 | 边界框(仅适用于组节点) |
chunkFromIndex | uint32 | 可选 | 块的开始位置(仅限CHUNK节点) |
chunkToIndex | uint32 | 可选 | 块的结束位置(仅限CHUNK节点) |
PathPointProperties
不变的管道属性。变量属性通过Stroke消息进行序列化。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
size | Float32 | 可选 | 笔刷大小 |
red | Float32 | 可选 | 红色通道的颜色值[0, 1] |
green | Float32 | 可选 | 绿色通道的颜色值[0, 1] |
blue | Float32 | 可选 | 蓝色通道的颜色值[0, 1] |
alpha | Float32 | 可选 | alpha通道的颜色值[0, 1] |
rotation | Float32 | 可选 | 笔刷的z轴旋转 |
scaleX | Float32 | 可选 | 笔刷的x轴缩放 |
scaleY | Float32 | 可选 | 笔刷的y轴缩放 |
scaleZ | Float32 | 可选 | 笔刷的z轴缩放[用于3D渲染] |
offsetX | Float32 | 可选 | 笔刷的x轴偏移 |
offsetY | Float32 | 可选 | 笔刷的y轴偏移 |
offsetZ | Float32 | 可选 | 笔刷的z轴偏移[用于3D渲染] |
Property
编码单个属性
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
name | string | 可选 | 属性的名称 |
value | string | 可选 | 属性的值 |
RasterBrush
使用光栅图像定义的笔刷
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
name | string | 可选 | 笔刷描述符。 |
spacing | float | 可选 | 相邻粒子之间的距离。 |
scattering | float | 可选 | 沿曲线法线的散射。 |
rotationMode | RotationMode | 可选 | 笔刷的粒子旋转模式。 |
shapeTexture | bytes | 重复 | 包含形状纹理的PNG图像列表。 |
shapeTextureURI | string | 重复 | 与形状纹理关联的URI列表。 |
fillTexture | bytes | 可选 | 包含填充纹理的PNG图像列表。 |
fillTextureURI | string | 可选 | 标识填充纹理的URI。 |
fillWidth | float | 可选 | 填充瓦片的宽度。 |
fillHeight | float | 可选 | 填充瓦片的高度。 |
randomizeFill | bool | 可选 | 指定填充纹理是否随机位移。 |
blendMode | BlendMode | 可选 | 应用的混合模式。 |
Rectangle
矩形的表示形式
字段 | 标签 | 描述 |
---|---|---|
x | float | 可选 |
y | float | 可选 |
width | float | 可选 |
height | float | 可选 |
SemanticTriple
语义三元组,或简称三元组,是原子数据实体数据模型。顾名思义,三元组是一组三个实体,以主谓宾表达式的形式编码了关于语义数据的陈述。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
subject | string | 可选 | |
predicate | string | 可选 | |
object | string | 可选 |
SensorChannel
关于传感器通道的信息。
支持的通道类型:
- will:///input/3.0/channel/X
- will:///input/3.0/channel/Y
- will:///input/3.0/channel/Z
- will:///input/3.0/channel/Timestamp
- will:///input/3.0/channel/Pressure
- will:///input/3.0/channel/RadiusX
- will:///input/3.0/channel/RadiusY
- will:///input/3.0/channel/Altitude
- will:///input/3.0/channel/Azimuth
- will:///input/3.0/channel/Rotation
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希基于MD5哈希的唯一标识符生成方案。 |
Type | string | 可选 | 描述此通道的唯一URI。支持的类型有: |
metric | InkSensorMetricType | 可选 | 用户定义的通道应该从用户方提供自定义含义。指示用于计算数据项分辨率的度量。 |
resolution | double | 可选 | 是一个十进制数,给出数据项增量的数量。 |
min | float | 可选 | 每个物理单位。例如,如果物理单位是米和设备单位。/ 分辨率为100000,那么值150将为0.0015米。通道的最小值。 |
max | float | 可选 | 通道的最大值。 |
precision | uint32 | 可选 | 整数编码的精度,用于编码的浮点值。 |
SensorChannelsContext
传感器通道上下文 SensorChannelsContext 将产生相同采样率的数据的传感器通道分组。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希基于MD5哈希的唯一标识符生成方案。 |
channels | SensorChannel | 重复 | 此组中的通道提供相同时间的对齐值。 |
samplingRateHint | Uint32 | 可选 | 通道的预期采样率的提示[可选]。 |
latency | Uint32 | 可选 | 毫秒为单位的延迟测量[可选]。 |
inkInputProviderID | string | 可选 | 对InkInputProvider的引用。 |
inputDeviceID | string | 可选 | 对InputDevice的引用。 |
SensorContext
每个输入设备都有一个SensorContext描述设备的可用传感器。 一个文件可以包含来自两个相同类型设备的Ink数据,它们共享一个上下文。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 根据MD5哈希基于MD5哈希的唯一标识符生成方案。 |
sensorChannelsContext | SensorChannelsContext | 重复 | 用于设备传感器通道的分组上下文。 |
SensorData
SensorData 是用于存储来自墨水传感器的原始数据的核心数据结构。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | |
inputContextID | string | 可选 | 通过id引用InputContext。 |
state | InkState | 可选 | 墨水的状态。 |
timestamp | uint64 | 可选 | 笔画的第一个样本的时间戳,以毫秒为单位测量。 |
dataChannels | ChannelData | 重复 | (第一次报告X和Y时的时间)。编码数据列表的数据通道。 |
Stroke
可视路径结构。 Stroke 最简单的形式包含一个或多个 Segments(Catmull-Rom),其中包括一系列位置点,Positions。 除了这些属性之外,数字墨水笔画还包括起始参数和结束参数作为Stroke实体的属性。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
id | string | 可选 | 内部ID。 |
startParameter | float | 可选 | 样条起始参数[0, 1]。 |
endParameter | float | 可选 | 样条结束参数[0, 1]。 |
splineX | float | 重复 | X轴的样条值。 |
splineY | float | 重复 | Y轴的样条值。 |
splineZ | float | 重复 | Z轴的样条值[用于3D渲染]。 |
red | float | 重复 | 红色通道的颜色值[0, 1]。 |
green | float | 重复 | 绿色通道的颜色值[0, 1]。 |
blue | float | 重复 | 蓝色通道的颜色值[0, 1]。 |
alpha | float | 重复 | Alpha通道的颜色值[0, 1]。 |
size | float | 重复 | 笔刷大小。 |
rotation | float | 重复 | 笔刷旋转z轴。 |
scaleX | float | 重复 | 笔刷缩放x轴。 |
scaleY | float | 重复 | 笔刷缩放y轴。 |
scaleZ | float | 重复 | 笔刷缩放z轴[用于3D渲染]。 |
offsetX | float | 重复 | 笔刷偏移x轴。 |
offsetY | float | 重复 | 笔刷偏移y轴。 |
offsetZ | float | 重复 | 笔刷偏移z轴[用于3D渲染]。 |
sensorDataOffset | uint32 | 可选 | 原始路径和处理后路径之间映射点的索引。 |
sensorDataID | string | 可选 | 引用传感器数据。 |
sensorDataMapping | uint32 | 重复 | Stroke和SensorData索引之间的显式映射,当输入速率非常高且提供了不需要的点时使用。 |
style | Style | 可选 | 应用于路径的样式。 |
Style
用于Stroke 自定义的样式消息。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
properties | PathPointProperties | 可选 | 不针对每个路径点存在的属性的静态值 |
brushURI | string | 可选 | 用于笔画光栅化的笔刷的引用。 |
particlesRandomSeed | uint32 | 可选 | 粒子随机种子,用于粒子笔触。 |
renderModeURI | string | 可选 | 定义笔画可视化的附加信息,例如 ERASER。 |
TripleStore
封装了TripleGroups 的列表。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
statements | SemanticTriple | 重复 | 语义三元组的列表。 |
Uint32
无符号整数值的包装器,用于避免跨平台零值问题。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
value | uint32 | 可选 | 包装在消息中的无符号整数值。 |
VectorBrush
使用多边形(三维情况下为多面体)定义的笔刷。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
name | string | 可选 | 笔刷描述符。 |
prototype | BrushPrototype | 重复 | 笔刷的多边形原型。 |
spacing | float | 可选 | 间距值。 |
View
一个表示墨水树视图的消息,以另一个树的形式进行序列化。
字段 | 类型 | 标签 | 描述 |
---|---|---|---|
name | string | 可选 | 视图描述符URI(在模型范围内唯一)。 |
tree | Node | 重复 | 当前视图的树结构。 |
BlendMode
混合模式枚举列出了可以应用于光栅笔刷的不同混合模式。
名称 | 数字 | 描述 |
---|---|---|
SOURCE_OVER | 0 | 这是默认设置,将新形状绘制在现有画布内容之上。也称为 NORMAL。 |
DESTINATION_OVER | 1 | 新形状绘制在现有画布内容的后面。也称为 NORMAL_REVERSE。 |
DESTINATION_OUT | 2 | 现有内容被保留在不重叠新形状的地方。也称为 ERASE。 |
LIGHTER | 3 | 在两个形状重叠的地方,颜色通过添加颜色值来确定。也称为 ADD。 |
COPY | 4 | 仅显示新形状。也称为 NONE。 |
MIN | 5 | 结果是两种颜色的最小值。结果是较暗的颜色。 |
MAX | 6 | 结果是两种颜色的最大值。结果是较亮的颜色。 |
InkInputProviderType
定义不同输入类型。
名称 | 数字 | 描述 |
---|---|---|
PEN | 0 | 触控笔、智能笔、笔式显示器、签字捕获设备等。 |
TOUCH | 1 | 触控器输入:手指或被动触控笔。 |
MOUSE | 2 | 鼠标设备。 |
CONTROLLER | 3 | 3DOF或6DOF输入设备。 |
InkSensorMetricType
支持的度量类型。
名称 | 数字 | 描述 |
---|---|---|
LENGTH | 0 | 底层SI单位为米。 |
TIME | 1 | 底层SI单位为秒。 |
FORCE | 2 | 底层SI单位为牛顿。 |
ANGLE | 3 | 底层SI单位为弧度。 |
NORMALIZED | 4 | 百分比,作为相对于最大-最小值的分数(1.0 = 100%)。 |
LOGICAL | 5 | 逻辑值,真/假值。 |
DIMENSIONLESS | 6 | 传感器未定义度量。 |
InkState
墨水设备状态定义了墨水设备的状态。WILL 3.0 支持不同的模式:
- 在平面上书写
- 在表面上悬停
- 在空中移动(VR/AR/MR 交互)
- 仅在空中悬停
名称 | 数字 | 描述 |
---|---|---|
PLANE | 0 | 墨水设备正在平面上书写。 |
HOVERING | 1 | 在表面上悬停。 |
IN_VOLUME | 2 | 在空中使用墨水设备,进行主动书写。 |
VOLUME_HOVERING | 3 | 在空中移动笔,停用书写功能。 |
NodeType
定义了节点类型。
名称 | 数字 | 描述 |
---|---|---|
PATH_GROUP | 0 | PATH_GROUP 是按层次组合笔画节点。 |
SENSOR_DATA_GROUP | 1 | SENSOR_DATA_GROUP 是按层次组合传感器数据节点。 |
PATH | 2 | PATH 是一个节点类型,其中的节点直接指向笔画。 |
SENSOR_DATA | 3 | SENSOR_DATA 是一个节点类型,其中的节点直接指向传感器数据样本序列。 |
RotationMode
旋转参数指定了粒子的旋转。
名称 | 数字 | 描述 |
---|---|---|
NONE | 0 | 表示形状不会旋转。 |
RANDOM | 1 | 表示形状在渲染之前将随机旋转。 |
TRAJECTORY | 2 | 表示形状将旋转以匹配路径轨迹。 |
标量数值类型
.proto 类型 | 注释 | C++ 类型 | Java 类型 | Python 类型 |
---|---|---|---|---|
double | double | double | float | |
float | float | float | float | |
int32 | 使用可变长度编码。对于编码负数效率低 - 如果字段可能有负值,请改用 sint32。 | int32 | int | int |
int64 | 使用可变长度编码。对于编码负数效率低 - 如果字段可能有负值,请改用 sint64。 | int64 | long | int/long |
uint32 | 使用可变长度编码。 | uint32 | int | int/long |
uint64 | 使用可变长度编码。 | uint64 | long | int/long |
sint32 | 使用可变长度编码。带符号整数值。与普通 int32 相比,这些编码负数的效率更高。 | int32 | int | int |
sint64 | 使用可变长度编码。带符号整数值。与普通 int64 相比,这些编码负数的效率更高。 | int64 | long | int/long |
fixed32 | 总是四个字节。如果值通常大于 2^28,则比 uint32 更高效。 | uint32 | int | int |
fixed64 | 总是八个字节。如果值通常大于 2^56,则比 uint64 更高效。 | uint64 | long | int/long |
sfixed32 | 总是四个字节。 | int32 | int | int |
sfixed64 | 总是八个字节。 | int64 | long | int/long |
bool | bool | boolean | boolean | |
string | 字符串必须始终包含 UTF-8 编码或 7 位 ASCII 文本。 | string | String | str/unicode |
bytes | 可能包含任意字节序列。 | string | ByteString | str |