modern-pdf-lib 0.9.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.
@@ -0,0 +1,226 @@
1
+ const require_rolldown_runtime = require('./rolldown-runtime-CKhH4XqG.cjs');
2
+
3
+ //#region src/assets/font/fontSubset.ts
4
+ var fontSubset_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
5
+ buildSubsetCmap: () => buildSubsetCmap,
6
+ computeSubsetTag: () => computeSubsetTag,
7
+ initSubsetWasm: () => initSubsetWasm,
8
+ subsetFont: () => subsetFont
9
+ });
10
+ /**
11
+ * Holds the subsetting WASM instance after initialization.
12
+ * `undefined` means WASM is not loaded (fallback mode).
13
+ */
14
+ let wasmInstance;
15
+ /**
16
+ * Initialize the font subsetting WASM module.
17
+ *
18
+ * Call this once if you want WASM-accelerated subsetting. If not
19
+ * called, {@link subsetFont} falls back to returning the entire font
20
+ * file (no size reduction, but still functional).
21
+ *
22
+ * @param wasmSource - The `.wasm` binary, a URL, or a fetch Response.
23
+ */
24
+ async function initSubsetWasm(wasmSource) {
25
+ if (wasmInstance) return;
26
+ const imports = { env: {} };
27
+ let result;
28
+ try {
29
+ if (wasmSource instanceof Uint8Array) result = await WebAssembly.instantiate(wasmSource.buffer, imports);
30
+ else if (typeof Response !== "undefined" && wasmSource instanceof Response) result = await WebAssembly.instantiateStreaming(wasmSource, imports);
31
+ else if (typeof wasmSource === "string" || wasmSource instanceof URL) {
32
+ const resp = await fetch(String(wasmSource));
33
+ result = await WebAssembly.instantiateStreaming(resp, imports);
34
+ } else {
35
+ const { loadWasmModule } = await Promise.resolve().then(() => require("./loader-mwt5wRJz.cjs"));
36
+ const bytes = await loadWasmModule("ttf");
37
+ result = await WebAssembly.instantiate(bytes.buffer, imports);
38
+ }
39
+ wasmInstance = result.instance.exports;
40
+ } catch {
41
+ wasmInstance = void 0;
42
+ }
43
+ }
44
+ /**
45
+ * Subset a font using the WASM module.
46
+ * @internal
47
+ */
48
+ function subsetWithWasm(_fontData, _usedGlyphIds) {
49
+ throw new Error("WASM subsetting not yet implemented");
50
+ }
51
+ /**
52
+ * Fallback "subsetting" that returns the full font unchanged.
53
+ *
54
+ * Since the full font data is returned unmodified, glyph IDs do not
55
+ * change. The mappings are therefore **true identity** for each used
56
+ * glyph: `oldGID === newGID`. This is functionally correct — PDF
57
+ * viewers render the font normally via `CIDToGIDMap /Identity` — but
58
+ * does not reduce file size.
59
+ *
60
+ * The `newToOldGid` array contains the used glyph IDs in sorted
61
+ * order. Because the font is not actually subsetted, each "new" GID
62
+ * equals the original GID (identity mapping).
63
+ *
64
+ * @param fontData The raw TTF font file bytes.
65
+ * @param usedGlyphIds Set of glyph IDs that are actually used.
66
+ * @returns A {@link SubsetResult} with the original font bytes and
67
+ * identity glyph-ID mappings for the used glyphs.
68
+ * @internal
69
+ */
70
+ function subsetFallback(fontData, usedGlyphIds) {
71
+ const allGids = new Set(usedGlyphIds);
72
+ allGids.add(0);
73
+ const sortedGids = allGids.values().toArray().sort((a, b) => a - b);
74
+ const newToOldGid = sortedGids;
75
+ const oldToNewGid = /* @__PURE__ */ new Map();
76
+ for (const gid of sortedGids) oldToNewGid.set(gid, gid);
77
+ return {
78
+ fontData: new Uint8Array(fontData),
79
+ newToOldGid,
80
+ oldToNewGid
81
+ };
82
+ }
83
+ /**
84
+ * Subset a TrueType font to include only the specified glyphs.
85
+ *
86
+ * Uses WASM-accelerated subsetting if available (via {@link initSubsetWasm}),
87
+ * otherwise falls back to returning the full font with identity glyph
88
+ * mappings.
89
+ *
90
+ * Glyph ID 0 (.notdef) is always included automatically.
91
+ *
92
+ * @param fontData - The raw TTF font file bytes.
93
+ * @param usedGlyphIds - Set of glyph IDs that are actually used.
94
+ * @returns The subset result with the (possibly reduced) font and
95
+ * glyph-ID remapping tables.
96
+ */
97
+ function subsetFont(fontData, usedGlyphIds) {
98
+ if (usedGlyphIds.size === 0) return subsetFallback(fontData, new Set([0]));
99
+ if (wasmInstance) return subsetWithWasm(fontData, usedGlyphIds);
100
+ return subsetFallback(fontData, usedGlyphIds);
101
+ }
102
+ /**
103
+ * Build a PDF `/ToUnicode` CMap stream for a subsetted font.
104
+ *
105
+ * The CMap maps CIDs (new glyph IDs in the subset) back to Unicode
106
+ * codepoints, enabling text extraction and copy-paste in PDF viewers.
107
+ *
108
+ * @param subsetResult - The result from {@link subsetFont}.
109
+ * @param originalCmapTable - The original font's cmap table (Unicode
110
+ * codepoint → original glyph ID).
111
+ * @returns A CMap stream body and a CID-to-Unicode lookup.
112
+ */
113
+ function buildSubsetCmap(subsetResult, originalCmapTable) {
114
+ const oldGidToUnicode = /* @__PURE__ */ new Map();
115
+ for (const [codepoint, gid] of originalCmapTable) {
116
+ const existing = oldGidToUnicode.get(gid);
117
+ if (existing) existing.push(codepoint);
118
+ else oldGidToUnicode.set(gid, [codepoint]);
119
+ }
120
+ const cidToUnicode = /* @__PURE__ */ new Map();
121
+ for (let newGid = 0; newGid < subsetResult.newToOldGid.length; newGid++) {
122
+ const oldGid = subsetResult.newToOldGid[newGid];
123
+ const unicodes = oldGidToUnicode.get(oldGid);
124
+ if (unicodes && unicodes.length > 0) cidToUnicode.set(newGid, unicodes);
125
+ }
126
+ return {
127
+ cmapStream: generateToUnicodeCmap(cidToUnicode),
128
+ cidToUnicode
129
+ };
130
+ }
131
+ /**
132
+ * Generate a PDF `/ToUnicode` CMap program.
133
+ *
134
+ * The CMap uses `beginbfchar` / `endbfchar` sections to map individual
135
+ * CIDs to Unicode values. For ranges of consecutive mappings it uses
136
+ * `beginbfrange` / `endbfrange`.
137
+ *
138
+ * @internal
139
+ */
140
+ function generateToUnicodeCmap(cidToUnicode) {
141
+ const lines = [];
142
+ lines.push("/CIDInit /ProcSet findresource begin");
143
+ lines.push("12 dict begin");
144
+ lines.push("begincmap");
145
+ lines.push("/CIDSystemInfo");
146
+ lines.push("<< /Registry (Adobe)");
147
+ lines.push("/Ordering (UCS)");
148
+ lines.push("/Supplement 0");
149
+ lines.push(">> def");
150
+ lines.push("/CMapName /Adobe-Identity-UCS def");
151
+ lines.push("/CMapType 2 def");
152
+ lines.push("1 begincodespacerange");
153
+ lines.push("<0000> <FFFF>");
154
+ lines.push("endcodespacerange");
155
+ const entries = cidToUnicode.entries().toArray().sort((a, b) => a[0] - b[0]);
156
+ const CHUNK_SIZE = 100;
157
+ for (let i = 0; i < entries.length; i += CHUNK_SIZE) {
158
+ const chunk = entries.slice(i, i + CHUNK_SIZE);
159
+ lines.push(`${chunk.length} beginbfchar`);
160
+ for (const [cid, unicodes] of chunk) {
161
+ const cidHex = cid.toString(16).padStart(4, "0").toUpperCase();
162
+ if (unicodes.length === 1) {
163
+ const uniHex = unicodes[0].toString(16).padStart(4, "0").toUpperCase();
164
+ lines.push(`<${cidHex}> <${uniHex}>`);
165
+ } else {
166
+ let uniHex = "";
167
+ for (const cp of unicodes.slice(0, 1)) uniHex += cp.toString(16).padStart(4, "0").toUpperCase();
168
+ lines.push(`<${cidHex}> <${uniHex}>`);
169
+ }
170
+ }
171
+ lines.push("endbfchar");
172
+ }
173
+ lines.push("endcmap");
174
+ lines.push("CMapName currentdict /CMap defineresource pop");
175
+ lines.push("end");
176
+ lines.push("end");
177
+ return lines.join("\n");
178
+ }
179
+ /**
180
+ * Generate a 6-letter uppercase tag for the subset font name.
181
+ *
182
+ * PDF spec recommends a tag prefix like `ABCDEF+FontName` to indicate
183
+ * the font is subsetted. This function generates a deterministic tag
184
+ * from the set of glyph IDs.
185
+ *
186
+ * @param usedGlyphIds - The set of glyph IDs in the subset.
187
+ * @returns A 6-character uppercase ASCII string (e.g. `"BCDEFG"`).
188
+ */
189
+ function computeSubsetTag(usedGlyphIds) {
190
+ let hash = 0;
191
+ for (const gid of usedGlyphIds) hash = (hash << 5) - hash + gid | 0;
192
+ const tag = [];
193
+ let h = Math.abs(hash);
194
+ for (let i = 0; i < 6; i++) {
195
+ tag.push(String.fromCharCode(65 + h % 26));
196
+ h = Math.floor(h / 26);
197
+ }
198
+ return tag.join("");
199
+ }
200
+
201
+ //#endregion
202
+ Object.defineProperty(exports, 'buildSubsetCmap', {
203
+ enumerable: true,
204
+ get: function () {
205
+ return buildSubsetCmap;
206
+ }
207
+ });
208
+ Object.defineProperty(exports, 'computeSubsetTag', {
209
+ enumerable: true,
210
+ get: function () {
211
+ return computeSubsetTag;
212
+ }
213
+ });
214
+ Object.defineProperty(exports, 'fontSubset_exports', {
215
+ enumerable: true,
216
+ get: function () {
217
+ return fontSubset_exports;
218
+ }
219
+ });
220
+ Object.defineProperty(exports, 'subsetFont', {
221
+ enumerable: true,
222
+ get: function () {
223
+ return subsetFont;
224
+ }
225
+ });
226
+ //# sourceMappingURL=fontSubset-C0Rm9ih6.cjs.map