@veltra/desktop 1.7.12 → 1.7.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/batch-edit/batch-edit-form.js +9 -3
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +2 -1
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +57 -30
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/helper.d.ts +1 -2
- package/dist/components/batch-edit/style.d.ts +1 -0
- package/dist/components/batch-edit/style.js +1 -0
- package/dist/components/batch-edit/style2.css +14 -0
- package/dist/components/batch-edit/use-dialog-effect.js +20 -0
- package/dist/components/batch-edit/use-dialog-effect.js.map +1 -0
- package/dist/components/batch-edit/use-edit-state.js +22 -3
- package/dist/components/batch-edit/use-edit-state.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js +5 -0
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/components/batch-edit/use-shortcut-key.js +5 -2
- package/dist/components/batch-edit/use-shortcut-key.js.map +1 -1
- package/dist/components/condition-editor/core/evaluator.d.ts +4 -5
- package/dist/components/contextmenu/api.d.ts +1 -2
- package/dist/components/contextmenu/di.d.ts +2 -3
- package/dist/components/file-viewer/file-viewer.js +21 -14
- package/dist/components/file-viewer/file-viewer.js.map +1 -1
- package/dist/components/file-viewer/helper.js +2 -0
- package/dist/components/file-viewer/helper.js.map +1 -1
- package/dist/components/file-viewer/previewers/ofd-previewer.js +196 -0
- package/dist/components/file-viewer/previewers/ofd-previewer.js.map +1 -0
- package/dist/components/file-viewer/style2.css +27 -0
- package/dist/components/loading/directive.d.ts +1 -2
- package/dist/components/message/message.d.ts +1 -2
- package/dist/components/message-confirm/message-confirm.d.ts +1 -2
- package/dist/components/notification/notification.d.ts +1 -2
- package/dist/components/table/node/col.js +19 -0
- package/dist/components/table/node/col.js.map +1 -1
- package/dist/components/table/table-cell.js +2 -0
- package/dist/components/table/table-cell.js.map +1 -1
- package/dist/components/table/table-foot.js +2 -0
- package/dist/components/table/table-foot.js.map +1 -1
- package/dist/components/table/table-head.js +1 -0
- package/dist/components/table/table-head.js.map +1 -1
- package/dist/components/table/table-row.js +2 -0
- package/dist/components/table/table-row.js.map +1 -1
- package/dist/components/table/use-columns.d.ts +1 -2
- package/dist/components/table-editor/style2.css +23 -3
- package/dist/components/table-editor/table-editor.js +213 -63
- package/dist/components/table-editor/table-editor.js.map +1 -1
- package/dist/components/tip/style2.css +63 -0
- package/dist/components/tip/tip.js +6 -1
- package/dist/components/tip/tip.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/install.d.ts +3 -3
- package/dist/packages/ofd-core/dist/color.js +69 -0
- package/dist/packages/ofd-core/dist/color.js.map +1 -0
- package/dist/packages/ofd-core/dist/ctm.js +55 -0
- package/dist/packages/ofd-core/dist/ctm.js.map +1 -0
- package/dist/packages/ofd-core/dist/error.js +14 -0
- package/dist/packages/ofd-core/dist/error.js.map +1 -0
- package/dist/packages/ofd-core/dist/font.js +384 -0
- package/dist/packages/ofd-core/dist/font.js.map +1 -0
- package/dist/packages/ofd-core/dist/index.js +6 -0
- package/dist/packages/ofd-core/dist/number.js +13 -0
- package/dist/packages/ofd-core/dist/number.js.map +1 -0
- package/dist/packages/ofd-core/dist/page-objects.js +181 -0
- package/dist/packages/ofd-core/dist/page-objects.js.map +1 -0
- package/dist/packages/ofd-core/dist/parse.js +65 -0
- package/dist/packages/ofd-core/dist/parse.js.map +1 -0
- package/dist/packages/ofd-core/dist/render.js +361 -0
- package/dist/packages/ofd-core/dist/render.js.map +1 -0
- package/dist/packages/ofd-core/dist/xml.js +199 -0
- package/dist/packages/ofd-core/dist/xml.js.map +1 -0
- package/dist/packages/ofd-core/dist/zip.js +93 -0
- package/dist/packages/ofd-core/dist/zip.js.map +1 -0
- package/dist/style.d.ts +1 -1
- package/dist/style.js +1 -1
- package/dist/types/action.d.ts +7 -8
- package/dist/types/animation.d.ts +4 -5
- package/dist/types/auto-complete.d.ts +4 -5
- package/dist/types/badge.d.ts +4 -5
- package/dist/types/batch-edit.d.ts +15 -10
- package/dist/types/breadcrumb.d.ts +6 -7
- package/dist/types/button.d.ts +5 -6
- package/dist/types/calendar.d.ts +7 -8
- package/dist/types/card.d.ts +7 -8
- package/dist/types/cascade.d.ts +6 -7
- package/dist/types/check-tag.d.ts +4 -5
- package/dist/types/checkbox-group.d.ts +3 -4
- package/dist/types/checkbox.d.ts +5 -6
- package/dist/types/code-editor.d.ts +5 -6
- package/dist/types/collapse.d.ts +6 -7
- package/dist/types/condition-editor.d.ts +11 -12
- package/dist/types/contextmenu.d.ts +5 -6
- package/dist/types/css-transition.d.ts +4 -5
- package/dist/types/date-panel.d.ts +3 -4
- package/dist/types/date-picker.d.ts +5 -6
- package/dist/types/date-range-picker.d.ts +6 -7
- package/dist/types/dialog.d.ts +5 -6
- package/dist/types/drawer.d.ts +6 -7
- package/dist/types/dropdown.d.ts +4 -5
- package/dist/types/dual-nav.d.ts +6 -7
- package/dist/types/empty.d.ts +4 -5
- package/dist/types/expression-editor.d.ts +6 -7
- package/dist/types/file-picker.d.ts +4 -5
- package/dist/types/file-viewer.d.ts +6 -7
- package/dist/types/float-button.d.ts +5 -6
- package/dist/types/form-item.d.ts +3 -4
- package/dist/types/form.d.ts +4 -5
- package/dist/types/gantt-chart.d.ts +4 -5
- package/dist/types/grid-input.d.ts +4 -5
- package/dist/types/grid.d.ts +7 -8
- package/dist/types/group-input.d.ts +4 -5
- package/dist/types/group-nav.d.ts +3 -4
- package/dist/types/icon.d.ts +3 -4
- package/dist/types/image-cropper.d.ts +9 -10
- package/dist/types/index.d.ts +4 -4
- package/dist/types/input.d.ts +4 -5
- package/dist/types/layout.d.ts +4 -5
- package/dist/types/list.d.ts +4 -5
- package/dist/types/loading.d.ts +5 -6
- package/dist/types/message-confirm.d.ts +8 -9
- package/dist/types/message.d.ts +8 -9
- package/dist/types/multi-auto-complete.d.ts +4 -5
- package/dist/types/multi-select.d.ts +4 -5
- package/dist/types/multi-tree-select.d.ts +4 -5
- package/dist/types/nav.d.ts +5 -6
- package/dist/types/node-render.d.ts +2 -3
- package/dist/types/notification.d.ts +8 -9
- package/dist/types/number-input.d.ts +3 -4
- package/dist/types/number-range-input.d.ts +4 -5
- package/dist/types/number.d.ts +3 -4
- package/dist/types/paginator.d.ts +4 -5
- package/dist/types/palette.d.ts +7 -8
- package/dist/types/password-input.d.ts +4 -5
- package/dist/types/pop-confirm.d.ts +4 -5
- package/dist/types/pop.d.ts +4 -5
- package/dist/types/progress-nodes.d.ts +4 -5
- package/dist/types/progress.d.ts +4 -5
- package/dist/types/quick-batch-edit.d.ts +4 -5
- package/dist/types/radio-group.d.ts +4 -5
- package/dist/types/radio.d.ts +4 -5
- package/dist/types/rich-text-editor.d.ts +6 -7
- package/dist/types/scroll.d.ts +5 -6
- package/dist/types/segment.d.ts +5 -6
- package/dist/types/select.d.ts +4 -5
- package/dist/types/slider.d.ts +4 -5
- package/dist/types/steps.d.ts +5 -6
- package/dist/types/switch.d.ts +4 -5
- package/dist/types/table-editor.d.ts +30 -10
- package/dist/types/table.d.ts +23 -13
- package/dist/types/tabs.d.ts +13 -14
- package/dist/types/tag.d.ts +3 -4
- package/dist/types/text-editor.d.ts +5 -6
- package/dist/types/text.d.ts +4 -5
- package/dist/types/textarea.d.ts +4 -5
- package/dist/types/theme.d.ts +3 -4
- package/dist/types/tip.d.ts +11 -8
- package/dist/types/tree-select.d.ts +4 -5
- package/dist/types/tree.d.ts +6 -6
- package/dist/types/watermark.d.ts +4 -5
- package/package.json +8 -7
- package/src/components/batch-edit/__test__/batch-edit.test.ts +191 -4
- package/src/components/batch-edit/batch-edit-form.vue +17 -3
- package/src/components/batch-edit/batch-edit-list.vue +2 -1
- package/src/components/batch-edit/batch-edit.vue +22 -4
- package/src/components/batch-edit/style.scss +20 -0
- package/src/components/batch-edit/style.ts +1 -0
- package/src/components/batch-edit/use-dialog-effect.ts +9 -3
- package/src/components/batch-edit/use-edit-state.ts +32 -4
- package/src/components/batch-edit/use-handlers.ts +10 -0
- package/src/components/batch-edit/use-shortcut-key.ts +6 -2
- package/src/components/file-viewer/__test__/helper.test.ts +13 -0
- package/src/components/file-viewer/file-viewer.vue +23 -16
- package/src/components/file-viewer/helper.ts +2 -0
- package/src/components/file-viewer/previewers/ofd-previewer.vue +216 -0
- package/src/components/file-viewer/style.scss +33 -0
- package/src/components/table/__test__/column-style.test.ts +67 -0
- package/src/components/table/node/col.ts +30 -1
- package/src/components/table/table-cell.vue +7 -2
- package/src/components/table/table-foot.vue +2 -0
- package/src/components/table/table-head.tsx +1 -0
- package/src/components/table/table-row.tsx +2 -0
- package/src/components/table-editor/__test__/table-editor.test.ts +471 -0
- package/src/components/table-editor/style.scss +42 -4
- package/src/components/table-editor/table-editor.vue +265 -38
- package/src/components/tip/style.scss +15 -0
- package/src/components/tip/tip.vue +1 -1
- package/src/types/batch-edit.ts +6 -0
- package/src/types/file-viewer.ts +1 -1
- package/src/types/table-editor.ts +29 -7
- package/src/types/table.ts +12 -0
- package/src/types/tip.ts +6 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { OfdParseError } from "./error.js";
|
|
2
|
+
import { formatNumber } from "./number.js";
|
|
3
|
+
//#region ../ofd-core/dist/font.js
|
|
4
|
+
/**
|
|
5
|
+
* 内嵌 TTF 字体解析与 glyph 轮廓输出(OFD Font@FontFile 声明的内嵌字体)。
|
|
6
|
+
*
|
|
7
|
+
* 读取 TrueType 的 head/maxp/cmap/loca/glyf/hhea/hmtx 表:cmap 把字符码点映射到
|
|
8
|
+
* glyph id(可省,省略时字符映射由渲染层 CGTransform 字形序号提供),glyf 提取
|
|
9
|
+
* 轮廓点(on/off curve,复合 glyph 递归展开并平移/缩放)。
|
|
10
|
+
* 二次贝塞尔轮廓按 unitsPerEm → 字号缩放、基线定位并翻转 y 轴后转成 SVG path
|
|
11
|
+
* `d`。二进制结构非法时抛 OfdParseError('invalid-font')。
|
|
12
|
+
*/
|
|
13
|
+
/** 解析 TTF 二进制:结构非法抛 OfdParseError('invalid-font') */
|
|
14
|
+
function parseEmbeddedFont(data, source) {
|
|
15
|
+
if (data.length < 12) throw new OfdParseError("invalid-font", `字体 ${source} 数据太短,不是 TTF 文件`);
|
|
16
|
+
const tables = parseTableDirectory(data, source);
|
|
17
|
+
for (const tag of REQUIRED_TABLES) {
|
|
18
|
+
const table = tables.get(tag);
|
|
19
|
+
if (!table) throw new OfdParseError("invalid-font", `字体 ${source} 缺少 ${tag} 表`);
|
|
20
|
+
if (table.offset + table.length > data.length) throw new OfdParseError("invalid-font", `字体 ${source} 的 ${tag} 表越界,数据被截断`);
|
|
21
|
+
}
|
|
22
|
+
const headOffset = tables.get("head").offset;
|
|
23
|
+
const unitsPerEm = new FontReader(data, source, headOffset + 18).u16();
|
|
24
|
+
if (unitsPerEm === 0) throw new OfdParseError("invalid-font", `字体 ${source} 的 unitsPerEm 为 0`);
|
|
25
|
+
const indexToLocFormat = new FontReader(data, source, headOffset + 50).i16();
|
|
26
|
+
if (indexToLocFormat !== 0 && indexToLocFormat !== 1) throw new OfdParseError("invalid-font", `字体 ${source} 的 indexToLocFormat 不合法:${indexToLocFormat}`);
|
|
27
|
+
const numGlyphs = new FontReader(data, source, tables.get("maxp").offset + 4).u16();
|
|
28
|
+
const cmapTable = tables.get("cmap");
|
|
29
|
+
const cmap = cmapTable ? parseCmap(data, cmapTable, source) : /* @__PURE__ */ new Map();
|
|
30
|
+
const glyfTable = tables.get("glyf");
|
|
31
|
+
const locaView = new FontReader(data, source, tables.get("loca").offset);
|
|
32
|
+
const loca = [];
|
|
33
|
+
for (let i = 0; i <= numGlyphs; i++) loca.push(indexToLocFormat === 0 ? locaView.u16() * 2 : locaView.u32());
|
|
34
|
+
for (let i = 0; i < numGlyphs; i++) if (loca[i + 1] < loca[i] || loca[i + 1] > glyfTable.length) throw new OfdParseError("invalid-font", `字体 ${source} 的 loca 表越界`);
|
|
35
|
+
const numberOfHMetrics = Math.min(new FontReader(data, source, tables.get("hhea").offset + 34).u16(), numGlyphs);
|
|
36
|
+
const hmtxView = new FontReader(data, source, tables.get("hmtx").offset);
|
|
37
|
+
const advances = [];
|
|
38
|
+
for (let i = 0; i < numberOfHMetrics; i++) {
|
|
39
|
+
advances.push(hmtxView.u16());
|
|
40
|
+
hmtxView.i16();
|
|
41
|
+
}
|
|
42
|
+
const glyf = data.subarray(glyfTable.offset, glyfTable.offset + glyfTable.length);
|
|
43
|
+
const outlineCache = /* @__PURE__ */ new Map();
|
|
44
|
+
return {
|
|
45
|
+
unitsPerEm,
|
|
46
|
+
numGlyphs,
|
|
47
|
+
glyphIndexOf: (codePoint) => cmap.get(codePoint) ?? null,
|
|
48
|
+
advanceWidth: (gid) => advances[Math.min(Math.max(gid, 0), advances.length - 1)] ?? 0,
|
|
49
|
+
glyphOutline: (gid) => {
|
|
50
|
+
const cached = outlineCache.get(gid);
|
|
51
|
+
if (cached) return cached;
|
|
52
|
+
const outline = readGlyphOutline(glyf, gid, /* @__PURE__ */ new Set([gid]), numGlyphs, loca, source);
|
|
53
|
+
outlineCache.set(gid, outline);
|
|
54
|
+
return outline;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* glyph 轮廓转 SVG path `d`:unitsPerEm → 字号缩放,基线原点定位并翻转
|
|
60
|
+
* y 轴(字体坐标向上,SVG 向下)。无轮廓返回空串。
|
|
61
|
+
*/
|
|
62
|
+
function glyphPathD(font, gid, fontSize, originX, originY) {
|
|
63
|
+
if (!(fontSize > 0)) return "";
|
|
64
|
+
const scale = fontSize / font.unitsPerEm;
|
|
65
|
+
return font.glyphOutline(gid).map((contour) => contourPathD(contour, scale, originX, originY)).filter((d) => d !== "").join(" ");
|
|
66
|
+
}
|
|
67
|
+
const REQUIRED_TABLES = [
|
|
68
|
+
"glyf",
|
|
69
|
+
"head",
|
|
70
|
+
"hhea",
|
|
71
|
+
"hmtx",
|
|
72
|
+
"loca",
|
|
73
|
+
"maxp"
|
|
74
|
+
];
|
|
75
|
+
/** 带越界检查的大端读取器:越界抛 invalid-font */
|
|
76
|
+
var FontReader = class {
|
|
77
|
+
data;
|
|
78
|
+
source;
|
|
79
|
+
offset;
|
|
80
|
+
constructor(data, source, offset = 0) {
|
|
81
|
+
this.data = data;
|
|
82
|
+
this.source = source;
|
|
83
|
+
this.offset = offset;
|
|
84
|
+
}
|
|
85
|
+
seek(offset) {
|
|
86
|
+
this.offset = offset;
|
|
87
|
+
}
|
|
88
|
+
u8() {
|
|
89
|
+
this.take(1);
|
|
90
|
+
return this.data[this.offset++];
|
|
91
|
+
}
|
|
92
|
+
i8() {
|
|
93
|
+
return this.u8() << 24 >> 24;
|
|
94
|
+
}
|
|
95
|
+
u16() {
|
|
96
|
+
this.take(2);
|
|
97
|
+
const value = this.data[this.offset] << 8 | this.data[this.offset + 1];
|
|
98
|
+
this.offset += 2;
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
i16() {
|
|
102
|
+
return this.u16() << 16 >> 16;
|
|
103
|
+
}
|
|
104
|
+
u32() {
|
|
105
|
+
return (this.u16() << 16 | this.u16()) >>> 0;
|
|
106
|
+
}
|
|
107
|
+
/** 读指定绝对偏移的 u16(cmap format 4 的 glyphIdArray 寻址用) */
|
|
108
|
+
u16At(offset) {
|
|
109
|
+
if (offset < 0 || offset + 2 > this.data.length) this.overrun();
|
|
110
|
+
return this.data[offset] << 8 | this.data[offset + 1];
|
|
111
|
+
}
|
|
112
|
+
take(size) {
|
|
113
|
+
if (this.offset + size > this.data.length) this.overrun();
|
|
114
|
+
}
|
|
115
|
+
overrun() {
|
|
116
|
+
throw new OfdParseError("invalid-font", `字体 ${this.source} 数据被截断`);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function parseTableDirectory(data, source) {
|
|
120
|
+
const view = new FontReader(data, source);
|
|
121
|
+
view.u32();
|
|
122
|
+
const numTables = view.u16();
|
|
123
|
+
view.seek(view.offset + 6);
|
|
124
|
+
const tables = /* @__PURE__ */ new Map();
|
|
125
|
+
for (let i = 0; i < numTables; i++) {
|
|
126
|
+
const tag = String.fromCharCode(view.u8(), view.u8(), view.u8(), view.u8());
|
|
127
|
+
view.u32();
|
|
128
|
+
const offset = view.u32();
|
|
129
|
+
const length = view.u32();
|
|
130
|
+
tables.set(tag, {
|
|
131
|
+
offset,
|
|
132
|
+
length
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return tables;
|
|
136
|
+
}
|
|
137
|
+
function parseCmap(data, table, source) {
|
|
138
|
+
const header = new FontReader(data, source, table.offset);
|
|
139
|
+
header.u16();
|
|
140
|
+
const recordCount = header.u16();
|
|
141
|
+
const records = [];
|
|
142
|
+
for (let i = 0; i < recordCount; i++) records.push({
|
|
143
|
+
platform: header.u16(),
|
|
144
|
+
encoding: header.u16(),
|
|
145
|
+
offset: table.offset + header.u32()
|
|
146
|
+
});
|
|
147
|
+
const score = (record) => record.platform === 3 && record.encoding === 10 ? 3 : record.platform === 0 ? 2 : record.platform === 3 && record.encoding === 1 ? 1 : 0;
|
|
148
|
+
records.sort((a, b) => score(b) - score(a));
|
|
149
|
+
for (const record of records) try {
|
|
150
|
+
return parseCmapSubtable(new FontReader(data, source, record.offset), source);
|
|
151
|
+
} catch {}
|
|
152
|
+
throw new OfdParseError("invalid-font", `字体 ${source} 没有可用的 cmap 子表`);
|
|
153
|
+
}
|
|
154
|
+
function parseCmapSubtable(view, source) {
|
|
155
|
+
const format = view.u16();
|
|
156
|
+
switch (format) {
|
|
157
|
+
case 4: return parseCmapFormat4(view);
|
|
158
|
+
case 12: return parseCmapFormat12(view);
|
|
159
|
+
case 0: return parseCmapFormat0(view);
|
|
160
|
+
case 6: return parseCmapFormat6(view);
|
|
161
|
+
default: throw new OfdParseError("invalid-font", `字体 ${source} 的 cmap 子表格式 ${format} 不支持`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function parseCmapFormat4(view) {
|
|
165
|
+
view.u16();
|
|
166
|
+
view.u16();
|
|
167
|
+
const segCount = view.u16() / 2;
|
|
168
|
+
view.u16();
|
|
169
|
+
view.u16();
|
|
170
|
+
view.u16();
|
|
171
|
+
if (segCount === 0) throw new OfdParseError("invalid-font", "cmap format 4 段数为 0");
|
|
172
|
+
const ends = readU16Array(view, segCount);
|
|
173
|
+
view.u16();
|
|
174
|
+
const starts = readU16Array(view, segCount);
|
|
175
|
+
const deltas = readU16Array(view, segCount);
|
|
176
|
+
const rangeOffsetBase = view.offset;
|
|
177
|
+
const rangeOffsets = readU16Array(view, segCount);
|
|
178
|
+
const map = /* @__PURE__ */ new Map();
|
|
179
|
+
for (let s = 0; s < segCount; s++) for (let code = starts[s]; code <= ends[s]; code++) {
|
|
180
|
+
let gid;
|
|
181
|
+
if (rangeOffsets[s] === 0) gid = code + deltas[s] & 65535;
|
|
182
|
+
else {
|
|
183
|
+
const address = rangeOffsetBase + 2 * s + rangeOffsets[s] + 2 * (code - starts[s]);
|
|
184
|
+
gid = view.u16At(address);
|
|
185
|
+
if (gid === 0) continue;
|
|
186
|
+
gid = gid + deltas[s] & 65535;
|
|
187
|
+
}
|
|
188
|
+
if (gid !== 0) map.set(code, gid);
|
|
189
|
+
}
|
|
190
|
+
return map;
|
|
191
|
+
}
|
|
192
|
+
function parseCmapFormat12(view) {
|
|
193
|
+
view.u16();
|
|
194
|
+
view.u32();
|
|
195
|
+
view.u32();
|
|
196
|
+
const groupCount = view.u32();
|
|
197
|
+
const map = /* @__PURE__ */ new Map();
|
|
198
|
+
for (let g = 0; g < groupCount; g++) {
|
|
199
|
+
const start = view.u32();
|
|
200
|
+
const end = Math.min(view.u32(), 1114111);
|
|
201
|
+
const startGlyph = view.u32();
|
|
202
|
+
for (let code = start; code <= end; code++) {
|
|
203
|
+
const gid = startGlyph + (code - start);
|
|
204
|
+
if (gid !== 0) map.set(code, gid);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return map;
|
|
208
|
+
}
|
|
209
|
+
function parseCmapFormat0(view) {
|
|
210
|
+
view.u16();
|
|
211
|
+
view.u16();
|
|
212
|
+
const map = /* @__PURE__ */ new Map();
|
|
213
|
+
for (let code = 0; code < 256; code++) {
|
|
214
|
+
const gid = view.u8();
|
|
215
|
+
if (gid !== 0) map.set(code, gid);
|
|
216
|
+
}
|
|
217
|
+
return map;
|
|
218
|
+
}
|
|
219
|
+
function parseCmapFormat6(view) {
|
|
220
|
+
view.u16();
|
|
221
|
+
view.u16();
|
|
222
|
+
const firstCode = view.u16();
|
|
223
|
+
const entryCount = view.u16();
|
|
224
|
+
const map = /* @__PURE__ */ new Map();
|
|
225
|
+
for (let i = 0; i < entryCount; i++) {
|
|
226
|
+
const gid = view.u16();
|
|
227
|
+
if (gid !== 0) map.set(firstCode + i, gid);
|
|
228
|
+
}
|
|
229
|
+
return map;
|
|
230
|
+
}
|
|
231
|
+
function readU16Array(view, count) {
|
|
232
|
+
return Array.from({ length: count }, () => view.u16());
|
|
233
|
+
}
|
|
234
|
+
const COMPONENT_WORDS_ARGS = 1;
|
|
235
|
+
const COMPONENT_MORE = 32;
|
|
236
|
+
const COMPONENT_SCALE = 8;
|
|
237
|
+
const COMPONENT_XY_SCALE = 64;
|
|
238
|
+
const COMPONENT_TWO_BY_TWO = 128;
|
|
239
|
+
/** 读单个 glyph 轮廓;复合 glyph 递归展开组件(带环检测),越界/空 glyph 返回空 */
|
|
240
|
+
function readGlyphOutline(glyf, gid, visiting, numGlyphs, loca, source) {
|
|
241
|
+
if (gid < 0 || gid >= numGlyphs) return [];
|
|
242
|
+
const start = loca[gid];
|
|
243
|
+
if (start === loca[gid + 1]) return [];
|
|
244
|
+
const view = new FontReader(glyf, source, start);
|
|
245
|
+
const numberOfContours = view.i16();
|
|
246
|
+
view.seek(view.offset + 8);
|
|
247
|
+
if (numberOfContours >= 0) return readSimpleGlyph(view, numberOfContours);
|
|
248
|
+
return readCompositeGlyph(view, (componentGid) => {
|
|
249
|
+
if (visiting.has(componentGid)) return [];
|
|
250
|
+
const next = new Set(visiting);
|
|
251
|
+
next.add(componentGid);
|
|
252
|
+
return readGlyphOutline(glyf, componentGid, next, numGlyphs, loca, source);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/** 简单 glyph:标志位驱动的增量坐标解码 */
|
|
256
|
+
function readSimpleGlyph(view, numberOfContours) {
|
|
257
|
+
if (numberOfContours === 0) return [];
|
|
258
|
+
const endPoints = [];
|
|
259
|
+
for (let i = 0; i < numberOfContours; i++) endPoints.push(view.u16());
|
|
260
|
+
const pointCount = endPoints[endPoints.length - 1] + 1;
|
|
261
|
+
const instructionLength = view.u16();
|
|
262
|
+
view.seek(view.offset + instructionLength);
|
|
263
|
+
const flags = [];
|
|
264
|
+
while (flags.length < pointCount) {
|
|
265
|
+
const flag = view.u8();
|
|
266
|
+
flags.push(flag);
|
|
267
|
+
if (flag & 8) {
|
|
268
|
+
const repeat = view.u8();
|
|
269
|
+
for (let r = 0; r < repeat && flags.length < pointCount; r++) flags.push(flag);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const xs = readDeltaCoords(view, flags, 2, 16);
|
|
273
|
+
const ys = readDeltaCoords(view, flags, 4, 32);
|
|
274
|
+
const points = [];
|
|
275
|
+
for (let i = 0; i < pointCount; i++) points.push({
|
|
276
|
+
x: xs[i],
|
|
277
|
+
y: ys[i],
|
|
278
|
+
onCurve: (flags[i] & 1) !== 0
|
|
279
|
+
});
|
|
280
|
+
const contours = [];
|
|
281
|
+
let start = 0;
|
|
282
|
+
for (const end of endPoints) {
|
|
283
|
+
contours.push(points.slice(start, end + 1));
|
|
284
|
+
start = end + 1;
|
|
285
|
+
}
|
|
286
|
+
return contours;
|
|
287
|
+
}
|
|
288
|
+
/** x/y 增量坐标共用解码:短格式 1 字节(符号由 same 位决定),否则 0 或 i16 */
|
|
289
|
+
function readDeltaCoords(view, flags, shortBit, sameBit) {
|
|
290
|
+
const coords = [];
|
|
291
|
+
let value = 0;
|
|
292
|
+
for (const flag of flags) {
|
|
293
|
+
if (flag & shortBit) {
|
|
294
|
+
const delta = view.u8();
|
|
295
|
+
value += (flag & sameBit) !== 0 ? delta : -delta;
|
|
296
|
+
} else if ((flag & sameBit) === 0) value += view.i16();
|
|
297
|
+
coords.push(value);
|
|
298
|
+
}
|
|
299
|
+
return coords;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 复合 glyph:组件递归展开,先按组件矩阵变换再平移。
|
|
303
|
+
* 极少见「点对齐」组件(args 为点序号而非 XY 偏移)按偏移量处理,不做点匹配。
|
|
304
|
+
*/
|
|
305
|
+
function readCompositeGlyph(view, resolve) {
|
|
306
|
+
const contours = [];
|
|
307
|
+
let flags;
|
|
308
|
+
do {
|
|
309
|
+
flags = view.u16();
|
|
310
|
+
const glyphIndex = view.u16();
|
|
311
|
+
const wide = (flags & COMPONENT_WORDS_ARGS) !== 0;
|
|
312
|
+
const dx = wide ? view.i16() : view.i8();
|
|
313
|
+
const dy = wide ? view.i16() : view.i8();
|
|
314
|
+
let a = 1;
|
|
315
|
+
let b = 0;
|
|
316
|
+
let c = 0;
|
|
317
|
+
let d = 1;
|
|
318
|
+
if (flags & COMPONENT_SCALE) a = d = readFixed214(view);
|
|
319
|
+
else if (flags & COMPONENT_XY_SCALE) {
|
|
320
|
+
a = readFixed214(view);
|
|
321
|
+
d = readFixed214(view);
|
|
322
|
+
} else if (flags & COMPONENT_TWO_BY_TWO) {
|
|
323
|
+
a = readFixed214(view);
|
|
324
|
+
b = readFixed214(view);
|
|
325
|
+
c = readFixed214(view);
|
|
326
|
+
d = readFixed214(view);
|
|
327
|
+
}
|
|
328
|
+
for (const contour of resolve(glyphIndex)) contours.push(contour.map((point) => ({
|
|
329
|
+
x: a * point.x + c * point.y + dx,
|
|
330
|
+
y: b * point.x + d * point.y + dy,
|
|
331
|
+
onCurve: point.onCurve
|
|
332
|
+
})));
|
|
333
|
+
} while (flags & COMPONENT_MORE);
|
|
334
|
+
return contours;
|
|
335
|
+
}
|
|
336
|
+
function readFixed214(view) {
|
|
337
|
+
return view.u16() / 16384;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* TrueType 轮廓转 path:相邻 off-curve 点之间补隐式中点(on-curve),
|
|
341
|
+
* 旋转到 on-curve 点开头后逐段输出 L / Q,Z 闭合。
|
|
342
|
+
*/
|
|
343
|
+
function contourPathD(contour, scale, originX, originY) {
|
|
344
|
+
const points = normalizeContour(contour);
|
|
345
|
+
if (points.length === 0) return "";
|
|
346
|
+
const count = points.length;
|
|
347
|
+
const at = (index) => points[index % count];
|
|
348
|
+
const x = (point) => formatNumber(point.x * scale + originX);
|
|
349
|
+
const y = (point) => formatNumber(originY - point.y * scale);
|
|
350
|
+
const parts = [`M ${x(points[0])} ${y(points[0])}`];
|
|
351
|
+
for (let i = 1; i < count; i++) {
|
|
352
|
+
const point = at(i);
|
|
353
|
+
if (point.onCurve) parts.push(`L ${x(point)} ${y(point)}`);
|
|
354
|
+
else {
|
|
355
|
+
const next = at(i + 1);
|
|
356
|
+
parts.push(`Q ${x(point)} ${y(point)} ${x(next)} ${y(next)}`);
|
|
357
|
+
i++;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
parts.push("Z");
|
|
361
|
+
return parts.join(" ");
|
|
362
|
+
}
|
|
363
|
+
function normalizeContour(contour) {
|
|
364
|
+
const count = contour.length;
|
|
365
|
+
if (count === 0) return [];
|
|
366
|
+
const expanded = [];
|
|
367
|
+
for (let i = 0; i < count; i++) {
|
|
368
|
+
const point = contour[i];
|
|
369
|
+
expanded.push(point);
|
|
370
|
+
const next = contour[(i + 1) % count];
|
|
371
|
+
if (!point.onCurve && !next.onCurve) expanded.push({
|
|
372
|
+
x: (point.x + next.x) / 2,
|
|
373
|
+
y: (point.y + next.y) / 2,
|
|
374
|
+
onCurve: true
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
const start = expanded.findIndex((point) => point.onCurve);
|
|
378
|
+
if (start <= 0) return expanded;
|
|
379
|
+
return [...expanded.slice(start), ...expanded.slice(0, start)];
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
export { glyphPathD, parseEmbeddedFont };
|
|
383
|
+
|
|
384
|
+
//# sourceMappingURL=font.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font.js","names":[],"sources":["../../../../../ofd-core/dist/font.js"],"sourcesContent":["import { OfdParseError } from \"./error.js\";\nimport { formatNumber } from \"./number.js\";\n//#region src/font.ts\n/**\n* 内嵌 TTF 字体解析与 glyph 轮廓输出(OFD Font@FontFile 声明的内嵌字体)。\n*\n* 读取 TrueType 的 head/maxp/cmap/loca/glyf/hhea/hmtx 表:cmap 把字符码点映射到\n* glyph id(可省,省略时字符映射由渲染层 CGTransform 字形序号提供),glyf 提取\n* 轮廓点(on/off curve,复合 glyph 递归展开并平移/缩放)。\n* 二次贝塞尔轮廓按 unitsPerEm → 字号缩放、基线定位并翻转 y 轴后转成 SVG path\n* `d`。二进制结构非法时抛 OfdParseError('invalid-font')。\n*/\n/** 解析 TTF 二进制:结构非法抛 OfdParseError('invalid-font') */\nfunction parseEmbeddedFont(data, source) {\n\tif (data.length < 12) throw new OfdParseError(\"invalid-font\", `字体 ${source} 数据太短,不是 TTF 文件`);\n\tconst tables = parseTableDirectory(data, source);\n\tfor (const tag of REQUIRED_TABLES) {\n\t\tconst table = tables.get(tag);\n\t\tif (!table) throw new OfdParseError(\"invalid-font\", `字体 ${source} 缺少 ${tag} 表`);\n\t\tif (table.offset + table.length > data.length) throw new OfdParseError(\"invalid-font\", `字体 ${source} 的 ${tag} 表越界,数据被截断`);\n\t}\n\tconst headOffset = tables.get(\"head\").offset;\n\tconst unitsPerEm = new FontReader(data, source, headOffset + 18).u16();\n\tif (unitsPerEm === 0) throw new OfdParseError(\"invalid-font\", `字体 ${source} 的 unitsPerEm 为 0`);\n\tconst indexToLocFormat = new FontReader(data, source, headOffset + 50).i16();\n\tif (indexToLocFormat !== 0 && indexToLocFormat !== 1) throw new OfdParseError(\"invalid-font\", `字体 ${source} 的 indexToLocFormat 不合法:${indexToLocFormat}`);\n\tconst numGlyphs = new FontReader(data, source, tables.get(\"maxp\").offset + 4).u16();\n\tconst cmapTable = tables.get(\"cmap\");\n\tconst cmap = cmapTable ? parseCmap(data, cmapTable, source) : /* @__PURE__ */ new Map();\n\tconst glyfTable = tables.get(\"glyf\");\n\tconst locaView = new FontReader(data, source, tables.get(\"loca\").offset);\n\tconst loca = [];\n\tfor (let i = 0; i <= numGlyphs; i++) loca.push(indexToLocFormat === 0 ? locaView.u16() * 2 : locaView.u32());\n\tfor (let i = 0; i < numGlyphs; i++) if (loca[i + 1] < loca[i] || loca[i + 1] > glyfTable.length) throw new OfdParseError(\"invalid-font\", `字体 ${source} 的 loca 表越界`);\n\tconst numberOfHMetrics = Math.min(new FontReader(data, source, tables.get(\"hhea\").offset + 34).u16(), numGlyphs);\n\tconst hmtxView = new FontReader(data, source, tables.get(\"hmtx\").offset);\n\tconst advances = [];\n\tfor (let i = 0; i < numberOfHMetrics; i++) {\n\t\tadvances.push(hmtxView.u16());\n\t\thmtxView.i16();\n\t}\n\tconst glyf = data.subarray(glyfTable.offset, glyfTable.offset + glyfTable.length);\n\tconst outlineCache = /* @__PURE__ */ new Map();\n\treturn {\n\t\tunitsPerEm,\n\t\tnumGlyphs,\n\t\tglyphIndexOf: (codePoint) => cmap.get(codePoint) ?? null,\n\t\tadvanceWidth: (gid) => advances[Math.min(Math.max(gid, 0), advances.length - 1)] ?? 0,\n\t\tglyphOutline: (gid) => {\n\t\t\tconst cached = outlineCache.get(gid);\n\t\t\tif (cached) return cached;\n\t\t\tconst outline = readGlyphOutline(glyf, gid, /* @__PURE__ */ new Set([gid]), numGlyphs, loca, source);\n\t\t\toutlineCache.set(gid, outline);\n\t\t\treturn outline;\n\t\t}\n\t};\n}\n/**\n* glyph 轮廓转 SVG path `d`:unitsPerEm → 字号缩放,基线原点定位并翻转\n* y 轴(字体坐标向上,SVG 向下)。无轮廓返回空串。\n*/\nfunction glyphPathD(font, gid, fontSize, originX, originY) {\n\tif (!(fontSize > 0)) return \"\";\n\tconst scale = fontSize / font.unitsPerEm;\n\treturn font.glyphOutline(gid).map((contour) => contourPathD(contour, scale, originX, originY)).filter((d) => d !== \"\").join(\" \");\n}\nconst REQUIRED_TABLES = [\n\t\"glyf\",\n\t\"head\",\n\t\"hhea\",\n\t\"hmtx\",\n\t\"loca\",\n\t\"maxp\"\n];\n/** 带越界检查的大端读取器:越界抛 invalid-font */\nvar FontReader = class {\n\tdata;\n\tsource;\n\toffset;\n\tconstructor(data, source, offset = 0) {\n\t\tthis.data = data;\n\t\tthis.source = source;\n\t\tthis.offset = offset;\n\t}\n\tseek(offset) {\n\t\tthis.offset = offset;\n\t}\n\tu8() {\n\t\tthis.take(1);\n\t\treturn this.data[this.offset++];\n\t}\n\ti8() {\n\t\treturn this.u8() << 24 >> 24;\n\t}\n\tu16() {\n\t\tthis.take(2);\n\t\tconst value = this.data[this.offset] << 8 | this.data[this.offset + 1];\n\t\tthis.offset += 2;\n\t\treturn value;\n\t}\n\ti16() {\n\t\treturn this.u16() << 16 >> 16;\n\t}\n\tu32() {\n\t\treturn (this.u16() << 16 | this.u16()) >>> 0;\n\t}\n\t/** 读指定绝对偏移的 u16(cmap format 4 的 glyphIdArray 寻址用) */\n\tu16At(offset) {\n\t\tif (offset < 0 || offset + 2 > this.data.length) this.overrun();\n\t\treturn this.data[offset] << 8 | this.data[offset + 1];\n\t}\n\ttake(size) {\n\t\tif (this.offset + size > this.data.length) this.overrun();\n\t}\n\toverrun() {\n\t\tthrow new OfdParseError(\"invalid-font\", `字体 ${this.source} 数据被截断`);\n\t}\n};\nfunction parseTableDirectory(data, source) {\n\tconst view = new FontReader(data, source);\n\tview.u32();\n\tconst numTables = view.u16();\n\tview.seek(view.offset + 6);\n\tconst tables = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < numTables; i++) {\n\t\tconst tag = String.fromCharCode(view.u8(), view.u8(), view.u8(), view.u8());\n\t\tview.u32();\n\t\tconst offset = view.u32();\n\t\tconst length = view.u32();\n\t\ttables.set(tag, {\n\t\t\toffset,\n\t\t\tlength\n\t\t});\n\t}\n\treturn tables;\n}\nfunction parseCmap(data, table, source) {\n\tconst header = new FontReader(data, source, table.offset);\n\theader.u16();\n\tconst recordCount = header.u16();\n\tconst records = [];\n\tfor (let i = 0; i < recordCount; i++) records.push({\n\t\tplatform: header.u16(),\n\t\tencoding: header.u16(),\n\t\toffset: table.offset + header.u32()\n\t});\n\tconst score = (record) => record.platform === 3 && record.encoding === 10 ? 3 : record.platform === 0 ? 2 : record.platform === 3 && record.encoding === 1 ? 1 : 0;\n\trecords.sort((a, b) => score(b) - score(a));\n\tfor (const record of records) try {\n\t\treturn parseCmapSubtable(new FontReader(data, source, record.offset), source);\n\t} catch {}\n\tthrow new OfdParseError(\"invalid-font\", `字体 ${source} 没有可用的 cmap 子表`);\n}\nfunction parseCmapSubtable(view, source) {\n\tconst format = view.u16();\n\tswitch (format) {\n\t\tcase 4: return parseCmapFormat4(view);\n\t\tcase 12: return parseCmapFormat12(view);\n\t\tcase 0: return parseCmapFormat0(view);\n\t\tcase 6: return parseCmapFormat6(view);\n\t\tdefault: throw new OfdParseError(\"invalid-font\", `字体 ${source} 的 cmap 子表格式 ${format} 不支持`);\n\t}\n}\nfunction parseCmapFormat4(view) {\n\tview.u16();\n\tview.u16();\n\tconst segCount = view.u16() / 2;\n\tview.u16();\n\tview.u16();\n\tview.u16();\n\tif (segCount === 0) throw new OfdParseError(\"invalid-font\", \"cmap format 4 段数为 0\");\n\tconst ends = readU16Array(view, segCount);\n\tview.u16();\n\tconst starts = readU16Array(view, segCount);\n\tconst deltas = readU16Array(view, segCount);\n\tconst rangeOffsetBase = view.offset;\n\tconst rangeOffsets = readU16Array(view, segCount);\n\tconst map = /* @__PURE__ */ new Map();\n\tfor (let s = 0; s < segCount; s++) for (let code = starts[s]; code <= ends[s]; code++) {\n\t\tlet gid;\n\t\tif (rangeOffsets[s] === 0) gid = code + deltas[s] & 65535;\n\t\telse {\n\t\t\tconst address = rangeOffsetBase + 2 * s + rangeOffsets[s] + 2 * (code - starts[s]);\n\t\t\tgid = view.u16At(address);\n\t\t\tif (gid === 0) continue;\n\t\t\tgid = gid + deltas[s] & 65535;\n\t\t}\n\t\tif (gid !== 0) map.set(code, gid);\n\t}\n\treturn map;\n}\nfunction parseCmapFormat12(view) {\n\tview.u16();\n\tview.u32();\n\tview.u32();\n\tconst groupCount = view.u32();\n\tconst map = /* @__PURE__ */ new Map();\n\tfor (let g = 0; g < groupCount; g++) {\n\t\tconst start = view.u32();\n\t\tconst end = Math.min(view.u32(), 1114111);\n\t\tconst startGlyph = view.u32();\n\t\tfor (let code = start; code <= end; code++) {\n\t\t\tconst gid = startGlyph + (code - start);\n\t\t\tif (gid !== 0) map.set(code, gid);\n\t\t}\n\t}\n\treturn map;\n}\nfunction parseCmapFormat0(view) {\n\tview.u16();\n\tview.u16();\n\tconst map = /* @__PURE__ */ new Map();\n\tfor (let code = 0; code < 256; code++) {\n\t\tconst gid = view.u8();\n\t\tif (gid !== 0) map.set(code, gid);\n\t}\n\treturn map;\n}\nfunction parseCmapFormat6(view) {\n\tview.u16();\n\tview.u16();\n\tconst firstCode = view.u16();\n\tconst entryCount = view.u16();\n\tconst map = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < entryCount; i++) {\n\t\tconst gid = view.u16();\n\t\tif (gid !== 0) map.set(firstCode + i, gid);\n\t}\n\treturn map;\n}\nfunction readU16Array(view, count) {\n\treturn Array.from({ length: count }, () => view.u16());\n}\nconst COMPONENT_WORDS_ARGS = 1;\nconst COMPONENT_MORE = 32;\nconst COMPONENT_SCALE = 8;\nconst COMPONENT_XY_SCALE = 64;\nconst COMPONENT_TWO_BY_TWO = 128;\n/** 读单个 glyph 轮廓;复合 glyph 递归展开组件(带环检测),越界/空 glyph 返回空 */\nfunction readGlyphOutline(glyf, gid, visiting, numGlyphs, loca, source) {\n\tif (gid < 0 || gid >= numGlyphs) return [];\n\tconst start = loca[gid];\n\tif (start === loca[gid + 1]) return [];\n\tconst view = new FontReader(glyf, source, start);\n\tconst numberOfContours = view.i16();\n\tview.seek(view.offset + 8);\n\tif (numberOfContours >= 0) return readSimpleGlyph(view, numberOfContours);\n\treturn readCompositeGlyph(view, (componentGid) => {\n\t\tif (visiting.has(componentGid)) return [];\n\t\tconst next = new Set(visiting);\n\t\tnext.add(componentGid);\n\t\treturn readGlyphOutline(glyf, componentGid, next, numGlyphs, loca, source);\n\t});\n}\n/** 简单 glyph:标志位驱动的增量坐标解码 */\nfunction readSimpleGlyph(view, numberOfContours) {\n\tif (numberOfContours === 0) return [];\n\tconst endPoints = [];\n\tfor (let i = 0; i < numberOfContours; i++) endPoints.push(view.u16());\n\tconst pointCount = endPoints[endPoints.length - 1] + 1;\n\tconst instructionLength = view.u16();\n\tview.seek(view.offset + instructionLength);\n\tconst flags = [];\n\twhile (flags.length < pointCount) {\n\t\tconst flag = view.u8();\n\t\tflags.push(flag);\n\t\tif (flag & 8) {\n\t\t\tconst repeat = view.u8();\n\t\t\tfor (let r = 0; r < repeat && flags.length < pointCount; r++) flags.push(flag);\n\t\t}\n\t}\n\tconst xs = readDeltaCoords(view, flags, 2, 16);\n\tconst ys = readDeltaCoords(view, flags, 4, 32);\n\tconst points = [];\n\tfor (let i = 0; i < pointCount; i++) points.push({\n\t\tx: xs[i],\n\t\ty: ys[i],\n\t\tonCurve: (flags[i] & 1) !== 0\n\t});\n\tconst contours = [];\n\tlet start = 0;\n\tfor (const end of endPoints) {\n\t\tcontours.push(points.slice(start, end + 1));\n\t\tstart = end + 1;\n\t}\n\treturn contours;\n}\n/** x/y 增量坐标共用解码:短格式 1 字节(符号由 same 位决定),否则 0 或 i16 */\nfunction readDeltaCoords(view, flags, shortBit, sameBit) {\n\tconst coords = [];\n\tlet value = 0;\n\tfor (const flag of flags) {\n\t\tif (flag & shortBit) {\n\t\t\tconst delta = view.u8();\n\t\t\tvalue += (flag & sameBit) !== 0 ? delta : -delta;\n\t\t} else if ((flag & sameBit) === 0) value += view.i16();\n\t\tcoords.push(value);\n\t}\n\treturn coords;\n}\n/**\n* 复合 glyph:组件递归展开,先按组件矩阵变换再平移。\n* 极少见「点对齐」组件(args 为点序号而非 XY 偏移)按偏移量处理,不做点匹配。\n*/\nfunction readCompositeGlyph(view, resolve) {\n\tconst contours = [];\n\tlet flags;\n\tdo {\n\t\tflags = view.u16();\n\t\tconst glyphIndex = view.u16();\n\t\tconst wide = (flags & COMPONENT_WORDS_ARGS) !== 0;\n\t\tconst dx = wide ? view.i16() : view.i8();\n\t\tconst dy = wide ? view.i16() : view.i8();\n\t\tlet a = 1;\n\t\tlet b = 0;\n\t\tlet c = 0;\n\t\tlet d = 1;\n\t\tif (flags & COMPONENT_SCALE) a = d = readFixed214(view);\n\t\telse if (flags & COMPONENT_XY_SCALE) {\n\t\t\ta = readFixed214(view);\n\t\t\td = readFixed214(view);\n\t\t} else if (flags & COMPONENT_TWO_BY_TWO) {\n\t\t\ta = readFixed214(view);\n\t\t\tb = readFixed214(view);\n\t\t\tc = readFixed214(view);\n\t\t\td = readFixed214(view);\n\t\t}\n\t\tfor (const contour of resolve(glyphIndex)) contours.push(contour.map((point) => ({\n\t\t\tx: a * point.x + c * point.y + dx,\n\t\t\ty: b * point.x + d * point.y + dy,\n\t\t\tonCurve: point.onCurve\n\t\t})));\n\t} while (flags & COMPONENT_MORE);\n\treturn contours;\n}\nfunction readFixed214(view) {\n\treturn view.u16() / 16384;\n}\n/**\n* TrueType 轮廓转 path:相邻 off-curve 点之间补隐式中点(on-curve),\n* 旋转到 on-curve 点开头后逐段输出 L / Q,Z 闭合。\n*/\nfunction contourPathD(contour, scale, originX, originY) {\n\tconst points = normalizeContour(contour);\n\tif (points.length === 0) return \"\";\n\tconst count = points.length;\n\tconst at = (index) => points[index % count];\n\tconst x = (point) => formatNumber(point.x * scale + originX);\n\tconst y = (point) => formatNumber(originY - point.y * scale);\n\tconst parts = [`M ${x(points[0])} ${y(points[0])}`];\n\tfor (let i = 1; i < count; i++) {\n\t\tconst point = at(i);\n\t\tif (point.onCurve) parts.push(`L ${x(point)} ${y(point)}`);\n\t\telse {\n\t\t\tconst next = at(i + 1);\n\t\t\tparts.push(`Q ${x(point)} ${y(point)} ${x(next)} ${y(next)}`);\n\t\t\ti++;\n\t\t}\n\t}\n\tparts.push(\"Z\");\n\treturn parts.join(\" \");\n}\nfunction normalizeContour(contour) {\n\tconst count = contour.length;\n\tif (count === 0) return [];\n\tconst expanded = [];\n\tfor (let i = 0; i < count; i++) {\n\t\tconst point = contour[i];\n\t\texpanded.push(point);\n\t\tconst next = contour[(i + 1) % count];\n\t\tif (!point.onCurve && !next.onCurve) expanded.push({\n\t\t\tx: (point.x + next.x) / 2,\n\t\t\ty: (point.y + next.y) / 2,\n\t\t\tonCurve: true\n\t\t});\n\t}\n\tconst start = expanded.findIndex((point) => point.onCurve);\n\tif (start <= 0) return expanded;\n\treturn [...expanded.slice(start), ...expanded.slice(0, start)];\n}\n//#endregion\nexport { glyphPathD, parseEmbeddedFont };\n\n//# sourceMappingURL=font.js.map"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OfdParseError } from "./error.js";
|
|
2
|
+
import { openOfdZip } from "./zip.js";
|
|
3
|
+
import { parseOfd, parseOfdContainer } from "./parse.js";
|
|
4
|
+
import { glyphPathD, parseEmbeddedFont } from "./font.js";
|
|
5
|
+
import { pageToSvg } from "./render.js";
|
|
6
|
+
export { OfdParseError, glyphPathD, openOfdZip, pageToSvg, parseEmbeddedFont, parseOfd, parseOfdContainer };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region ../ofd-core/dist/number.js
|
|
2
|
+
/** SVG 输出共用的小数处理(render 与 font 两处调用) */
|
|
3
|
+
function roundTo(value, digits) {
|
|
4
|
+
return Math.round(value * 10 ** digits) / 10 ** digits;
|
|
5
|
+
}
|
|
6
|
+
/** 数值转 SVG 属性文本:截掉浮点噪声(如 0.30000000000000004 → 0.3) */
|
|
7
|
+
function formatNumber(value) {
|
|
8
|
+
return String(roundTo(value, 4));
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { formatNumber, roundTo };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number.js","names":[],"sources":["../../../../../ofd-core/dist/number.js"],"sourcesContent":["//#region src/number.ts\n/** SVG 输出共用的小数处理(render 与 font 两处调用) */\nfunction roundTo(value, digits) {\n\treturn Math.round(value * 10 ** digits) / 10 ** digits;\n}\n/** 数值转 SVG 属性文本:截掉浮点噪声(如 0.30000000000000004 → 0.3) */\nfunction formatNumber(value) {\n\treturn String(roundTo(value, 4));\n}\n//#endregion\nexport { formatNumber, roundTo };\n\n//# sourceMappingURL=number.js.map"],"mappings":";;AAEA,SAAS,QAAQ,OAAO,QAAQ;CAC/B,OAAO,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM;AACjD;;AAEA,SAAS,aAAa,OAAO;CAC5B,OAAO,OAAO,QAAQ,OAAO,CAAC,CAAC;AAChC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { parseBoundary, parseMatrix, parseNumberList } from "./ctm.js";
|
|
2
|
+
import { parseOfdColor } from "./color.js";
|
|
3
|
+
import { childElements, childrenNamed, firstChildNamed, localNameOf, parseLayerType, parseXml, rootElementOf } from "./xml.js";
|
|
4
|
+
//#region ../ofd-core/dist/page-objects.js
|
|
5
|
+
/**
|
|
6
|
+
* Page.xml 内容对象模型:图层内的文本 / 图片 / 路径 / 复合对象。
|
|
7
|
+
*
|
|
8
|
+
* 与 P1 的 OfdPage(图层声明)分离:渲染按页懒执行,这里在渲染前按需解析,
|
|
9
|
+
* 使页与页相互独立、未渲染页不产生解析开销。
|
|
10
|
+
*/
|
|
11
|
+
/** 页面内容文件根元素:普通页为 Page,模板页内容也有产出写作 TemplatePage */
|
|
12
|
+
const PAGE_ROOT_NAMES = ["Page", "TemplatePage"];
|
|
13
|
+
/** 解析页 / 模板页内容的图元对象;未知对象类型跳过 */
|
|
14
|
+
function parsePageContent(xml, source) {
|
|
15
|
+
const root = rootElementOf(parseXml(xml, source), PAGE_ROOT_NAMES, source);
|
|
16
|
+
const layerParent = firstChildNamed(root, "Content") ?? root;
|
|
17
|
+
const layers = [];
|
|
18
|
+
const objectsById = /* @__PURE__ */ new Map();
|
|
19
|
+
for (const layer of childrenNamed(layerParent, "Layer")) {
|
|
20
|
+
const objects = [];
|
|
21
|
+
collectLayerObjects(layer, objects, objectsById);
|
|
22
|
+
layers.push({
|
|
23
|
+
type: parseLayerType(layer.getAttribute("Type")),
|
|
24
|
+
drawParamId: layer.getAttribute("DrawParam"),
|
|
25
|
+
objects
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
layers,
|
|
30
|
+
objectsById,
|
|
31
|
+
templateRefs: childrenNamed(root, "Template").map(parseTemplateRef)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 图层内对象收集:PageBlock 是纯分组容器(新版数电票正文层实证,自身无
|
|
36
|
+
* Boundary/CTM),递归扁平化不改变成员对象坐标。
|
|
37
|
+
*/
|
|
38
|
+
function collectLayerObjects(container, out, objectsById) {
|
|
39
|
+
for (const element of childElements(container)) {
|
|
40
|
+
if (localNameOf(element) === "PageBlock") {
|
|
41
|
+
collectLayerObjects(element, out, objectsById);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const object = parsePageObject(element);
|
|
45
|
+
if (!object) continue;
|
|
46
|
+
if (object.id) objectsById.set(object.id, object);
|
|
47
|
+
out.push(object);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** 解析 Template 引用:TemplateID 取声明 ID,ZOrder 缺省按背景叠加 */
|
|
51
|
+
function parseTemplateRef(element) {
|
|
52
|
+
const stackedForeground = element.getAttribute("ZOrder")?.toLowerCase() === "foreground";
|
|
53
|
+
return {
|
|
54
|
+
templateId: element.getAttribute("TemplateID"),
|
|
55
|
+
zOrder: stackedForeground ? "foreground" : "background"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function parsePageObject(element) {
|
|
59
|
+
const base = {
|
|
60
|
+
id: element.getAttribute("ID"),
|
|
61
|
+
boundary: parseBoundary(element.getAttribute("Boundary")),
|
|
62
|
+
ctm: parseMatrix(element.getAttribute("CTM")),
|
|
63
|
+
drawParamId: element.getAttribute("DrawParam")
|
|
64
|
+
};
|
|
65
|
+
switch (localNameOf(element)) {
|
|
66
|
+
case "TextObject": return {
|
|
67
|
+
...base,
|
|
68
|
+
kind: "text",
|
|
69
|
+
fontId: element.getAttribute("FontID") ?? element.getAttribute("Font"),
|
|
70
|
+
fontSize: parseNumber(element.getAttribute("FontSize") ?? element.getAttribute("Size")),
|
|
71
|
+
fillColor: objectColor(element, "FillColor"),
|
|
72
|
+
codes: childrenNamed(element, "TextCode").map(parseTextCode),
|
|
73
|
+
glyphSubstitutions: childrenNamed(element, "CGTransform").map(parseGlyphSubstitution)
|
|
74
|
+
};
|
|
75
|
+
case "ImageObject": return {
|
|
76
|
+
...base,
|
|
77
|
+
kind: "image",
|
|
78
|
+
resourceId: element.getAttribute("ResourceID")
|
|
79
|
+
};
|
|
80
|
+
case "PathObject": return {
|
|
81
|
+
...base,
|
|
82
|
+
kind: "path",
|
|
83
|
+
fill: element.getAttribute("Fill") === "true",
|
|
84
|
+
fillColor: objectColor(element, "FillColor"),
|
|
85
|
+
strokeColor: objectColor(element, "StrokeColor"),
|
|
86
|
+
lineWidth: parseNumber(element.getAttribute("LineWidth")),
|
|
87
|
+
dashPattern: parseNumberList(element.getAttribute("DashPattern")),
|
|
88
|
+
commands: parsePathCommands(firstChildNamed(element, "AbbreviatedData")?.textContent ?? null)
|
|
89
|
+
};
|
|
90
|
+
case "CompositeObject": return {
|
|
91
|
+
...base,
|
|
92
|
+
kind: "composite",
|
|
93
|
+
referenceId: element.getAttribute("ReferenceID")
|
|
94
|
+
};
|
|
95
|
+
default: return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 对象颜色声明兼容两种形式:属性 `FillColor="128 0 0"` 与子元素
|
|
100
|
+
* `<FillColor Value="128 0 0"/>`(新版数电票实证为子元素形式)。
|
|
101
|
+
*/
|
|
102
|
+
function objectColor(element, name) {
|
|
103
|
+
return parseOfdColor(element.getAttribute(name) ?? firstChildNamed(element, name)?.getAttribute("Value") ?? null);
|
|
104
|
+
}
|
|
105
|
+
/** 解析 CGTransform:Glyphs 支持 ST_Array 的 `g n v` 压缩写法 */
|
|
106
|
+
function parseGlyphSubstitution(element) {
|
|
107
|
+
return {
|
|
108
|
+
codePosition: parseNumber(element.getAttribute("CodePosition")) ?? 0,
|
|
109
|
+
codeCount: parseNumber(element.getAttribute("CodeCount")) ?? 0,
|
|
110
|
+
glyphIds: parseDeltaList(firstChildNamed(element, "Glyphs")?.textContent ?? null)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function parseTextCode(code) {
|
|
114
|
+
return {
|
|
115
|
+
x: parseNumber(code.getAttribute("X")),
|
|
116
|
+
y: parseNumber(code.getAttribute("Y")),
|
|
117
|
+
deltaX: parseDeltaList(code.getAttribute("DeltaX")),
|
|
118
|
+
deltaY: parseDeltaList(code.getAttribute("DeltaY")),
|
|
119
|
+
text: code.textContent ?? ""
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 解析 TextCode 位移数组:数值按序对应相邻字符位移;`g n v` 是 ST_Array 的
|
|
124
|
+
* 压缩写法(数电发票实证),表示 n 个连续位移均为 v。
|
|
125
|
+
*/
|
|
126
|
+
function parseDeltaList(value) {
|
|
127
|
+
const tokens = value?.trim().split(/[\s,]+/).filter((token) => token !== "") ?? [];
|
|
128
|
+
const deltas = [];
|
|
129
|
+
for (let index = 0; index < tokens.length;) {
|
|
130
|
+
if (tokens[index] === "g") {
|
|
131
|
+
const count = Number(tokens[index + 1]);
|
|
132
|
+
const repeated = Number(tokens[index + 2]);
|
|
133
|
+
if (Number.isInteger(count) && count > 0 && Number.isFinite(repeated)) {
|
|
134
|
+
for (let repeat = 0; repeat < count; repeat++) deltas.push(repeated);
|
|
135
|
+
index += 3;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
index += 1;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const delta = Number(tokens[index]);
|
|
142
|
+
if (Number.isFinite(delta)) deltas.push(delta);
|
|
143
|
+
index += 1;
|
|
144
|
+
}
|
|
145
|
+
return deltas;
|
|
146
|
+
}
|
|
147
|
+
const PATH_ARITY = {
|
|
148
|
+
M: 2,
|
|
149
|
+
L: 2,
|
|
150
|
+
C: 6,
|
|
151
|
+
B: 4,
|
|
152
|
+
Q: 4,
|
|
153
|
+
Z: 0
|
|
154
|
+
};
|
|
155
|
+
function parsePathCommands(data) {
|
|
156
|
+
const tokens = data?.trim().split(/[\s,]+/).filter((token) => token !== "") ?? [];
|
|
157
|
+
const commands = [];
|
|
158
|
+
for (let index = 0; index < tokens.length;) {
|
|
159
|
+
const type = tokens[index].toUpperCase();
|
|
160
|
+
const arity = PATH_ARITY[type];
|
|
161
|
+
if (arity === void 0) {
|
|
162
|
+
index += 1;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const points = tokens.slice(index + 1, index + 1 + arity).map(Number);
|
|
166
|
+
if (points.length === arity && points.every((point) => Number.isFinite(point))) commands.push({
|
|
167
|
+
type,
|
|
168
|
+
points
|
|
169
|
+
});
|
|
170
|
+
index += 1 + arity;
|
|
171
|
+
}
|
|
172
|
+
return commands;
|
|
173
|
+
}
|
|
174
|
+
function parseNumber(value) {
|
|
175
|
+
const numbers = parseNumberList(value);
|
|
176
|
+
return numbers.length > 0 ? numbers[0] : null;
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { parsePageContent };
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=page-objects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-objects.js","names":[],"sources":["../../../../../ofd-core/dist/page-objects.js"],"sourcesContent":["import { parseBoundary, parseMatrix, parseNumberList } from \"./ctm.js\";\nimport { parseOfdColor } from \"./color.js\";\nimport { childElements, childrenNamed, firstChildNamed, localNameOf, parseLayerType, parseXml, rootElementOf } from \"./xml.js\";\n//#region src/page-objects.ts\n/**\n* Page.xml 内容对象模型:图层内的文本 / 图片 / 路径 / 复合对象。\n*\n* 与 P1 的 OfdPage(图层声明)分离:渲染按页懒执行,这里在渲染前按需解析,\n* 使页与页相互独立、未渲染页不产生解析开销。\n*/\n/** 页面内容文件根元素:普通页为 Page,模板页内容也有产出写作 TemplatePage */\nconst PAGE_ROOT_NAMES = [\"Page\", \"TemplatePage\"];\n/** 解析页 / 模板页内容的图元对象;未知对象类型跳过 */\nfunction parsePageContent(xml, source) {\n\tconst root = rootElementOf(parseXml(xml, source), PAGE_ROOT_NAMES, source);\n\tconst layerParent = firstChildNamed(root, \"Content\") ?? root;\n\tconst layers = [];\n\tconst objectsById = /* @__PURE__ */ new Map();\n\tfor (const layer of childrenNamed(layerParent, \"Layer\")) {\n\t\tconst objects = [];\n\t\tcollectLayerObjects(layer, objects, objectsById);\n\t\tlayers.push({\n\t\t\ttype: parseLayerType(layer.getAttribute(\"Type\")),\n\t\t\tdrawParamId: layer.getAttribute(\"DrawParam\"),\n\t\t\tobjects\n\t\t});\n\t}\n\treturn {\n\t\tlayers,\n\t\tobjectsById,\n\t\ttemplateRefs: childrenNamed(root, \"Template\").map(parseTemplateRef)\n\t};\n}\n/**\n* 图层内对象收集:PageBlock 是纯分组容器(新版数电票正文层实证,自身无\n* Boundary/CTM),递归扁平化不改变成员对象坐标。\n*/\nfunction collectLayerObjects(container, out, objectsById) {\n\tfor (const element of childElements(container)) {\n\t\tif (localNameOf(element) === \"PageBlock\") {\n\t\t\tcollectLayerObjects(element, out, objectsById);\n\t\t\tcontinue;\n\t\t}\n\t\tconst object = parsePageObject(element);\n\t\tif (!object) continue;\n\t\tif (object.id) objectsById.set(object.id, object);\n\t\tout.push(object);\n\t}\n}\n/** 解析 Template 引用:TemplateID 取声明 ID,ZOrder 缺省按背景叠加 */\nfunction parseTemplateRef(element) {\n\tconst stackedForeground = element.getAttribute(\"ZOrder\")?.toLowerCase() === \"foreground\";\n\treturn {\n\t\ttemplateId: element.getAttribute(\"TemplateID\"),\n\t\tzOrder: stackedForeground ? \"foreground\" : \"background\"\n\t};\n}\nfunction parsePageObject(element) {\n\tconst base = {\n\t\tid: element.getAttribute(\"ID\"),\n\t\tboundary: parseBoundary(element.getAttribute(\"Boundary\")),\n\t\tctm: parseMatrix(element.getAttribute(\"CTM\")),\n\t\tdrawParamId: element.getAttribute(\"DrawParam\")\n\t};\n\tswitch (localNameOf(element)) {\n\t\tcase \"TextObject\": return {\n\t\t\t...base,\n\t\t\tkind: \"text\",\n\t\t\tfontId: element.getAttribute(\"FontID\") ?? element.getAttribute(\"Font\"),\n\t\t\tfontSize: parseNumber(element.getAttribute(\"FontSize\") ?? element.getAttribute(\"Size\")),\n\t\t\tfillColor: objectColor(element, \"FillColor\"),\n\t\t\tcodes: childrenNamed(element, \"TextCode\").map(parseTextCode),\n\t\t\tglyphSubstitutions: childrenNamed(element, \"CGTransform\").map(parseGlyphSubstitution)\n\t\t};\n\t\tcase \"ImageObject\": return {\n\t\t\t...base,\n\t\t\tkind: \"image\",\n\t\t\tresourceId: element.getAttribute(\"ResourceID\")\n\t\t};\n\t\tcase \"PathObject\": return {\n\t\t\t...base,\n\t\t\tkind: \"path\",\n\t\t\tfill: element.getAttribute(\"Fill\") === \"true\",\n\t\t\tfillColor: objectColor(element, \"FillColor\"),\n\t\t\tstrokeColor: objectColor(element, \"StrokeColor\"),\n\t\t\tlineWidth: parseNumber(element.getAttribute(\"LineWidth\")),\n\t\t\tdashPattern: parseNumberList(element.getAttribute(\"DashPattern\")),\n\t\t\tcommands: parsePathCommands(firstChildNamed(element, \"AbbreviatedData\")?.textContent ?? null)\n\t\t};\n\t\tcase \"CompositeObject\": return {\n\t\t\t...base,\n\t\t\tkind: \"composite\",\n\t\t\treferenceId: element.getAttribute(\"ReferenceID\")\n\t\t};\n\t\tdefault: return null;\n\t}\n}\n/**\n* 对象颜色声明兼容两种形式:属性 `FillColor=\"128 0 0\"` 与子元素\n* `<FillColor Value=\"128 0 0\"/>`(新版数电票实证为子元素形式)。\n*/\nfunction objectColor(element, name) {\n\treturn parseOfdColor(element.getAttribute(name) ?? firstChildNamed(element, name)?.getAttribute(\"Value\") ?? null);\n}\n/** 解析 CGTransform:Glyphs 支持 ST_Array 的 `g n v` 压缩写法 */\nfunction parseGlyphSubstitution(element) {\n\treturn {\n\t\tcodePosition: parseNumber(element.getAttribute(\"CodePosition\")) ?? 0,\n\t\tcodeCount: parseNumber(element.getAttribute(\"CodeCount\")) ?? 0,\n\t\tglyphIds: parseDeltaList(firstChildNamed(element, \"Glyphs\")?.textContent ?? null)\n\t};\n}\nfunction parseTextCode(code) {\n\treturn {\n\t\tx: parseNumber(code.getAttribute(\"X\")),\n\t\ty: parseNumber(code.getAttribute(\"Y\")),\n\t\tdeltaX: parseDeltaList(code.getAttribute(\"DeltaX\")),\n\t\tdeltaY: parseDeltaList(code.getAttribute(\"DeltaY\")),\n\t\ttext: code.textContent ?? \"\"\n\t};\n}\n/**\n* 解析 TextCode 位移数组:数值按序对应相邻字符位移;`g n v` 是 ST_Array 的\n* 压缩写法(数电发票实证),表示 n 个连续位移均为 v。\n*/\nfunction parseDeltaList(value) {\n\tconst tokens = value?.trim().split(/[\\s,]+/).filter((token) => token !== \"\") ?? [];\n\tconst deltas = [];\n\tfor (let index = 0; index < tokens.length;) {\n\t\tif (tokens[index] === \"g\") {\n\t\t\tconst count = Number(tokens[index + 1]);\n\t\t\tconst repeated = Number(tokens[index + 2]);\n\t\t\tif (Number.isInteger(count) && count > 0 && Number.isFinite(repeated)) {\n\t\t\t\tfor (let repeat = 0; repeat < count; repeat++) deltas.push(repeated);\n\t\t\t\tindex += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tindex += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst delta = Number(tokens[index]);\n\t\tif (Number.isFinite(delta)) deltas.push(delta);\n\t\tindex += 1;\n\t}\n\treturn deltas;\n}\nconst PATH_ARITY = {\n\tM: 2,\n\tL: 2,\n\tC: 6,\n\tB: 4,\n\tQ: 4,\n\tZ: 0\n};\nfunction parsePathCommands(data) {\n\tconst tokens = data?.trim().split(/[\\s,]+/).filter((token) => token !== \"\") ?? [];\n\tconst commands = [];\n\tfor (let index = 0; index < tokens.length;) {\n\t\tconst type = tokens[index].toUpperCase();\n\t\tconst arity = PATH_ARITY[type];\n\t\tif (arity === void 0) {\n\t\t\tindex += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst points = tokens.slice(index + 1, index + 1 + arity).map(Number);\n\t\tif (points.length === arity && points.every((point) => Number.isFinite(point))) commands.push({\n\t\t\ttype,\n\t\t\tpoints\n\t\t});\n\t\tindex += 1 + arity;\n\t}\n\treturn commands;\n}\nfunction parseNumber(value) {\n\tconst numbers = parseNumberList(value);\n\treturn numbers.length > 0 ? numbers[0] : null;\n}\n//#endregion\nexport { parsePageContent };\n\n//# sourceMappingURL=page-objects.js.map"],"mappings":"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"}
|