@ym-print/core 0.1.0-rc.1 → 0.1.0-rc.3
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/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +2 -1
- package/dependency-licenses.json +13 -1
- package/dist/advanced-elements.d.ts +1 -1
- package/dist/data.d.ts +1 -0
- package/dist/font-file.js +15 -15
- package/dist/font-hkKjjlzV.js +153 -0
- package/dist/geometry.d.ts +14 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2026 -1692
- package/dist/plugins.d.ts +10 -2
- package/dist/print-time.d.ts +21 -0
- package/dist/protocol.d.ts +4 -0
- package/dist/text-limits.d.ts +8 -0
- package/package.json +3 -2
- package/third-party-licenses/re2js@2.9.1/LICENSE +21 -0
- package/dist/font-ToGNY599.js +0 -136
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ Web 页面可使用 `@ym-print/renderer-dom` 的 `BrowserFont` 作为测量器
|
|
|
47
47
|
| --- | --- |
|
|
48
48
|
| 字段路径 | JSON Pointer,例如 `/supplier/name` |
|
|
49
49
|
| 表格数据 | 列值使用行作用域,数组来源由模板指定 |
|
|
50
|
-
| 金额 |
|
|
50
|
+
| 金额 | 内部使用十进制字符串,例如 `"12.35"`;业务输入中的小数 `number` 在入口自动转换,安全整数保持不变 |
|
|
51
51
|
| 坐标与尺寸 | 微米,`1000 μm = 1 mm` |
|
|
52
52
|
| 字号 | 毫点,`1000 mpt = 1 pt` |
|
|
53
53
|
| 旋转 | 毫度,`1000 mdeg = 1°` |
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
@ym-print/core 0.1.0-rc.
|
|
3
|
+
@ym-print/core 0.1.0-rc.3 — original code: UNLICENSED.
|
|
4
4
|
|
|
5
5
|
Bundled code and external packages keep their original licenses. Optional peers are loaded through their documented opt-in entry.
|
|
6
6
|
|
|
@@ -16,4 +16,5 @@ Bundled code and external packages keep their original licenses. Optional peers
|
|
|
16
16
|
| json-schema-traverse@1.0.0 | MIT | external | [LICENSE](third-party-licenses/json-schema-traverse@1.0.0/LICENSE) |
|
|
17
17
|
| pako@1.0.11 | (MIT AND Zlib) | external | [LICENSE](third-party-licenses/pako@1.0.11/LICENSE) |
|
|
18
18
|
| parse5@8.0.1 | MIT | external | [LICENSE](third-party-licenses/parse5@8.0.1/LICENSE) |
|
|
19
|
+
| re2js@2.9.1 | MIT | external | [LICENSE](third-party-licenses/re2js@2.9.1/LICENSE) |
|
|
19
20
|
| require-from-string@2.0.2 | MIT | external | [license](third-party-licenses/require-from-string@2.0.2/license) |
|
package/dependency-licenses.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@ym-print/core",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.3",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"licenseScope": "original YmPrintUnit code only",
|
|
6
6
|
"dependencies": [
|
|
@@ -132,6 +132,18 @@
|
|
|
132
132
|
}
|
|
133
133
|
]
|
|
134
134
|
},
|
|
135
|
+
{
|
|
136
|
+
"name": "re2js",
|
|
137
|
+
"version": "2.9.1",
|
|
138
|
+
"license": "MIT",
|
|
139
|
+
"kind": "external",
|
|
140
|
+
"notices": [
|
|
141
|
+
{
|
|
142
|
+
"path": "third-party-licenses/re2js@2.9.1/LICENSE",
|
|
143
|
+
"sha256": "b80a94f2c3c0b8bd6af849511cef624ad9feecbc0151d08bacad86ebab4cb46e"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
},
|
|
135
147
|
{
|
|
136
148
|
"name": "require-from-string",
|
|
137
149
|
"version": "2.0.2",
|
|
@@ -3,4 +3,4 @@ export declare const richTextPlugin: ElementPlugin;
|
|
|
3
3
|
export declare const svgPlugin: ElementPlugin;
|
|
4
4
|
export declare const pdfPagePlugin: ElementPlugin;
|
|
5
5
|
export declare const seamSealPlugin: ElementPlugin;
|
|
6
|
-
export declare const advancedElements: readonly [ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin];
|
|
6
|
+
export declare const advancedElements: readonly [ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin];
|
package/dist/data.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Template, RuntimeInputs, EvalContext, NamedDataSources } from './p
|
|
|
2
2
|
export declare const pointerSegment: (value: string) => string;
|
|
3
3
|
/** Copy JSON without coercing dates, non-finite numbers, accessors, cycles or undefined to other values. */
|
|
4
4
|
export declare function snapshotJson<T>(input: T): T;
|
|
5
|
+
/** Runtime inputs normalize fractional numbers to plain decimal strings in a private snapshot. */
|
|
5
6
|
export declare function jsonObject(input: unknown, scope?: string): Record<string, unknown>;
|
|
6
7
|
export declare function validateInputSchema(schema: unknown): void;
|
|
7
8
|
export declare function validateData(schema: Record<string, unknown> | undefined, data: Record<string, unknown>, scope: 'root' | 'params'): void;
|
package/dist/font-file.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e,
|
|
1
|
+
import { a as e, h as t, v as n } from "./font-hkKjjlzV.js";
|
|
2
2
|
import r from "@pdf-lib/fontkit";
|
|
3
3
|
// src/font-file.ts
|
|
4
4
|
var i = class {
|
|
@@ -10,31 +10,31 @@ var i = class {
|
|
|
10
10
|
ascent;
|
|
11
11
|
descent;
|
|
12
12
|
font;
|
|
13
|
-
constructor(e,
|
|
14
|
-
if (this.bytes = e, this.sha256 =
|
|
13
|
+
constructor(e, n) {
|
|
14
|
+
if (this.bytes = e, this.sha256 = n, e.length < 12) throw new t("FONT_INVALID", "字体文件头不完整");
|
|
15
15
|
let i = new DataView(e.buffer, e.byteOffset, e.byteLength), a = String.fromCharCode(...e.subarray(0, 4));
|
|
16
|
-
if (a !== "OTTO" && a !== "true" && i.getUint32(0) !== 65536) throw new
|
|
16
|
+
if (a !== "OTTO" && a !== "true" && i.getUint32(0) !== 65536) throw new t("FONT_INVALID", "W2 支持独立 OTF/CFF1 和 TTF 字体,不支持字体集合");
|
|
17
17
|
let o = i.getUint16(4);
|
|
18
|
-
if (12 + o * 16 > e.length) throw new
|
|
19
|
-
for (let
|
|
20
|
-
let r = 12 +
|
|
21
|
-
if (a === "fvar" || a === "CFF2") throw new
|
|
22
|
-
if (i.getUint32(r + 8) + i.getUint32(r + 12) > e.length) throw new
|
|
18
|
+
if (12 + o * 16 > e.length) throw new t("FONT_INVALID", "字体目录不完整");
|
|
19
|
+
for (let n = 0; n < o; n++) {
|
|
20
|
+
let r = 12 + n * 16, a = String.fromCharCode(...e.subarray(r, r + 4));
|
|
21
|
+
if (a === "fvar" || a === "CFF2") throw new t("FONT_UNSUPPORTED", "可变字体和 CFF2 留待后续 profile 实现");
|
|
22
|
+
if (i.getUint32(r + 8) + i.getUint32(r + 12) > e.length) throw new t("FONT_INVALID", "字体表越界");
|
|
23
23
|
}
|
|
24
24
|
this.font = r.create(e), this.family = this.font.familyName ?? "Noto Sans CJK SC", this.unitsPerEm = this.font.unitsPerEm, this.ascent = this.font.ascent, this.descent = this.font.descent;
|
|
25
25
|
}
|
|
26
26
|
glyph(e) {
|
|
27
|
-
let
|
|
28
|
-
if (!this.font.hasGlyphForCodePoint(
|
|
29
|
-
if (!/^[\p{Script=Latin}\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Number}\p{Punctuation}\p{Symbol} ]$/u.test(e)) throw new
|
|
30
|
-
let r = this.font.glyphForCodePoint(
|
|
27
|
+
let n = e.codePointAt(0);
|
|
28
|
+
if (!this.font.hasGlyphForCodePoint(n)) throw new t("FONT_GLYPH_MISSING", `字体缺字:${e} U+${n.toString(16).toUpperCase()}`);
|
|
29
|
+
if (!/^[\p{Script=Latin}\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Number}\p{Punctuation}\p{Symbol} ]$/u.test(e)) throw new t("W0_UNSUPPORTED_SHAPING", `W0 不支持该字符的 shaping:U+${n.toString(16).toUpperCase()}`);
|
|
30
|
+
let r = this.font.glyphForCodePoint(n);
|
|
31
31
|
return {
|
|
32
32
|
id: r.id,
|
|
33
33
|
advance: r.advanceWidth
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
toUm(e,
|
|
37
|
-
return
|
|
36
|
+
toUm(e, t) {
|
|
37
|
+
return n(BigInt(e) * BigInt(t) * 25400n, BigInt(this.unitsPerEm) * 72000n);
|
|
38
38
|
}
|
|
39
39
|
measure(t, n, r = 0) {
|
|
40
40
|
let i = 0;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// src/protocol.ts
|
|
2
|
+
var e = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
nodeId;
|
|
5
|
+
path;
|
|
6
|
+
details;
|
|
7
|
+
dataPath;
|
|
8
|
+
scope;
|
|
9
|
+
issues;
|
|
10
|
+
constructor(e, t, n, r, i) {
|
|
11
|
+
super(t), this.code = e, this.nodeId = n, this.path = r, this.details = i, this.name = "PrintError", this.dataPath = i?.dataPath, this.scope = i?.scope, this.issues = i?.issues;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function t(t, n) {
|
|
15
|
+
if (!Number.isSafeInteger(t)) throw new e("INVALID_GEOMETRY", `${n} 必须为安全整数`);
|
|
16
|
+
}
|
|
17
|
+
function n(n, r) {
|
|
18
|
+
if (r <= 0n) throw new e("INVALID_GEOMETRY", "分母必须大于零");
|
|
19
|
+
let i = n < 0n ? -1n : 1n, a = n * i, o = Number(i * ((a + r / 2n) / r));
|
|
20
|
+
return t(o, "换算结果"), o;
|
|
21
|
+
}
|
|
22
|
+
var r = (e) => n(BigInt(e) * 25400n, 72000n), i = (e) => e * 72 / 25400, a = (e) => e / 1e3, o = {
|
|
23
|
+
valueChars: 1e5,
|
|
24
|
+
layoutChars: 2e6,
|
|
25
|
+
measureChars: 5e6,
|
|
26
|
+
lines: 1e4
|
|
27
|
+
};
|
|
28
|
+
function s(t) {
|
|
29
|
+
if (t.length > o.valueChars) throw new e("EXPR_LIMIT", "单段文字超过 10 万字符");
|
|
30
|
+
return t;
|
|
31
|
+
}
|
|
32
|
+
// src/font.ts
|
|
33
|
+
function c(t, n) {
|
|
34
|
+
if (!t || typeof t != "object" || Object.keys(t).some((e) => ![
|
|
35
|
+
"minSizeMpt",
|
|
36
|
+
"stepMpt",
|
|
37
|
+
"mode"
|
|
38
|
+
].includes(e)) || !Number.isSafeInteger(t.minSizeMpt) || t.minSizeMpt < 1e3 || t.minSizeMpt > 72e3 || t.stepMpt !== void 0 && (!Number.isSafeInteger(t.stepMpt) || t.stepMpt < 100 || t.stepMpt > 1e4) || t.mode !== void 0 && !["wrap", "single-line"].includes(t.mode) || n && t.minSizeMpt > n.sizeMpt) throw new e("TEXT_FIT_INVALID", "自适应最小字号需为 1–72 pt 且不大于初始字号,步长为 0.1–10 pt");
|
|
39
|
+
}
|
|
40
|
+
function l(t, n, r, i, a, o) {
|
|
41
|
+
if (s(t), !o) {
|
|
42
|
+
let e = C(t, n, i.sizeMpt, d(a, i), i.letterSpacingUm);
|
|
43
|
+
return {
|
|
44
|
+
lines: e,
|
|
45
|
+
style: y(i, a, e)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (!Number.isSafeInteger(n) || !Number.isSafeInteger(r) || n < 1 || r < 1) throw new e("TEXT_FIT_INVALID", "文字自适应区域需为正整数");
|
|
49
|
+
c(o, i);
|
|
50
|
+
let l = o.stepMpt ?? 500, u = Math.floor((i.sizeMpt - o.minSizeMpt) / l), f = i.sizeMpt, p = (s) => {
|
|
51
|
+
let c = {
|
|
52
|
+
...i,
|
|
53
|
+
sizeMpt: s,
|
|
54
|
+
lineHeightMpt: Math.max(1e3, Math.round(i.lineHeightMpt * s / f))
|
|
55
|
+
}, l = d(a, c);
|
|
56
|
+
try {
|
|
57
|
+
let e = o.mode === "single-line" ? t.includes("\n") ? void 0 : [t] : C(t, n, s, l, c.letterSpacingUm);
|
|
58
|
+
return !e || e.some((e) => l.measure(e, s, c.letterSpacingUm) > n) || e.length * _(c, a, e.join("")).heightUm > r ? void 0 : {
|
|
59
|
+
lines: e,
|
|
60
|
+
style: y(c, a, e)
|
|
61
|
+
};
|
|
62
|
+
} catch (t) {
|
|
63
|
+
if (t instanceof e && t.code === "LAYOUT_OVERFLOW") return;
|
|
64
|
+
throw t;
|
|
65
|
+
}
|
|
66
|
+
}, m = p(f);
|
|
67
|
+
if (m) return m;
|
|
68
|
+
let h = 0, g = u, v;
|
|
69
|
+
for (; h <= g;) {
|
|
70
|
+
let e = Math.floor((h + g) / 2), t = p(o.minSizeMpt + e * l);
|
|
71
|
+
t ? (v = t, h = e + 1) : g = e - 1;
|
|
72
|
+
}
|
|
73
|
+
if (!v) throw new e("TEXT_FIT_FAILED", "缩到最小字号仍无法放入文字框,请增大尺寸或调整最小字号");
|
|
74
|
+
return v;
|
|
75
|
+
}
|
|
76
|
+
var u = "\"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", Arial, sans-serif", d = (e, t) => e.forStyle?.(t) ?? e;
|
|
77
|
+
function f(t) {
|
|
78
|
+
if (!Number.isSafeInteger(t) || t < -5e3 || t > 2e4) throw new e("TEXT_SPACING_INVALID", "字距需为 -5–20 mm 的整数微米值");
|
|
79
|
+
}
|
|
80
|
+
var p = new Intl.Segmenter("und", { granularity: "grapheme" }), m = new Intl.Segmenter("und", { granularity: "word" }), h = (e) => Array.from(p.segment(s(e)), (e) => e.segment), g = (e) => Array.from(m.segment(s(e)), (e) => e.segment);
|
|
81
|
+
function _(e, t, n = "") {
|
|
82
|
+
let r = d(t, e), i = n ? r.metrics?.(n, e.sizeMpt) : void 0, a = r.toUm(r.ascent - r.descent, e.sizeMpt), o = r.toUm(r.ascent, e.sizeMpt), s = a - o, c = i && i.ascentUm > o + 2 ? i.ascentUm : o, l = i && i.descentUm > s + 2 ? i.descentUm : s, u = Math.round(e.lineHeightMpt * 25400 / 72e3), f = r.system ? Math.max(u, c + l) : u;
|
|
83
|
+
return {
|
|
84
|
+
heightUm: f,
|
|
85
|
+
baselineUm: Math.round((f - c - l) / 2) + c
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function v(e, t) {
|
|
89
|
+
return _(e, t).heightUm;
|
|
90
|
+
}
|
|
91
|
+
function y(e, t, n) {
|
|
92
|
+
let r = _(e, t, n.join("")).heightUm;
|
|
93
|
+
return r > v(e, t) ? {
|
|
94
|
+
...e,
|
|
95
|
+
lineHeightMpt: Math.ceil(r * 72e3 / 25400)
|
|
96
|
+
} : e;
|
|
97
|
+
}
|
|
98
|
+
function b(t) {
|
|
99
|
+
if (typeof t != "string" || !t.trim() || t.length > 256 || /[;{}<>\\()@:\u0000-\u001f]/u.test(t) || [
|
|
100
|
+
"inherit",
|
|
101
|
+
"initial",
|
|
102
|
+
"unset",
|
|
103
|
+
"revert",
|
|
104
|
+
"revert-layer"
|
|
105
|
+
].includes(t.trim().toLowerCase())) throw new e("FONT_FAMILY_INVALID", "字体名称需要 1–256 字,不能包含样式代码或控制字符;继承字体请留空");
|
|
106
|
+
}
|
|
107
|
+
var x = /^[,。!?:;、)》】」』,.!?;:)]$/u, S = /[(《【「『(\[]$/u;
|
|
108
|
+
function C(t, n, r, i, a = 0) {
|
|
109
|
+
s(t);
|
|
110
|
+
let c = o.measureChars, l = (t) => {
|
|
111
|
+
if ((c -= t.length) < 0) throw new e("TEXT_LIMIT", "文字测量工作量超过限制,请缩短内容或减小文字框宽度");
|
|
112
|
+
return i.measure(t, r, a);
|
|
113
|
+
};
|
|
114
|
+
if (f(a), n <= 0) throw new e("LAYOUT_OVERFLOW", "文字可用宽度必须大于零");
|
|
115
|
+
let u = [], d = (t) => {
|
|
116
|
+
if (u.length >= o.lines) throw new e("TEXT_LIMIT", "单段文字超过 10000 行");
|
|
117
|
+
u.push(t);
|
|
118
|
+
};
|
|
119
|
+
for (let r of t.normalize("NFC").replace(/\r\n?/g, "\n").split("\n")) {
|
|
120
|
+
if (r === "") {
|
|
121
|
+
d("");
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
let t = "", i = g(r);
|
|
125
|
+
for (let r of i) if (!t && l(r) <= n) t = r;
|
|
126
|
+
else if (t && l(t + r) <= n) t += r;
|
|
127
|
+
else {
|
|
128
|
+
if (t && l(r) <= n && !x.test(r)) {
|
|
129
|
+
let e = "";
|
|
130
|
+
if (S.test(t)) {
|
|
131
|
+
let n = h(t);
|
|
132
|
+
e = n.pop(), t = n.join("");
|
|
133
|
+
}
|
|
134
|
+
t && d(t.replace(/[ \t]+$/u, "")), t = e;
|
|
135
|
+
}
|
|
136
|
+
for (let i of h(r)) {
|
|
137
|
+
if (l(i) > n) throw new e("LAYOUT_OVERFLOW", `单字宽度超过文字框:${i}`);
|
|
138
|
+
if (t && l(t + i) > n) {
|
|
139
|
+
let r = "";
|
|
140
|
+
if (x.test(i) || S.test(t)) {
|
|
141
|
+
let e = h(t);
|
|
142
|
+
r = e.pop(), t = e.join("");
|
|
143
|
+
}
|
|
144
|
+
if (t && d(t.replace(/[ \t]+$/u, "")), t = r, l(t + i) > n) throw new e("LAYOUT_OVERFLOW", "标点禁则需要更宽的文字框");
|
|
145
|
+
}
|
|
146
|
+
t += i;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
t && d(t.replace(/[ \t]+$/u, ""));
|
|
150
|
+
}
|
|
151
|
+
return u;
|
|
152
|
+
}
|
|
153
|
+
export { r as _, h as a, i as b, g as c, f as d, C as f, t as g, e as h, y as i, c as l, s as m, l as n, _ as o, o as p, d as r, v as s, u as t, b as u, n as v, a as y };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PrintNode } from './protocol.js';
|
|
2
|
+
export interface FrameBounds {
|
|
3
|
+
xUm: number;
|
|
4
|
+
yUm: number;
|
|
5
|
+
widthUm: number;
|
|
6
|
+
heightUm: number;
|
|
7
|
+
}
|
|
8
|
+
/** Axis-aligned extent after rotating a box around the renderer's pivot. */
|
|
9
|
+
export declare function rotateBounds(bounds: FrameBounds, rotationMdeg?: number, pivot?: {
|
|
10
|
+
xUm: number;
|
|
11
|
+
yUm: number;
|
|
12
|
+
}): FrameBounds;
|
|
13
|
+
/** Content can grow below the frame, while rotation still uses the original frame center. */
|
|
14
|
+
export declare function nodeFrameBounds(node: PrintNode, heightUm?: number): FrameBounds;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './protocol.js';
|
|
2
|
+
export * from './geometry.js';
|
|
2
3
|
export * from './expression.js';
|
|
3
4
|
export * from './font.js';
|
|
4
5
|
export * from './plugins.js';
|
|
@@ -18,6 +19,8 @@ export * from './vector.js';
|
|
|
18
19
|
export * from './advanced-elements.js';
|
|
19
20
|
export * from './imposition.js';
|
|
20
21
|
export * from './stamp.js';
|
|
22
|
+
export * from './print-time.js';
|
|
21
23
|
export * from './functions.js';
|
|
22
24
|
export * from './html.js';
|
|
23
25
|
export * from './composite-cell.js';
|
|
26
|
+
export { TEXT_LIMITS } from './text-limits.js';
|