pdf-codec 4.2.0 → 4.4.0
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 +4 -4
- package/dist/content-write.cjs +29 -7
- package/dist/content-write.d.cts +9 -2
- package/dist/content-write.d.ts +9 -2
- package/dist/content-write.js +29 -7
- package/dist/{embedded-font-fREdbxnr.d.ts → embedded-font-B4p9a3O3.d.ts} +3 -1
- package/dist/{embedded-font-BU6Jgcof.d.cts → embedded-font-oc65VGlr.d.cts} +3 -1
- package/dist/embedded-font-write.d.cts +2 -2
- package/dist/embedded-font-write.d.ts +2 -2
- package/dist/embedded-font.cjs +46 -15
- package/dist/embedded-font.d.cts +1 -1
- package/dist/embedded-font.d.ts +1 -1
- package/dist/embedded-font.js +46 -15
- package/dist/font-registry.d.cts +1 -1
- package/dist/font-registry.d.ts +1 -1
- package/dist/gsub-table-BRTQ8EUW.d.ts +10 -0
- package/dist/gsub-table-URczLd85.d.cts +10 -0
- package/dist/gsub-table.cjs +225 -0
- package/dist/gsub-table.d.cts +2 -0
- package/dist/gsub-table.d.ts +2 -0
- package/dist/gsub-table.js +224 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/math-font-write.cjs +1 -1
- package/dist/math-font-write.js +1 -1
- package/dist/sfnt-subset.cjs +10 -3
- package/dist/sfnt-subset.d.cts +1 -1
- package/dist/sfnt-subset.d.ts +1 -1
- package/dist/sfnt-subset.js +10 -3
- package/dist/tounicode.cjs +8 -3
- package/dist/tounicode.d.cts +1 -1
- package/dist/tounicode.d.ts +1 -1
- package/dist/tounicode.js +8 -3
- package/dist/write.cjs +245 -4
- package/dist/write.d.cts +1 -1
- package/dist/write.d.ts +1 -1
- package/dist/write.js +245 -4
- package/package.json +1 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_sfnt = require("./sfnt.cjs");
|
|
3
|
+
const require_ot_layout_common = require("./ot-layout-common.cjs");
|
|
4
|
+
//#region src/gsub-table.ts
|
|
5
|
+
const LIGATURE_FEATURE_TAGS = ["liga", "rlig"];
|
|
6
|
+
const GSUB_HEADER_SIZE = 10;
|
|
7
|
+
const SCRIPT_RECORD_SIZE = 6;
|
|
8
|
+
const FEATURE_RECORD_SIZE = 6;
|
|
9
|
+
const LANG_SYS_HEADER_SIZE = 6;
|
|
10
|
+
const FEATURE_HEADER_SIZE = 4;
|
|
11
|
+
const LOOKUP_HEADER_SIZE = 6;
|
|
12
|
+
const LOOKUP_TYPE_SINGLE_SUBST = 1;
|
|
13
|
+
const LOOKUP_TYPE_LIGATURE_SUBST = 4;
|
|
14
|
+
const LOOKUP_TYPE_EXTENSION_SUBST = 7;
|
|
15
|
+
const EXTENSION_SUBST_HEADER_SIZE = 8;
|
|
16
|
+
const PREFERRED_SCRIPT_TAGS = ["latn", "DFLT"];
|
|
17
|
+
function readTag(bytes, offset) {
|
|
18
|
+
return String.fromCharCode(require_sfnt.u16(bytes, offset) >> 8, require_sfnt.u16(bytes, offset) & 255, require_sfnt.u16(bytes, offset + 2) >> 8, require_sfnt.u16(bytes, offset + 2) & 255);
|
|
19
|
+
}
|
|
20
|
+
const SINGLE_SUBST_FORMAT_1_SIZE = 6;
|
|
21
|
+
function parseSingleSubstFormat1(bytes, subtableOffset) {
|
|
22
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_1_SIZE)) return;
|
|
23
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
|
|
24
|
+
if (coverage === void 0) return;
|
|
25
|
+
const delta = require_sfnt.i16(bytes, subtableOffset + 4);
|
|
26
|
+
return {
|
|
27
|
+
kind: "single",
|
|
28
|
+
lookup: (glyphId) => {
|
|
29
|
+
if (coverage.coverageIndex(glyphId) === void 0) return;
|
|
30
|
+
return glyphId + delta;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const SINGLE_SUBST_FORMAT_2_HEADER_SIZE = 6;
|
|
35
|
+
function parseSingleSubstFormat2(bytes, subtableOffset) {
|
|
36
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_2_HEADER_SIZE)) return;
|
|
37
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
|
|
38
|
+
if (coverage === void 0) return;
|
|
39
|
+
const glyphCount = require_sfnt.u16(bytes, subtableOffset + 4);
|
|
40
|
+
const substitutesOffset = subtableOffset + SINGLE_SUBST_FORMAT_2_HEADER_SIZE;
|
|
41
|
+
if (!require_sfnt.hasBytes(bytes, substitutesOffset, glyphCount * 2)) return;
|
|
42
|
+
return {
|
|
43
|
+
kind: "single",
|
|
44
|
+
lookup: (glyphId) => {
|
|
45
|
+
const coverageIndex = coverage.coverageIndex(glyphId);
|
|
46
|
+
if (coverageIndex === void 0 || coverageIndex >= glyphCount) return;
|
|
47
|
+
return require_sfnt.u16(bytes, substitutesOffset + coverageIndex * 2);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const LIGATURE_SUBST_FORMAT_1_HEADER_SIZE = 6;
|
|
52
|
+
const LIGATURE_SET_HEADER_SIZE = 2;
|
|
53
|
+
const LIGATURE_HEADER_PREFIX_SIZE = 4;
|
|
54
|
+
function parseLigatureSubstFormat1(bytes, subtableOffset) {
|
|
55
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, LIGATURE_SUBST_FORMAT_1_HEADER_SIZE)) return;
|
|
56
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
|
|
57
|
+
if (coverage === void 0) return;
|
|
58
|
+
const ligSetCount = require_sfnt.u16(bytes, subtableOffset + 4);
|
|
59
|
+
const ligSetOffsetsOffset = subtableOffset + LIGATURE_SUBST_FORMAT_1_HEADER_SIZE;
|
|
60
|
+
if (!require_sfnt.hasBytes(bytes, ligSetOffsetsOffset, ligSetCount * 2)) return;
|
|
61
|
+
return {
|
|
62
|
+
kind: "ligature",
|
|
63
|
+
match: (glyphIds, index) => {
|
|
64
|
+
const coverageIndex = coverage.coverageIndex(glyphIds[index]);
|
|
65
|
+
if (coverageIndex === void 0 || coverageIndex >= ligSetCount) return;
|
|
66
|
+
const ligSetOffset = subtableOffset + require_sfnt.u16(bytes, ligSetOffsetsOffset + coverageIndex * 2);
|
|
67
|
+
if (!require_sfnt.hasBytes(bytes, ligSetOffset, LIGATURE_SET_HEADER_SIZE)) return;
|
|
68
|
+
const ligatureCount = require_sfnt.u16(bytes, ligSetOffset);
|
|
69
|
+
const ligatureOffsetsOffset = ligSetOffset + LIGATURE_SET_HEADER_SIZE;
|
|
70
|
+
if (!require_sfnt.hasBytes(bytes, ligatureOffsetsOffset, ligatureCount * 2)) return;
|
|
71
|
+
for (let i = 0; i < ligatureCount; i++) {
|
|
72
|
+
const ligatureOffset = ligSetOffset + require_sfnt.u16(bytes, ligatureOffsetsOffset + i * 2);
|
|
73
|
+
if (!require_sfnt.hasBytes(bytes, ligatureOffset, LIGATURE_HEADER_PREFIX_SIZE)) continue;
|
|
74
|
+
const ligatureGlyph = require_sfnt.u16(bytes, ligatureOffset);
|
|
75
|
+
const componentCount = require_sfnt.u16(bytes, ligatureOffset + 2);
|
|
76
|
+
if (componentCount === 0) continue;
|
|
77
|
+
const componentsOffset = ligatureOffset + LIGATURE_HEADER_PREFIX_SIZE;
|
|
78
|
+
if (!require_sfnt.hasBytes(bytes, componentsOffset, (componentCount - 1) * 2)) continue;
|
|
79
|
+
if (index + componentCount > glyphIds.length) continue;
|
|
80
|
+
let matches = true;
|
|
81
|
+
for (let c = 1; c < componentCount; c++) if (glyphIds[index + c] !== require_sfnt.u16(bytes, componentsOffset + (c - 1) * 2)) {
|
|
82
|
+
matches = false;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
if (matches) return {
|
|
86
|
+
ligatureGlyph,
|
|
87
|
+
componentCount
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function parseSubtable(bytes, lookupType, subtableOffset) {
|
|
94
|
+
if (lookupType === LOOKUP_TYPE_EXTENSION_SUBST) {
|
|
95
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, EXTENSION_SUBST_HEADER_SIZE) || require_sfnt.u16(bytes, subtableOffset) !== 1) return;
|
|
96
|
+
const extensionLookupType = require_sfnt.u16(bytes, subtableOffset + 2);
|
|
97
|
+
if (extensionLookupType === LOOKUP_TYPE_EXTENSION_SUBST) return;
|
|
98
|
+
return parseSubtable(bytes, extensionLookupType, subtableOffset + require_sfnt.u32(bytes, subtableOffset + 4));
|
|
99
|
+
}
|
|
100
|
+
if (lookupType === LOOKUP_TYPE_SINGLE_SUBST) {
|
|
101
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
|
|
102
|
+
const substFormat = require_sfnt.u16(bytes, subtableOffset);
|
|
103
|
+
if (substFormat === 1) return parseSingleSubstFormat1(bytes, subtableOffset);
|
|
104
|
+
if (substFormat === 2) return parseSingleSubstFormat2(bytes, subtableOffset);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (lookupType === LOOKUP_TYPE_LIGATURE_SUBST) {
|
|
108
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
|
|
109
|
+
if (require_sfnt.u16(bytes, subtableOffset) !== 1) return;
|
|
110
|
+
return parseLigatureSubstFormat1(bytes, subtableOffset);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function findScriptOffset(bytes, scriptListOffset) {
|
|
114
|
+
if (!require_sfnt.hasBytes(bytes, scriptListOffset, 2)) return;
|
|
115
|
+
const scriptCount = require_sfnt.u16(bytes, scriptListOffset);
|
|
116
|
+
const recordsOffset = scriptListOffset + 2;
|
|
117
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, scriptCount * SCRIPT_RECORD_SIZE) || scriptCount === 0) return;
|
|
118
|
+
for (const wanted of PREFERRED_SCRIPT_TAGS) for (let i = 0; i < scriptCount; i++) {
|
|
119
|
+
const recordOffset = recordsOffset + i * SCRIPT_RECORD_SIZE;
|
|
120
|
+
if (readTag(bytes, recordOffset) === wanted) return scriptListOffset + require_sfnt.u16(bytes, recordOffset + 4);
|
|
121
|
+
}
|
|
122
|
+
return scriptListOffset + require_sfnt.u16(bytes, recordsOffset + 4);
|
|
123
|
+
}
|
|
124
|
+
function parseDefaultLangSysFeatureIndices(bytes, scriptOffset) {
|
|
125
|
+
if (!require_sfnt.hasBytes(bytes, scriptOffset, 2)) return [];
|
|
126
|
+
const defaultLangSysOffset = require_sfnt.u16(bytes, scriptOffset);
|
|
127
|
+
if (defaultLangSysOffset === 0) return [];
|
|
128
|
+
const langSysOffset = scriptOffset + defaultLangSysOffset;
|
|
129
|
+
if (!require_sfnt.hasBytes(bytes, langSysOffset, LANG_SYS_HEADER_SIZE)) return [];
|
|
130
|
+
const featureIndexCount = require_sfnt.u16(bytes, langSysOffset + 4);
|
|
131
|
+
const indicesOffset = langSysOffset + LANG_SYS_HEADER_SIZE;
|
|
132
|
+
if (!require_sfnt.hasBytes(bytes, indicesOffset, featureIndexCount * 2)) return [];
|
|
133
|
+
const indices = [];
|
|
134
|
+
for (let i = 0; i < featureIndexCount; i++) indices.push(require_sfnt.u16(bytes, indicesOffset + i * 2));
|
|
135
|
+
return indices;
|
|
136
|
+
}
|
|
137
|
+
function collectLigatureLookupIndices(bytes, featureListOffset, featureIndices) {
|
|
138
|
+
if (!require_sfnt.hasBytes(bytes, featureListOffset, 2)) return [];
|
|
139
|
+
const featureCount = require_sfnt.u16(bytes, featureListOffset);
|
|
140
|
+
const recordsOffset = featureListOffset + 2;
|
|
141
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, featureCount * FEATURE_RECORD_SIZE)) return [];
|
|
142
|
+
const lookupIndices = [];
|
|
143
|
+
const seen = /* @__PURE__ */ new Set();
|
|
144
|
+
for (const featureIndex of featureIndices) {
|
|
145
|
+
if (featureIndex >= featureCount) continue;
|
|
146
|
+
const recordOffset = recordsOffset + featureIndex * FEATURE_RECORD_SIZE;
|
|
147
|
+
const tag = readTag(bytes, recordOffset);
|
|
148
|
+
if (!LIGATURE_FEATURE_TAGS.includes(tag)) continue;
|
|
149
|
+
const featureOffset = featureListOffset + require_sfnt.u16(bytes, recordOffset + 4);
|
|
150
|
+
if (!require_sfnt.hasBytes(bytes, featureOffset, FEATURE_HEADER_SIZE)) continue;
|
|
151
|
+
const lookupIndexCount = require_sfnt.u16(bytes, featureOffset + 2);
|
|
152
|
+
const indicesOffset = featureOffset + FEATURE_HEADER_SIZE;
|
|
153
|
+
if (!require_sfnt.hasBytes(bytes, indicesOffset, lookupIndexCount * 2)) continue;
|
|
154
|
+
for (let i = 0; i < lookupIndexCount; i++) {
|
|
155
|
+
const lookupIndex = require_sfnt.u16(bytes, indicesOffset + i * 2);
|
|
156
|
+
if (!seen.has(lookupIndex)) {
|
|
157
|
+
seen.add(lookupIndex);
|
|
158
|
+
lookupIndices.push(lookupIndex);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return lookupIndices;
|
|
163
|
+
}
|
|
164
|
+
function buildGsubShaper(font) {
|
|
165
|
+
const bytes = require_sfnt.sfntTableBytes(font, "GSUB");
|
|
166
|
+
if (bytes === void 0 || !require_sfnt.hasBytes(bytes, 0, GSUB_HEADER_SIZE) || require_sfnt.u16(bytes, 0) !== 1) return;
|
|
167
|
+
const scriptOffset = findScriptOffset(bytes, require_sfnt.u16(bytes, 4));
|
|
168
|
+
if (scriptOffset === void 0) return;
|
|
169
|
+
const lookupIndices = collectLigatureLookupIndices(bytes, require_sfnt.u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset));
|
|
170
|
+
if (lookupIndices.length === 0) return;
|
|
171
|
+
const lookupListOffset = require_sfnt.u16(bytes, 8);
|
|
172
|
+
if (!require_sfnt.hasBytes(bytes, lookupListOffset, 2)) return;
|
|
173
|
+
const lookupCount = require_sfnt.u16(bytes, lookupListOffset);
|
|
174
|
+
const lookupOffsetsOffset = lookupListOffset + 2;
|
|
175
|
+
if (!require_sfnt.hasBytes(bytes, lookupOffsetsOffset, lookupCount * 2)) return;
|
|
176
|
+
const subtables = [];
|
|
177
|
+
for (const lookupIndex of lookupIndices) {
|
|
178
|
+
if (lookupIndex >= lookupCount) continue;
|
|
179
|
+
const lookupOffset = lookupListOffset + require_sfnt.u16(bytes, lookupOffsetsOffset + lookupIndex * 2);
|
|
180
|
+
if (!require_sfnt.hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) continue;
|
|
181
|
+
if (require_sfnt.u16(bytes, lookupOffset + 2) !== 0) continue;
|
|
182
|
+
const lookupType = require_sfnt.u16(bytes, lookupOffset);
|
|
183
|
+
const subTableCount = require_sfnt.u16(bytes, lookupOffset + 4);
|
|
184
|
+
const subtableOffsetsOffset = lookupOffset + LOOKUP_HEADER_SIZE;
|
|
185
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffsetsOffset, subTableCount * 2)) continue;
|
|
186
|
+
for (let i = 0; i < subTableCount; i++) {
|
|
187
|
+
const subtable = parseSubtable(bytes, lookupType, lookupOffset + require_sfnt.u16(bytes, subtableOffsetsOffset + i * 2));
|
|
188
|
+
if (subtable !== void 0) subtables.push(subtable);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (subtables.length === 0) return;
|
|
192
|
+
return (glyphIds) => {
|
|
193
|
+
const shaped = [];
|
|
194
|
+
const spans = [];
|
|
195
|
+
let index = 0;
|
|
196
|
+
outer: while (index < glyphIds.length) {
|
|
197
|
+
for (const subtable of subtables) if (subtable.kind === "single") {
|
|
198
|
+
const substitute = subtable.lookup(glyphIds[index]);
|
|
199
|
+
if (substitute !== void 0) {
|
|
200
|
+
shaped.push(substitute);
|
|
201
|
+
spans.push(1);
|
|
202
|
+
index += 1;
|
|
203
|
+
continue outer;
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
const match = subtable.match(glyphIds, index);
|
|
207
|
+
if (match !== void 0) {
|
|
208
|
+
shaped.push(match.ligatureGlyph);
|
|
209
|
+
spans.push(match.componentCount);
|
|
210
|
+
index += match.componentCount;
|
|
211
|
+
continue outer;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
shaped.push(glyphIds[index]);
|
|
215
|
+
spans.push(1);
|
|
216
|
+
index += 1;
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
glyphIds: shaped,
|
|
220
|
+
spans
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
//#endregion
|
|
225
|
+
exports.buildGsubShaper = buildGsubShaper;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { hasBytes, i16, sfntTableBytes, u16, u32 } from "./sfnt.js";
|
|
2
|
+
import { parseCoverage } from "./ot-layout-common.js";
|
|
3
|
+
//#region src/gsub-table.ts
|
|
4
|
+
const LIGATURE_FEATURE_TAGS = ["liga", "rlig"];
|
|
5
|
+
const GSUB_HEADER_SIZE = 10;
|
|
6
|
+
const SCRIPT_RECORD_SIZE = 6;
|
|
7
|
+
const FEATURE_RECORD_SIZE = 6;
|
|
8
|
+
const LANG_SYS_HEADER_SIZE = 6;
|
|
9
|
+
const FEATURE_HEADER_SIZE = 4;
|
|
10
|
+
const LOOKUP_HEADER_SIZE = 6;
|
|
11
|
+
const LOOKUP_TYPE_SINGLE_SUBST = 1;
|
|
12
|
+
const LOOKUP_TYPE_LIGATURE_SUBST = 4;
|
|
13
|
+
const LOOKUP_TYPE_EXTENSION_SUBST = 7;
|
|
14
|
+
const EXTENSION_SUBST_HEADER_SIZE = 8;
|
|
15
|
+
const PREFERRED_SCRIPT_TAGS = ["latn", "DFLT"];
|
|
16
|
+
function readTag(bytes, offset) {
|
|
17
|
+
return String.fromCharCode(u16(bytes, offset) >> 8, u16(bytes, offset) & 255, u16(bytes, offset + 2) >> 8, u16(bytes, offset + 2) & 255);
|
|
18
|
+
}
|
|
19
|
+
const SINGLE_SUBST_FORMAT_1_SIZE = 6;
|
|
20
|
+
function parseSingleSubstFormat1(bytes, subtableOffset) {
|
|
21
|
+
if (!hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_1_SIZE)) return;
|
|
22
|
+
const coverage = parseCoverage(bytes, subtableOffset + u16(bytes, subtableOffset + 2));
|
|
23
|
+
if (coverage === void 0) return;
|
|
24
|
+
const delta = i16(bytes, subtableOffset + 4);
|
|
25
|
+
return {
|
|
26
|
+
kind: "single",
|
|
27
|
+
lookup: (glyphId) => {
|
|
28
|
+
if (coverage.coverageIndex(glyphId) === void 0) return;
|
|
29
|
+
return glyphId + delta;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const SINGLE_SUBST_FORMAT_2_HEADER_SIZE = 6;
|
|
34
|
+
function parseSingleSubstFormat2(bytes, subtableOffset) {
|
|
35
|
+
if (!hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_2_HEADER_SIZE)) return;
|
|
36
|
+
const coverage = parseCoverage(bytes, subtableOffset + u16(bytes, subtableOffset + 2));
|
|
37
|
+
if (coverage === void 0) return;
|
|
38
|
+
const glyphCount = u16(bytes, subtableOffset + 4);
|
|
39
|
+
const substitutesOffset = subtableOffset + SINGLE_SUBST_FORMAT_2_HEADER_SIZE;
|
|
40
|
+
if (!hasBytes(bytes, substitutesOffset, glyphCount * 2)) return;
|
|
41
|
+
return {
|
|
42
|
+
kind: "single",
|
|
43
|
+
lookup: (glyphId) => {
|
|
44
|
+
const coverageIndex = coverage.coverageIndex(glyphId);
|
|
45
|
+
if (coverageIndex === void 0 || coverageIndex >= glyphCount) return;
|
|
46
|
+
return u16(bytes, substitutesOffset + coverageIndex * 2);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const LIGATURE_SUBST_FORMAT_1_HEADER_SIZE = 6;
|
|
51
|
+
const LIGATURE_SET_HEADER_SIZE = 2;
|
|
52
|
+
const LIGATURE_HEADER_PREFIX_SIZE = 4;
|
|
53
|
+
function parseLigatureSubstFormat1(bytes, subtableOffset) {
|
|
54
|
+
if (!hasBytes(bytes, subtableOffset, LIGATURE_SUBST_FORMAT_1_HEADER_SIZE)) return;
|
|
55
|
+
const coverage = parseCoverage(bytes, subtableOffset + u16(bytes, subtableOffset + 2));
|
|
56
|
+
if (coverage === void 0) return;
|
|
57
|
+
const ligSetCount = u16(bytes, subtableOffset + 4);
|
|
58
|
+
const ligSetOffsetsOffset = subtableOffset + LIGATURE_SUBST_FORMAT_1_HEADER_SIZE;
|
|
59
|
+
if (!hasBytes(bytes, ligSetOffsetsOffset, ligSetCount * 2)) return;
|
|
60
|
+
return {
|
|
61
|
+
kind: "ligature",
|
|
62
|
+
match: (glyphIds, index) => {
|
|
63
|
+
const coverageIndex = coverage.coverageIndex(glyphIds[index]);
|
|
64
|
+
if (coverageIndex === void 0 || coverageIndex >= ligSetCount) return;
|
|
65
|
+
const ligSetOffset = subtableOffset + u16(bytes, ligSetOffsetsOffset + coverageIndex * 2);
|
|
66
|
+
if (!hasBytes(bytes, ligSetOffset, LIGATURE_SET_HEADER_SIZE)) return;
|
|
67
|
+
const ligatureCount = u16(bytes, ligSetOffset);
|
|
68
|
+
const ligatureOffsetsOffset = ligSetOffset + LIGATURE_SET_HEADER_SIZE;
|
|
69
|
+
if (!hasBytes(bytes, ligatureOffsetsOffset, ligatureCount * 2)) return;
|
|
70
|
+
for (let i = 0; i < ligatureCount; i++) {
|
|
71
|
+
const ligatureOffset = ligSetOffset + u16(bytes, ligatureOffsetsOffset + i * 2);
|
|
72
|
+
if (!hasBytes(bytes, ligatureOffset, LIGATURE_HEADER_PREFIX_SIZE)) continue;
|
|
73
|
+
const ligatureGlyph = u16(bytes, ligatureOffset);
|
|
74
|
+
const componentCount = u16(bytes, ligatureOffset + 2);
|
|
75
|
+
if (componentCount === 0) continue;
|
|
76
|
+
const componentsOffset = ligatureOffset + LIGATURE_HEADER_PREFIX_SIZE;
|
|
77
|
+
if (!hasBytes(bytes, componentsOffset, (componentCount - 1) * 2)) continue;
|
|
78
|
+
if (index + componentCount > glyphIds.length) continue;
|
|
79
|
+
let matches = true;
|
|
80
|
+
for (let c = 1; c < componentCount; c++) if (glyphIds[index + c] !== u16(bytes, componentsOffset + (c - 1) * 2)) {
|
|
81
|
+
matches = false;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (matches) return {
|
|
85
|
+
ligatureGlyph,
|
|
86
|
+
componentCount
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseSubtable(bytes, lookupType, subtableOffset) {
|
|
93
|
+
if (lookupType === LOOKUP_TYPE_EXTENSION_SUBST) {
|
|
94
|
+
if (!hasBytes(bytes, subtableOffset, EXTENSION_SUBST_HEADER_SIZE) || u16(bytes, subtableOffset) !== 1) return;
|
|
95
|
+
const extensionLookupType = u16(bytes, subtableOffset + 2);
|
|
96
|
+
if (extensionLookupType === LOOKUP_TYPE_EXTENSION_SUBST) return;
|
|
97
|
+
return parseSubtable(bytes, extensionLookupType, subtableOffset + u32(bytes, subtableOffset + 4));
|
|
98
|
+
}
|
|
99
|
+
if (lookupType === LOOKUP_TYPE_SINGLE_SUBST) {
|
|
100
|
+
if (!hasBytes(bytes, subtableOffset, 2)) return;
|
|
101
|
+
const substFormat = u16(bytes, subtableOffset);
|
|
102
|
+
if (substFormat === 1) return parseSingleSubstFormat1(bytes, subtableOffset);
|
|
103
|
+
if (substFormat === 2) return parseSingleSubstFormat2(bytes, subtableOffset);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (lookupType === LOOKUP_TYPE_LIGATURE_SUBST) {
|
|
107
|
+
if (!hasBytes(bytes, subtableOffset, 2)) return;
|
|
108
|
+
if (u16(bytes, subtableOffset) !== 1) return;
|
|
109
|
+
return parseLigatureSubstFormat1(bytes, subtableOffset);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function findScriptOffset(bytes, scriptListOffset) {
|
|
113
|
+
if (!hasBytes(bytes, scriptListOffset, 2)) return;
|
|
114
|
+
const scriptCount = u16(bytes, scriptListOffset);
|
|
115
|
+
const recordsOffset = scriptListOffset + 2;
|
|
116
|
+
if (!hasBytes(bytes, recordsOffset, scriptCount * SCRIPT_RECORD_SIZE) || scriptCount === 0) return;
|
|
117
|
+
for (const wanted of PREFERRED_SCRIPT_TAGS) for (let i = 0; i < scriptCount; i++) {
|
|
118
|
+
const recordOffset = recordsOffset + i * SCRIPT_RECORD_SIZE;
|
|
119
|
+
if (readTag(bytes, recordOffset) === wanted) return scriptListOffset + u16(bytes, recordOffset + 4);
|
|
120
|
+
}
|
|
121
|
+
return scriptListOffset + u16(bytes, recordsOffset + 4);
|
|
122
|
+
}
|
|
123
|
+
function parseDefaultLangSysFeatureIndices(bytes, scriptOffset) {
|
|
124
|
+
if (!hasBytes(bytes, scriptOffset, 2)) return [];
|
|
125
|
+
const defaultLangSysOffset = u16(bytes, scriptOffset);
|
|
126
|
+
if (defaultLangSysOffset === 0) return [];
|
|
127
|
+
const langSysOffset = scriptOffset + defaultLangSysOffset;
|
|
128
|
+
if (!hasBytes(bytes, langSysOffset, LANG_SYS_HEADER_SIZE)) return [];
|
|
129
|
+
const featureIndexCount = u16(bytes, langSysOffset + 4);
|
|
130
|
+
const indicesOffset = langSysOffset + LANG_SYS_HEADER_SIZE;
|
|
131
|
+
if (!hasBytes(bytes, indicesOffset, featureIndexCount * 2)) return [];
|
|
132
|
+
const indices = [];
|
|
133
|
+
for (let i = 0; i < featureIndexCount; i++) indices.push(u16(bytes, indicesOffset + i * 2));
|
|
134
|
+
return indices;
|
|
135
|
+
}
|
|
136
|
+
function collectLigatureLookupIndices(bytes, featureListOffset, featureIndices) {
|
|
137
|
+
if (!hasBytes(bytes, featureListOffset, 2)) return [];
|
|
138
|
+
const featureCount = u16(bytes, featureListOffset);
|
|
139
|
+
const recordsOffset = featureListOffset + 2;
|
|
140
|
+
if (!hasBytes(bytes, recordsOffset, featureCount * FEATURE_RECORD_SIZE)) return [];
|
|
141
|
+
const lookupIndices = [];
|
|
142
|
+
const seen = /* @__PURE__ */ new Set();
|
|
143
|
+
for (const featureIndex of featureIndices) {
|
|
144
|
+
if (featureIndex >= featureCount) continue;
|
|
145
|
+
const recordOffset = recordsOffset + featureIndex * FEATURE_RECORD_SIZE;
|
|
146
|
+
const tag = readTag(bytes, recordOffset);
|
|
147
|
+
if (!LIGATURE_FEATURE_TAGS.includes(tag)) continue;
|
|
148
|
+
const featureOffset = featureListOffset + u16(bytes, recordOffset + 4);
|
|
149
|
+
if (!hasBytes(bytes, featureOffset, FEATURE_HEADER_SIZE)) continue;
|
|
150
|
+
const lookupIndexCount = u16(bytes, featureOffset + 2);
|
|
151
|
+
const indicesOffset = featureOffset + FEATURE_HEADER_SIZE;
|
|
152
|
+
if (!hasBytes(bytes, indicesOffset, lookupIndexCount * 2)) continue;
|
|
153
|
+
for (let i = 0; i < lookupIndexCount; i++) {
|
|
154
|
+
const lookupIndex = u16(bytes, indicesOffset + i * 2);
|
|
155
|
+
if (!seen.has(lookupIndex)) {
|
|
156
|
+
seen.add(lookupIndex);
|
|
157
|
+
lookupIndices.push(lookupIndex);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return lookupIndices;
|
|
162
|
+
}
|
|
163
|
+
function buildGsubShaper(font) {
|
|
164
|
+
const bytes = sfntTableBytes(font, "GSUB");
|
|
165
|
+
if (bytes === void 0 || !hasBytes(bytes, 0, GSUB_HEADER_SIZE) || u16(bytes, 0) !== 1) return;
|
|
166
|
+
const scriptOffset = findScriptOffset(bytes, u16(bytes, 4));
|
|
167
|
+
if (scriptOffset === void 0) return;
|
|
168
|
+
const lookupIndices = collectLigatureLookupIndices(bytes, u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset));
|
|
169
|
+
if (lookupIndices.length === 0) return;
|
|
170
|
+
const lookupListOffset = u16(bytes, 8);
|
|
171
|
+
if (!hasBytes(bytes, lookupListOffset, 2)) return;
|
|
172
|
+
const lookupCount = u16(bytes, lookupListOffset);
|
|
173
|
+
const lookupOffsetsOffset = lookupListOffset + 2;
|
|
174
|
+
if (!hasBytes(bytes, lookupOffsetsOffset, lookupCount * 2)) return;
|
|
175
|
+
const subtables = [];
|
|
176
|
+
for (const lookupIndex of lookupIndices) {
|
|
177
|
+
if (lookupIndex >= lookupCount) continue;
|
|
178
|
+
const lookupOffset = lookupListOffset + u16(bytes, lookupOffsetsOffset + lookupIndex * 2);
|
|
179
|
+
if (!hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) continue;
|
|
180
|
+
if (u16(bytes, lookupOffset + 2) !== 0) continue;
|
|
181
|
+
const lookupType = u16(bytes, lookupOffset);
|
|
182
|
+
const subTableCount = u16(bytes, lookupOffset + 4);
|
|
183
|
+
const subtableOffsetsOffset = lookupOffset + LOOKUP_HEADER_SIZE;
|
|
184
|
+
if (!hasBytes(bytes, subtableOffsetsOffset, subTableCount * 2)) continue;
|
|
185
|
+
for (let i = 0; i < subTableCount; i++) {
|
|
186
|
+
const subtable = parseSubtable(bytes, lookupType, lookupOffset + u16(bytes, subtableOffsetsOffset + i * 2));
|
|
187
|
+
if (subtable !== void 0) subtables.push(subtable);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (subtables.length === 0) return;
|
|
191
|
+
return (glyphIds) => {
|
|
192
|
+
const shaped = [];
|
|
193
|
+
const spans = [];
|
|
194
|
+
let index = 0;
|
|
195
|
+
outer: while (index < glyphIds.length) {
|
|
196
|
+
for (const subtable of subtables) if (subtable.kind === "single") {
|
|
197
|
+
const substitute = subtable.lookup(glyphIds[index]);
|
|
198
|
+
if (substitute !== void 0) {
|
|
199
|
+
shaped.push(substitute);
|
|
200
|
+
spans.push(1);
|
|
201
|
+
index += 1;
|
|
202
|
+
continue outer;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
const match = subtable.match(glyphIds, index);
|
|
206
|
+
if (match !== void 0) {
|
|
207
|
+
shaped.push(match.ligatureGlyph);
|
|
208
|
+
spans.push(match.componentCount);
|
|
209
|
+
index += match.componentCount;
|
|
210
|
+
continue outer;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
shaped.push(glyphIds[index]);
|
|
214
|
+
spans.push(1);
|
|
215
|
+
index += 1;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
glyphIds: shaped,
|
|
219
|
+
spans
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//#endregion
|
|
224
|
+
export { buildGsubShaper };
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ import { NOOP_DIAGNOSTIC_SINK, PdfDiagnostic, PdfDiagnosticSeverity, PdfDiagnost
|
|
|
3
3
|
import { LAYOUT_FORMAT_VERSION, LayoutAnnotation, LayoutAnnotationQuad, LayoutAnnotationQuadSchema, LayoutAnnotationSchema, LayoutAttachment, LayoutAttachmentSchema, LayoutDestination, LayoutDestinationSchema, LayoutDestinationTarget, LayoutDestinationTargetSchema, LayoutDocument, LayoutDocumentSchema, LayoutEllipse, LayoutEllipseSchema, LayoutFormField, LayoutFormFieldSchema, LayoutFormWidget, LayoutFormWidgetSchema, LayoutImage, LayoutImageAsset, LayoutImageAssetSchema, LayoutImageSchema, LayoutInternalLink, LayoutInternalLinkSchema, LayoutItem, LayoutItemSchema, LayoutLayer, LayoutLayerSchema, LayoutLine, LayoutLineSchema, LayoutLink, LayoutLinkSchema, LayoutOutlineItem, LayoutOutlineItemSchema, LayoutPage, LayoutPageSchema, LayoutPath, LayoutPathSchema, LayoutPathSegment, LayoutPathSegmentSchema, LayoutRect, LayoutRectSchema, LayoutStructureElement, LayoutStructureElementSchema, LayoutSubpath, LayoutSubpathSchema, LayoutText, LayoutTextSchema } from "./layout.cjs";
|
|
4
4
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.cjs";
|
|
5
5
|
import { PdfBytesSchema, pdfCodec } from "./codec.cjs";
|
|
6
|
-
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-
|
|
6
|
+
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-oc65VGlr.cjs";
|
|
7
7
|
import { WinAnsiSubstitution } from "./winansi.cjs";
|
|
8
8
|
import { PdfEncryptionError, PdfEncryptionOptions, PdfEncryptionPermissions, PdfEncryptionScheme } from "./encrypt-write.cjs";
|
|
9
9
|
import { FontFace, FontFaceParseError, readFontFace } from "./font-face.cjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { NOOP_DIAGNOSTIC_SINK, PdfDiagnostic, PdfDiagnosticSeverity, PdfDiagnost
|
|
|
3
3
|
import { LAYOUT_FORMAT_VERSION, LayoutAnnotation, LayoutAnnotationQuad, LayoutAnnotationQuadSchema, LayoutAnnotationSchema, LayoutAttachment, LayoutAttachmentSchema, LayoutDestination, LayoutDestinationSchema, LayoutDestinationTarget, LayoutDestinationTargetSchema, LayoutDocument, LayoutDocumentSchema, LayoutEllipse, LayoutEllipseSchema, LayoutFormField, LayoutFormFieldSchema, LayoutFormWidget, LayoutFormWidgetSchema, LayoutImage, LayoutImageAsset, LayoutImageAssetSchema, LayoutImageSchema, LayoutInternalLink, LayoutInternalLinkSchema, LayoutItem, LayoutItemSchema, LayoutLayer, LayoutLayerSchema, LayoutLine, LayoutLineSchema, LayoutLink, LayoutLinkSchema, LayoutOutlineItem, LayoutOutlineItemSchema, LayoutPage, LayoutPageSchema, LayoutPath, LayoutPathSchema, LayoutPathSegment, LayoutPathSegmentSchema, LayoutRect, LayoutRectSchema, LayoutStructureElement, LayoutStructureElementSchema, LayoutSubpath, LayoutSubpathSchema, LayoutText, LayoutTextSchema } from "./layout.js";
|
|
4
4
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.js";
|
|
5
5
|
import { PdfBytesSchema, pdfCodec } from "./codec.js";
|
|
6
|
-
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-
|
|
6
|
+
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-B4p9a3O3.js";
|
|
7
7
|
import { WinAnsiSubstitution } from "./winansi.js";
|
|
8
8
|
import { PdfEncryptionError, PdfEncryptionOptions, PdfEncryptionPermissions, PdfEncryptionScheme } from "./encrypt-write.js";
|
|
9
9
|
import { FontFace, FontFaceParseError, readFontFace } from "./font-face.js";
|
package/dist/math-font-write.cjs
CHANGED
|
@@ -40,7 +40,7 @@ function buildFontFileStream(font, compress) {
|
|
|
40
40
|
}
|
|
41
41
|
function toUnicodeEntries(usedGlyphs) {
|
|
42
42
|
const entries = /* @__PURE__ */ new Map();
|
|
43
|
-
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
|
|
43
|
+
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, [codePoint]);
|
|
44
44
|
return entries;
|
|
45
45
|
}
|
|
46
46
|
function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
package/dist/math-font-write.js
CHANGED
|
@@ -39,7 +39,7 @@ function buildFontFileStream(font, compress) {
|
|
|
39
39
|
}
|
|
40
40
|
function toUnicodeEntries(usedGlyphs) {
|
|
41
41
|
const entries = /* @__PURE__ */ new Map();
|
|
42
|
-
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
|
|
42
|
+
for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, [codePoint]);
|
|
43
43
|
return entries;
|
|
44
44
|
}
|
|
45
45
|
function buildMathFontObjects(font, usedGlyphs, refs, compress) {
|
package/dist/sfnt-subset.cjs
CHANGED
|
@@ -71,7 +71,7 @@ function buildPostStub(font) {
|
|
|
71
71
|
if (sourcePost !== void 0 && require_sfnt.hasBytes(sourcePost, POST_METRICS_OFFSET, POST_METRICS_SIZE)) post.set(sourcePost.subarray(POST_METRICS_OFFSET, 16), POST_METRICS_OFFSET);
|
|
72
72
|
return post;
|
|
73
73
|
}
|
|
74
|
-
function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
74
|
+
function collectGlyphIds(glyf, cmap, numGlyphs, codePoints, extraGlyphIds) {
|
|
75
75
|
const used = /* @__PURE__ */ new Set([0]);
|
|
76
76
|
const unmapped = /* @__PURE__ */ new Set();
|
|
77
77
|
const pending = [0];
|
|
@@ -87,6 +87,13 @@ function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
|
87
87
|
pending.push(glyphId);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
for (const glyphId of extraGlyphIds) {
|
|
91
|
+
if (glyphId >= numGlyphs) return;
|
|
92
|
+
if (!used.has(glyphId)) {
|
|
93
|
+
used.add(glyphId);
|
|
94
|
+
pending.push(glyphId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
90
97
|
while (pending.length > 0) {
|
|
91
98
|
const glyphId = pending.pop();
|
|
92
99
|
if (glyf.glyphBytes(glyphId) === void 0) return;
|
|
@@ -107,7 +114,7 @@ function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
|
107
114
|
unmapped: [...unmapped].sort((a, b) => a - b)
|
|
108
115
|
};
|
|
109
116
|
}
|
|
110
|
-
function subsetSfnt(font, codePoints) {
|
|
117
|
+
function subsetSfnt(font, codePoints, extraGlyphIds = []) {
|
|
111
118
|
const head = require_font_tables.parseHead(font);
|
|
112
119
|
const maxp = require_font_tables.parseMaxp(font);
|
|
113
120
|
const sourceHead = require_sfnt.sfntTableBytes(font, "head");
|
|
@@ -124,7 +131,7 @@ function subsetSfnt(font, codePoints) {
|
|
|
124
131
|
});
|
|
125
132
|
const cmap = require_cmap_table.buildCmapLookup(font);
|
|
126
133
|
if (glyf === void 0 || cmap === void 0) return;
|
|
127
|
-
const collected = collectGlyphIds(glyf, cmap, maxp.numGlyphs, codePoints);
|
|
134
|
+
const collected = collectGlyphIds(glyf, cmap, maxp.numGlyphs, codePoints, extraGlyphIds);
|
|
128
135
|
if (collected === void 0) return;
|
|
129
136
|
const glyphIds = [...collected.used].sort((a, b) => a - b);
|
|
130
137
|
const numGlyphs = glyphIds[glyphIds.length - 1] + 1;
|
package/dist/sfnt-subset.d.cts
CHANGED
|
@@ -6,6 +6,6 @@ interface SfntSubsetResult {
|
|
|
6
6
|
readonly glyphIds: readonly number[];
|
|
7
7
|
readonly unmappedCodePoints: readonly number[];
|
|
8
8
|
}
|
|
9
|
-
declare function subsetSfnt(font: SfntFont, codePoints: Iterable<number>): SfntSubsetResult | undefined;
|
|
9
|
+
declare function subsetSfnt(font: SfntFont, codePoints: Iterable<number>, extraGlyphIds?: Iterable<number>): SfntSubsetResult | undefined;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { SfntSubsetResult, subsetSfnt };
|
package/dist/sfnt-subset.d.ts
CHANGED
|
@@ -6,6 +6,6 @@ interface SfntSubsetResult {
|
|
|
6
6
|
readonly glyphIds: readonly number[];
|
|
7
7
|
readonly unmappedCodePoints: readonly number[];
|
|
8
8
|
}
|
|
9
|
-
declare function subsetSfnt(font: SfntFont, codePoints: Iterable<number>): SfntSubsetResult | undefined;
|
|
9
|
+
declare function subsetSfnt(font: SfntFont, codePoints: Iterable<number>, extraGlyphIds?: Iterable<number>): SfntSubsetResult | undefined;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { SfntSubsetResult, subsetSfnt };
|
package/dist/sfnt-subset.js
CHANGED
|
@@ -70,7 +70,7 @@ function buildPostStub(font) {
|
|
|
70
70
|
if (sourcePost !== void 0 && hasBytes(sourcePost, POST_METRICS_OFFSET, POST_METRICS_SIZE)) post.set(sourcePost.subarray(POST_METRICS_OFFSET, 16), POST_METRICS_OFFSET);
|
|
71
71
|
return post;
|
|
72
72
|
}
|
|
73
|
-
function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
73
|
+
function collectGlyphIds(glyf, cmap, numGlyphs, codePoints, extraGlyphIds) {
|
|
74
74
|
const used = /* @__PURE__ */ new Set([0]);
|
|
75
75
|
const unmapped = /* @__PURE__ */ new Set();
|
|
76
76
|
const pending = [0];
|
|
@@ -86,6 +86,13 @@ function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
|
86
86
|
pending.push(glyphId);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
for (const glyphId of extraGlyphIds) {
|
|
90
|
+
if (glyphId >= numGlyphs) return;
|
|
91
|
+
if (!used.has(glyphId)) {
|
|
92
|
+
used.add(glyphId);
|
|
93
|
+
pending.push(glyphId);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
89
96
|
while (pending.length > 0) {
|
|
90
97
|
const glyphId = pending.pop();
|
|
91
98
|
if (glyf.glyphBytes(glyphId) === void 0) return;
|
|
@@ -106,7 +113,7 @@ function collectGlyphIds(glyf, cmap, numGlyphs, codePoints) {
|
|
|
106
113
|
unmapped: [...unmapped].sort((a, b) => a - b)
|
|
107
114
|
};
|
|
108
115
|
}
|
|
109
|
-
function subsetSfnt(font, codePoints) {
|
|
116
|
+
function subsetSfnt(font, codePoints, extraGlyphIds = []) {
|
|
110
117
|
const head = parseHead(font);
|
|
111
118
|
const maxp = parseMaxp(font);
|
|
112
119
|
const sourceHead = sfntTableBytes(font, "head");
|
|
@@ -123,7 +130,7 @@ function subsetSfnt(font, codePoints) {
|
|
|
123
130
|
});
|
|
124
131
|
const cmap = buildCmapLookup(font);
|
|
125
132
|
if (glyf === void 0 || cmap === void 0) return;
|
|
126
|
-
const collected = collectGlyphIds(glyf, cmap, maxp.numGlyphs, codePoints);
|
|
133
|
+
const collected = collectGlyphIds(glyf, cmap, maxp.numGlyphs, codePoints, extraGlyphIds);
|
|
127
134
|
if (collected === void 0) return;
|
|
128
135
|
const glyphIds = [...collected.used].sort((a, b) => a - b);
|
|
129
136
|
const numGlyphs = glyphIds[glyphIds.length - 1] + 1;
|
package/dist/tounicode.cjs
CHANGED
|
@@ -8,8 +8,13 @@ function codePointToUtf16BEHex(codePoint) {
|
|
|
8
8
|
for (let i = 0; i < text.length; i++) hex += text.charCodeAt(i).toString(16).padStart(4, "0");
|
|
9
9
|
return hex;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
11
|
+
function sequenceToUtf16BEHex(codePoints) {
|
|
12
|
+
let hex = "";
|
|
13
|
+
for (const codePoint of codePoints) hex += codePointToUtf16BEHex(codePoint);
|
|
14
|
+
return hex;
|
|
15
|
+
}
|
|
16
|
+
function buildToUnicodeCMap(codeToSequence) {
|
|
17
|
+
const entries = [...codeToSequence].sort((a, b) => a[0] - b[0]);
|
|
13
18
|
const lines = [
|
|
14
19
|
"/CIDInit /ProcSet findresource begin",
|
|
15
20
|
"12 dict begin",
|
|
@@ -24,7 +29,7 @@ function buildToUnicodeCMap(codeToCodePoint) {
|
|
|
24
29
|
for (let start = 0; start < entries.length; start += MAX_BFCHAR_ENTRIES_PER_BLOCK) {
|
|
25
30
|
const block = entries.slice(start, start + MAX_BFCHAR_ENTRIES_PER_BLOCK);
|
|
26
31
|
lines.push(`${block.length} beginbfchar`);
|
|
27
|
-
for (const [code,
|
|
32
|
+
for (const [code, sequence] of block) lines.push(`<${code.toString(16).padStart(4, "0")}> <${sequenceToUtf16BEHex(sequence)}>`);
|
|
28
33
|
lines.push("endbfchar");
|
|
29
34
|
}
|
|
30
35
|
lines.push("endcmap", "CMapName currentdict /CMap defineresource pop", "end", "end");
|
package/dist/tounicode.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as PdfObject } from "./objects-B7HdMeWS.cjs";
|
|
2
2
|
//#region src/tounicode.d.ts
|
|
3
|
-
declare function buildToUnicodeCMap(
|
|
3
|
+
declare function buildToUnicodeCMap(codeToSequence: ReadonlyMap<number, readonly number[]>): PdfObject;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { buildToUnicodeCMap };
|
package/dist/tounicode.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as PdfObject } from "./objects-B7HdMeWS.js";
|
|
2
2
|
//#region src/tounicode.d.ts
|
|
3
|
-
declare function buildToUnicodeCMap(
|
|
3
|
+
declare function buildToUnicodeCMap(codeToSequence: ReadonlyMap<number, readonly number[]>): PdfObject;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { buildToUnicodeCMap };
|
package/dist/tounicode.js
CHANGED
|
@@ -7,8 +7,13 @@ function codePointToUtf16BEHex(codePoint) {
|
|
|
7
7
|
for (let i = 0; i < text.length; i++) hex += text.charCodeAt(i).toString(16).padStart(4, "0");
|
|
8
8
|
return hex;
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
|
|
10
|
+
function sequenceToUtf16BEHex(codePoints) {
|
|
11
|
+
let hex = "";
|
|
12
|
+
for (const codePoint of codePoints) hex += codePointToUtf16BEHex(codePoint);
|
|
13
|
+
return hex;
|
|
14
|
+
}
|
|
15
|
+
function buildToUnicodeCMap(codeToSequence) {
|
|
16
|
+
const entries = [...codeToSequence].sort((a, b) => a[0] - b[0]);
|
|
12
17
|
const lines = [
|
|
13
18
|
"/CIDInit /ProcSet findresource begin",
|
|
14
19
|
"12 dict begin",
|
|
@@ -23,7 +28,7 @@ function buildToUnicodeCMap(codeToCodePoint) {
|
|
|
23
28
|
for (let start = 0; start < entries.length; start += MAX_BFCHAR_ENTRIES_PER_BLOCK) {
|
|
24
29
|
const block = entries.slice(start, start + MAX_BFCHAR_ENTRIES_PER_BLOCK);
|
|
25
30
|
lines.push(`${block.length} beginbfchar`);
|
|
26
|
-
for (const [code,
|
|
31
|
+
for (const [code, sequence] of block) lines.push(`<${code.toString(16).padStart(4, "0")}> <${sequenceToUtf16BEHex(sequence)}>`);
|
|
27
32
|
lines.push("endbfchar");
|
|
28
33
|
}
|
|
29
34
|
lines.push("endcmap", "CMapName currentdict /CMap defineresource pop", "end", "end");
|