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.
- package/LICENSE +21 -0
- package/README.md +455 -0
- package/dist/documentMerge-CNPWlWic.mjs +18351 -0
- package/dist/documentMerge-DnLzOg5P.cjs +18878 -0
- package/dist/fflateAdapter-D2mv_ttM.mjs +196 -0
- package/dist/fflateAdapter-cT4YeY_h.cjs +207 -0
- package/dist/fontSubset-BOGts8y9.mjs +203 -0
- package/dist/fontSubset-C0Rm9ih6.cjs +226 -0
- package/dist/index.cjs +4597 -0
- package/dist/index.d.cts +7898 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +7898 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +4306 -0
- package/dist/libdeflateWasm-QVHmuzw-.mjs +220 -0
- package/dist/libdeflateWasm-to2bG6NG.cjs +237 -0
- package/dist/loader-D9LTYmrX.mjs +162 -0
- package/dist/loader-mwt5wRJz.cjs +164 -0
- package/dist/pdfCatalog-DTXk0tbK.cjs +627 -0
- package/dist/pdfCatalog-Dk4qUVvx.mjs +532 -0
- package/dist/pdfPage-C9vw_D1J.cjs +5203 -0
- package/dist/pdfPage-DZA6XJzR.mjs +4544 -0
- package/dist/pngEmbed-BN-gMJrb.cjs +536 -0
- package/dist/pngEmbed-DgeNWlbS.mjs +525 -0
- package/dist/rolldown-runtime-95iHPtFO.mjs +18 -0
- package/dist/rolldown-runtime-CKhH4XqG.cjs +24 -0
- package/package.json +94 -0
|
@@ -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
|