renderpdf-js 0.0.0-stage → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1092 @@
1
+ import e from "@pdf-lib/fontkit";
2
+ import { PDFArray as t, PDFDict as n, PDFDocument as r, PDFHexString as i, PDFName as a, TextRenderingMode as o, beginText as s, clip as c, endPath as l, endText as u, popGraphicsState as d, pushGraphicsState as f, rectangle as p, rgb as m, setFillingColor as h, setFontAndSize as g, setGraphicsState as _, setTextMatrix as v, setTextRenderingMode as ee, showText as te } from "pdf-lib";
3
+ import { toPng as y } from "html-to-image";
4
+ // src/diagnostics.ts
5
+ var b = class extends Error {
6
+ code;
7
+ constructor(e, t, n) {
8
+ super(t, n), this.code = e, this.name = "RenderPDFError";
9
+ }
10
+ };
11
+ function x(e) {
12
+ if (e?.aborted) throw new DOMException("PDF rendering was cancelled.", "AbortError");
13
+ }
14
+ // src/breaks.ts
15
+ var S = /* @__PURE__ */ new Set([
16
+ "block",
17
+ "flow-root",
18
+ "flex",
19
+ "grid",
20
+ "table",
21
+ "table-caption",
22
+ "table-row",
23
+ "table-row-group",
24
+ "table-header-group",
25
+ "table-footer-group"
26
+ ]);
27
+ function C(e, t) {
28
+ let n = e.getPropertyValue(`break-${t}`).trim(), r = e.getPropertyValue(`page-break-${t}`).trim();
29
+ return n && n !== "auto" ? n : r || n || "auto";
30
+ }
31
+ function w(e, t) {
32
+ if (e !== "auto" && e !== "avoid" && e !== "avoid-page" && (t === "inside" || e !== "page" && e !== "always")) throw new b("UNSUPPORTED_CSS", `Unsupported CSS break-${t}: ${e}; only page/always boundaries and avoid/avoid-page preferences are supported.`);
33
+ }
34
+ function T(e, t) {
35
+ let n = e.getBoundingClientRect();
36
+ return {
37
+ x: n.left - t.left,
38
+ y: n.top - t.top,
39
+ width: n.width,
40
+ height: n.height
41
+ };
42
+ }
43
+ function ne(e) {
44
+ let t = getComputedStyle(e), n = e.getBoundingClientRect();
45
+ return t.visibility === "visible" && S.has(t.display) && n.width > 0 && n.height > 0;
46
+ }
47
+ function re(e, t) {
48
+ let n = t === "previous" ? e.previousElementSibling : e.nextElementSibling;
49
+ for (; n;) {
50
+ if (!(n instanceof HTMLElement)) return;
51
+ let e = getComputedStyle(n);
52
+ if (e.display !== "none" && e.visibility === "visible") return ne(n) ? n : void 0;
53
+ n = t === "previous" ? n.previousElementSibling : n.nextElementSibling;
54
+ }
55
+ }
56
+ function ie(e, t) {
57
+ let n = Math.min(e.x, t.x), r = Math.min(e.y, t.y);
58
+ return {
59
+ x: n,
60
+ y: r,
61
+ width: Math.max(e.x + e.width, t.x + t.width) - n,
62
+ height: Math.max(e.y + e.height, t.y + t.height) - r
63
+ };
64
+ }
65
+ function ae(e, t) {
66
+ if (!e.isConnected || e.ownerDocument !== document) throw new b("INVALID_SOURCE", "CSS page-break collection requires a connected source in the current document.");
67
+ let n = e.getBoundingClientRect(), r = t.operations.filter((e) => e.kind === "raster"), i = /* @__PURE__ */ new Map(), a = [];
68
+ for (let t of [e, ...e.querySelectorAll("*")]) {
69
+ if (!(t instanceof HTMLElement)) continue;
70
+ let e = getComputedStyle(t);
71
+ if (e.display === "none" || e.visibility !== "visible") continue;
72
+ let o = t.getBoundingClientRect();
73
+ if (o.width === 0 && o.height === 0 && t.getClientRects().length === 0) continue;
74
+ let s = C(e, "before"), c = C(e, "after"), l = C(e, "inside");
75
+ w(s, "before"), w(c, "after"), w(l, "inside");
76
+ let u = r.find((e) => e.element.contains(t));
77
+ if (!u && S.has(e.display) && (e.widows && e.widows !== "2" || e.orphans && e.orphans !== "2")) throw new b("UNSUPPORTED_CSS", "Nondefault CSS widows/orphans are unsupported; this renderer preserves measured text lines without a line-count pagination policy.");
78
+ if (s === "auto" && c === "auto" && l === "auto") continue;
79
+ let d = s === "page" || s === "always", f = c === "page" || c === "always";
80
+ if (u && u.element !== t) {
81
+ if (d || f) throw new b("PAGINATION_FAILED", "A forced CSS page break lies inside an atomic raster region; move the break outside that region.");
82
+ continue;
83
+ }
84
+ if (!S.has(e.display)) throw new b("UNSUPPORTED_CSS", "Explicit CSS page breaks require a block, table group or table row; inline fragments and table cells are unsupported.");
85
+ let p = T(t, n);
86
+ d && a.push(p.y), f && a.push(p.y + p.height), l !== "auto" && !u && i.set(`${p.x}:${p.y}:${p.width}:${p.height}`, p);
87
+ for (let e of ["previous", "next"]) {
88
+ let r = e === "previous" ? s : c;
89
+ if (r !== "avoid" && r !== "avoid-page") continue;
90
+ let a = re(t, e);
91
+ if (!a) continue;
92
+ let o = ie(p, T(a, n));
93
+ i.set(`${o.x}:${o.y}:${o.width}:${o.height}`, o);
94
+ }
95
+ }
96
+ return {
97
+ forcedBreaks: a,
98
+ avoidBreakBounds: [...i.values()]
99
+ };
100
+ }
101
+ // src/fonts.ts
102
+ var E = /* @__PURE__ */ new WeakMap(), D = /* @__PURE__ */ new WeakMap(), oe = /* @__PURE__ */ new Set([
103
+ "serif",
104
+ "sans-serif",
105
+ "monospace",
106
+ "cursive",
107
+ "fantasy",
108
+ "system-ui",
109
+ "ui-serif",
110
+ "ui-sans-serif",
111
+ "ui-monospace",
112
+ "ui-rounded",
113
+ "emoji",
114
+ "math",
115
+ "fangsong",
116
+ "inherit",
117
+ "initial",
118
+ "unset",
119
+ "revert",
120
+ "revert-layer"
121
+ ]);
122
+ function O(e) {
123
+ if (e.byteLength < 12) throw new b("FONT_LOAD_FAILED", "Provide a complete static TTF/OTF font program.");
124
+ let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = t.getUint32(0);
125
+ if (n !== 65536 && n !== 1330926671) throw new b("FONT_LOAD_FAILED", "Only static TTF/OTF programs are supported; WOFF fonts and font collections are unsupported.");
126
+ let r = t.getUint16(4);
127
+ if (r === 0 || 12 + r * 16 > e.byteLength) throw new b("FONT_LOAD_FAILED", "The TTF/OTF font table directory is incomplete.");
128
+ for (let e = 0; e < r; e += 1) if (t.getUint32(12 + e * 16) === 1719034226) throw new b("FONT_LOAD_FAILED", "Variable fonts are unsupported. Provide an explicitly generated static TTF/OTF instance.");
129
+ }
130
+ function k(e, t, n, r, i) {
131
+ for (let a of e.fonts) {
132
+ if (a === i || a.family.replace(/^["']|["']$/g, "").toLowerCase() !== t.toLowerCase() || a.style !== r) continue;
133
+ let e = a.weight === "normal" ? [400] : a.weight === "bold" ? [700] : a.weight.split(/\s+/).map(Number);
134
+ if (e[0] === n || e.length === 2 && n >= e[0] && n <= e[1]) throw new b("INVALID_OPTIONS", `Font ${t} ${n} ${r} conflicts with an existing browser font face. Choose a family owned by this registration.`);
135
+ }
136
+ }
137
+ function A(e) {
138
+ for (let t of e) {
139
+ let e = t && typeof t == "object" ? D.get(t) : void 0;
140
+ if (!e || typeof document > "u" || e.document !== document || !document.fonts.has(e.face)) throw new b("MISSING_FONT", "Provide font handles returned by registerFont() whose browser faces remain registered in the current document.");
141
+ k(document, t.family, t.weight, t.style, e.face);
142
+ }
143
+ }
144
+ async function se(e) {
145
+ if (!e || typeof e != "object" || typeof e.family != "string") throw new b("INVALID_OPTIONS", "Font registration requires a CSS family and font bytes.");
146
+ let t = e.family.trim(), n = e.weight ?? 400, r = e.style ?? "normal";
147
+ if (!t || !/^[\w -]+$/.test(t) || oe.has(t.toLowerCase()) || !Number.isInteger(n) || n < 1 || n > 1e3 || r !== "normal" && r !== "italic" || !(e.data instanceof Uint8Array) && !(e.data instanceof ArrayBuffer) || e.data.byteLength === 0) throw new b("INVALID_OPTIONS", "Provide a plain custom CSS family (letters, digits, spaces, hyphens, or underscores), nonempty TTF/OTF bytes, integer weight from 1 to 1000, and normal or italic style.");
148
+ if (typeof document > "u" || typeof FontFace > "u" || !document.fonts) throw new b("FONT_LOAD_FAILED", "Font registration requires a browser document with FontFace support.");
149
+ let i = new Uint8Array(e.data instanceof Uint8Array ? e.data : new Uint8Array(e.data));
150
+ O(i);
151
+ let a = `${t.toLowerCase()}:${n}:${r}`, o = document, s = E.get(o);
152
+ s || (s = /* @__PURE__ */ new Map(), E.set(o, s));
153
+ let c = s.get(a);
154
+ if (k(o, t, n, r, c?.face), c) {
155
+ if (c.bytes.length !== i.length || c.bytes.some((e, t) => e !== i[t])) throw new b("INVALID_OPTIONS", `Font ${t} ${n} ${r} is already registered with different bytes.`);
156
+ return c.promise;
157
+ }
158
+ async function l() {
159
+ try {
160
+ let e = new FontFace(t, i, {
161
+ weight: String(n),
162
+ style: r
163
+ });
164
+ await e.load(), k(o, t, n, r), o.fonts.add(e), d.face = e;
165
+ let a = Object.freeze({
166
+ family: t,
167
+ weight: n,
168
+ style: r,
169
+ get bytes() {
170
+ return i.slice();
171
+ }
172
+ });
173
+ return D.set(a, {
174
+ document: o,
175
+ face: e
176
+ }), a;
177
+ } catch (e) {
178
+ throw s.delete(a), e instanceof b ? e : new b("FONT_LOAD_FAILED", `Could not load font ${t} ${n} ${r}.`, { cause: e });
179
+ }
180
+ }
181
+ let u = Promise.resolve().then(l), d = {
182
+ bytes: i,
183
+ promise: u
184
+ };
185
+ return s.set(a, d), u;
186
+ }
187
+ // src/planner.ts
188
+ var j = /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z\d+/=\s]+$/i;
189
+ function M(e) {
190
+ let t = 0, n = "", r = 0, i = [];
191
+ for (let a = 0; a < e.length; a += 1) {
192
+ let o = e[a];
193
+ o === "\\" ? a += 1 : n ? o === n && (n = "") : o === "\"" || o === "'" ? n = o : o === "(" ? t += 1 : o === ")" ? --t : o === "," && t === 0 && (i.push(e.slice(r, a).trim()), r = a + 1);
194
+ }
195
+ return i.push(e.slice(r).trim()), i;
196
+ }
197
+ function N(e) {
198
+ let t = [];
199
+ if (e.backgroundImage !== "none") {
200
+ for (let t of M(e.backgroundImage)) {
201
+ if (/^(?:repeating-)?(?:linear|radial|conic)-gradient\(/i.test(t)) continue;
202
+ let e = t.match(/^url\(\s*(["']?)(.*?)\1\s*\)$/i)?.[2];
203
+ if (!e || !j.test(e)) throw new b("UNSUPPORTED_CSS", "Unsupported CSS: automatic raster backgrounds require gradients or inline bitmap URLs.");
204
+ }
205
+ t.push("background-image");
206
+ }
207
+ if (e.borderRadius !== "0px" && t.push("border-radius"), e.boxShadow !== "none") {
208
+ if (M(e.boxShadow).some((e) => !/\binset\b/.test(e))) throw new b("UNSUPPORTED_CSS", "Unsupported CSS: outer shadows require expanded capture bounds; only inset shadows can fall back automatically.");
209
+ t.push("inset box-shadow");
210
+ }
211
+ return e.opacity !== "1" && t.push("opacity"), t.length ? t.join(", ") : void 0;
212
+ }
213
+ function ce(e, t) {
214
+ if (!(e instanceof HTMLImageElement) && ![
215
+ "block",
216
+ "flow-root",
217
+ "inline-block",
218
+ "flex",
219
+ "inline-flex",
220
+ "grid",
221
+ "inline-grid"
222
+ ].includes(t.display)) throw new b("UNSUPPORTED_CSS", "Automatic raster fallback requires a rectangular block, flex, grid, inline-block, or image boundary; wrap inline or table-internal effects in a supported block.");
223
+ if (Array.from(e.getClientRects()).filter((e) => e.width > 0 && e.height > 0).length !== 1) throw new b("UNSUPPORTED_CSS", "Automatic raster fallback cannot capture fragmented inline or multi-column regions.");
224
+ }
225
+ // src/layout.ts
226
+ var le = new Intl.Segmenter("en", { granularity: "grapheme" });
227
+ function P(e, t) {
228
+ if (![
229
+ e.x,
230
+ e.y,
231
+ e.width,
232
+ e.height
233
+ ].every(Number.isFinite)) throw new b("INVALID_SOURCE", "Browser geometry must contain only finite CSS pixel values.");
234
+ return {
235
+ x: e.left - t.left,
236
+ y: e.top - t.top,
237
+ width: e.width,
238
+ height: e.height
239
+ };
240
+ }
241
+ function F(e) {
242
+ let t = e.getRootNode();
243
+ return e.parentElement ?? (t instanceof ShadowRoot && t.host instanceof HTMLElement ? t.host : null);
244
+ }
245
+ function I(e, t, n = !1) {
246
+ let r = e instanceof HTMLImageElement, i = [
247
+ t.position !== "static" && `position: ${t.position}`,
248
+ t.zIndex !== "auto" && `z-index: ${t.zIndex}`,
249
+ t.transform !== "none" && "transform",
250
+ t.filter !== "none" && "filter",
251
+ t.backdropFilter !== "none" && "backdrop-filter",
252
+ t.mixBlendMode !== "normal" && "mix-blend-mode",
253
+ t.opacity !== "1" && !n && "opacity",
254
+ t.clipPath !== "none" && "clip-path",
255
+ t.maskImage !== "none" && "mask-image",
256
+ t.backgroundImage !== "none" && !n && "background-image",
257
+ t.boxShadow !== "none" && !n && "box-shadow",
258
+ t.borderRadius !== "0px" && !n && "border-radius",
259
+ t.overflowX !== "visible" && !(r && t.overflowX === "clip") && "overflow-x",
260
+ t.overflowY !== "visible" && !(r && t.overflowY === "clip") && "overflow-y",
261
+ t.cssFloat !== "none" && "float",
262
+ t.order !== "0" && "order",
263
+ t.direction !== "ltr" && "direction",
264
+ t.writingMode !== "horizontal-tb" && "writing-mode",
265
+ t.textShadow !== "none" && "text-shadow",
266
+ t.textDecorationLine !== "none" && "text-decoration",
267
+ t.textTransform !== "none" && "text-transform",
268
+ t.letterSpacing !== "normal" && t.letterSpacing !== "0px" && "letter-spacing",
269
+ t.wordSpacing !== "normal" && t.wordSpacing !== "0px" && "word-spacing",
270
+ t.whiteSpace !== "normal" && "white-space",
271
+ t.columnCount !== "auto" && t.columnCount !== "1" && "columns",
272
+ t.outlineStyle !== "none" && "outline",
273
+ t.borderImageSource !== "none" && "border-image",
274
+ t.boxDecorationBreak === "clone" && "box-decoration-break: clone",
275
+ t.zoom !== "1" && "zoom",
276
+ [
277
+ "marginTop",
278
+ "marginRight",
279
+ "marginBottom",
280
+ "marginLeft"
281
+ ].some((e) => Number.parseFloat(t.getPropertyValue(e.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`))) < 0) && "negative margins"
282
+ ].filter(Boolean);
283
+ for (let t of ["::before", "::after"]) {
284
+ let n = getComputedStyle(e, t).content;
285
+ n !== "none" && n !== "normal" && i.push(`generated content ${t}`);
286
+ }
287
+ if (i.length > 0) throw new b("UNSUPPORTED_CSS", `Unsupported CSS on ${e.tagName}: ${i.join(", ")}. Use a bounded data-raster subtree when safe.`);
288
+ if (e instanceof HTMLTableElement && t.borderCollapse !== "separate") throw new b("UNSUPPORTED_CSS", "Native table snapshots require separate borders; collapsed borders are unsupported.");
289
+ if ([
290
+ "THEAD",
291
+ "TBODY",
292
+ "TFOOT",
293
+ "TR",
294
+ "COL",
295
+ "COLGROUP"
296
+ ].includes(e.tagName) && t.backgroundColor !== "rgba(0, 0, 0, 0)") throw new b("UNSUPPORTED_CSS", "Native table snapshots require transparent row-group, row, and column backgrounds.");
297
+ let a = [
298
+ "Top",
299
+ "Right",
300
+ "Bottom",
301
+ "Left"
302
+ ], o = a.map((e) => t[`border${e}Width`]), s = a.map((e) => t[`border${e}Color`]), c = a.map((e) => t[`border${e}Style`]);
303
+ if (o.some((e) => e !== o[0]) || o[0] !== "0px" && (s.some((e) => e !== s[0]) || c.some((e) => e !== "solid"))) throw new b("UNSUPPORTED_CSS", "Unsupported CSS: only uniform solid borders are supported.");
304
+ if (!n && (t.backgroundColor !== "rgba(0, 0, 0, 0)" || o[0] !== "0px") && Array.from(e.getClientRects()).filter((e) => e.width > 0 && e.height > 0).length > 1) throw new b("UNSUPPORTED_CSS", "Fragmented inline backgrounds and borders require an explicit containing raster region.");
305
+ }
306
+ function L(e, t) {
307
+ if (!(e instanceof HTMLImageElement) && ![
308
+ "block",
309
+ "flow-root",
310
+ "inline",
311
+ "inline-block",
312
+ "flex",
313
+ "inline-flex",
314
+ "grid",
315
+ "inline-grid",
316
+ "table",
317
+ "inline-table",
318
+ "table-caption",
319
+ "table-header-group",
320
+ "table-row-group",
321
+ "table-footer-group",
322
+ "table-row",
323
+ "table-cell",
324
+ "table-column-group",
325
+ "table-column"
326
+ ].includes(t.display)) throw new b("UNSUPPORTED_CSS", `Unsupported CSS display: ${t.display}.`);
327
+ }
328
+ function R(e, t, n, r, i) {
329
+ let a = e.parentElement;
330
+ if (!a || !e.data.replace(/[\t\n\r\f ]+/g, "")) return [];
331
+ let o = getComputedStyle(a), s = o.fontFamily.split(",")[0]?.trim().replace(/^['"]|['"]$/g, ""), c = Number(o.fontWeight), l = n.find((e) => e.family.toLowerCase() === s?.toLowerCase() && e.weight === c && e.style === o.fontStyle);
332
+ if (!l) throw new b("MISSING_FONT", `No exact registered font face for ${o.fontFamily} ${o.fontWeight} ${o.fontStyle}.`);
333
+ if (o.direction !== "ltr" || o.writingMode !== "horizontal-tb" || o.textTransform !== "none" || o.whiteSpace !== "normal" || e.data.includes("­") || o.hyphens === "auto" || o.letterSpacing !== "normal" && o.letterSpacing !== "0px" || o.wordSpacing !== "normal" && o.wordSpacing !== "0px" || o.fontVariantCaps !== "normal" || o.fontVariantAlternates !== "normal" || o.fontVariantLigatures !== "normal" || o.fontVariantNumeric !== "normal" || o.fontVariantEastAsian !== "normal" || o.fontVariantPosition !== "normal" || o.fontFeatureSettings !== "normal" || o.fontVariationSettings !== "normal" || o.fontStretch !== "100%" && o.fontStretch !== "normal" || o.fontSizeAdjust !== "none" && o.fontSizeAdjust !== void 0 || !["auto", "geometricPrecision"].includes(o.textRendering)) throw new b("UNSUPPORTED_CSS", "Unsupported CSS: text requires horizontal LTR layout with normal whitespace, spacing, font variants and OpenType features, without automatic hyphenation or soft hyphens.");
334
+ let u = Number.parseFloat(o.fontSize), d = `${l.style} ${l.weight} ${u}px "${l.family}"`, f = r.fonts.get(d);
335
+ if (!f) {
336
+ if (!Array.from(document.fonts).some((e) => {
337
+ let t = e.weight === "normal" ? 400 : e.weight === "bold" ? 700 : Number(e.weight);
338
+ return e.family.replace(/^['"]|['"]$/g, "").toLowerCase() === l.family.toLowerCase() && t === l.weight && e.style === l.style && e.status === "loaded";
339
+ }) || !document.fonts.check(d, e.data)) throw new b("MISSING_FONT", `Browser font is not loaded: ${d}.`);
340
+ r.context.font = d;
341
+ let t = r.context.measureText(e.data), n = t.fontBoundingBoxAscent, i = t.fontBoundingBoxDescent;
342
+ if (!Number.isFinite(n) || !Number.isFinite(i)) throw new b("UNSUPPORTED_CSS", "Font bounding metrics are unavailable in this browser.");
343
+ f = {
344
+ ascent: n,
345
+ descent: i
346
+ }, r.fonts.set(d, f);
347
+ }
348
+ let { ascent: p, descent: m } = f, h = le.segment(e.data), g = document.createRange(), _ = [];
349
+ for (let t of h) {
350
+ g.setStart(e, t.index), g.setEnd(e, t.index + t.segment.length);
351
+ let n = Array.from(g.getClientRects()), r = n.find((e) => e.width > 0 && e.height > 0);
352
+ if (!r) {
353
+ if (/[^\t\n\r\f ]/.test(t.segment) && n.some((e) => e.height > 0 && e.width === 0)) throw new b("UNSUPPORTED_CSS", "Text shaping crosses an inline boundary or uses an unsupported zero-width glyph. Keep each shaped word in one text node.");
354
+ continue;
355
+ }
356
+ let i = _.at(-1);
357
+ i && Math.abs(i.top - r.top) < .5 ? i.end = t.index + t.segment.length : _.push({
358
+ start: t.index,
359
+ end: t.index + t.segment.length,
360
+ top: r.top
361
+ });
362
+ }
363
+ return _.flatMap((n) => {
364
+ let r = n.start, a = n.end;
365
+ for (; r < a && /[\t\n\r\f ]/.test(e.data[r]);) r += 1;
366
+ for (; a > r && /[\t\n\r\f ]/.test(e.data[a - 1]);) --a;
367
+ if (r === a) return [];
368
+ g.setStart(e, r), g.setEnd(e, a);
369
+ let s = e.data.slice(r, a), c = s.replace(/[\t\n\r\f ]+/g, " "), d = P(g.getBoundingClientRect(), t);
370
+ return [{
371
+ kind: "text",
372
+ bounds: d,
373
+ text: c,
374
+ runs: Array.from(s.matchAll(/[^\t\n\r\f ]+/g), (n) => {
375
+ g.setStart(e, r + n.index), g.setEnd(e, r + n.index + n[0].length);
376
+ let i = P(g.getBoundingClientRect(), t);
377
+ return {
378
+ text: n[0],
379
+ x: i.x,
380
+ width: i.width
381
+ };
382
+ }),
383
+ baseline: d.y + (d.height - p - m) / 2 + p,
384
+ fontSize: u,
385
+ family: l.family,
386
+ weight: l.weight,
387
+ style: l.style,
388
+ kerning: o.fontKerning !== "none",
389
+ color: o.color,
390
+ invisible: i
391
+ }];
392
+ });
393
+ }
394
+ function z(e, t, n) {
395
+ if (n !== "auto" && n !== "strict") throw new b("INVALID_OPTIONS", "Raster fallback must be auto or strict.");
396
+ if (!(e instanceof HTMLElement) || e.ownerDocument !== document || !e.isConnected || t.length === 0) throw new b("INVALID_SOURCE", "A connected source root and registered fonts are required.");
397
+ if (new Set(t.map((e) => `${e.family.toLowerCase()}:${e.weight}:${e.style}`)).size !== t.length) throw new b("INVALID_OPTIONS", "Registered fonts require unique family/weight/style descriptors.");
398
+ for (let t = F(e); t; t = F(t)) {
399
+ let e = getComputedStyle(t);
400
+ if (e.transform !== "none" || e.filter !== "none" || e.opacity !== "1" || e.clipPath !== "none" || e.maskImage !== "none" || e.mixBlendMode !== "normal" || e.zoom !== "1" || e.overflowX !== "visible" || e.overflowY !== "visible") throw new b("UNSUPPORTED_CSS", "Unsupported CSS: source ancestors must not transform, clip, blend, or fade the source.");
401
+ }
402
+ }
403
+ function B(e, t, n = {}) {
404
+ let r = n.fallback ?? "auto";
405
+ z(e, t, r);
406
+ let i = e.getBoundingClientRect();
407
+ if (i.width <= 0 || i.height <= 0) throw new b("INVALID_SOURCE", "The source root must have positive visible dimensions.");
408
+ let a = document.createElement("canvas").getContext("2d");
409
+ if (!a) throw new b("INVALID_SOURCE", "Canvas font measurement is unavailable.");
410
+ let o = {
411
+ context: a,
412
+ fonts: /* @__PURE__ */ new Map()
413
+ }, s = [], c = [], l = [{
414
+ code: "TEXT_METRICS_APPROXIMATED",
415
+ message: "Baselines are estimated from Canvas font metrics; browser and PDF shaping engines may still differ for unsupported scripts or font features."
416
+ }];
417
+ function u(e, n, a = !1) {
418
+ let d = getComputedStyle(e);
419
+ if (d.display === "none") return;
420
+ if (d.visibility !== "visible") {
421
+ if (!n || a) throw new b("UNSUPPORTED_CSS", "Unsupported CSS: visibility overrides are not supported.");
422
+ l.push({
423
+ code: "RASTER_TEXT_OMITTED",
424
+ message: `Raster text extraction omitted for visibility-controlled subtree ${e.tagName}.`
425
+ });
426
+ return;
427
+ }
428
+ if ((!n || a) && !(/* @__PURE__ */ "MAIN.SECTION.ARTICLE.DIV.SPAN.P.H1.H2.H3.H4.H5.H6.STRONG.EM.B.I.IMG.FONT.CENTER.BR.HR.TABLE.THEAD.TBODY.TFOOT.TR.TH.TD.CAPTION.COLGROUP.COL".split(".")).includes(e.tagName)) throw new b("UNSUPPORTED_ELEMENT", `Native snapshots do not support ${e.tagName}.`);
429
+ let f = !n && e.hasAttribute("data-raster"), p = !n && !f && r === "auto" ? N(d) : void 0, m = a || p !== void 0;
430
+ if (m && (a && N(d), I(e, d, !0), L(e, d)), n && (d.transform !== "none" || d.writingMode !== "horizontal-tb" || d.direction !== "ltr" || d.opacity === "0" || d.clipPath !== "none" || d.maskImage !== "none" || d.overflowX !== "visible" || d.overflowY !== "visible")) {
431
+ l.push({
432
+ code: "RASTER_TEXT_OMITTED",
433
+ message: `Raster text extraction omitted for transformed, clipped, hidden, masked, or non-LTR subtree ${e.tagName}.`
434
+ });
435
+ return;
436
+ }
437
+ let h = P(e.getBoundingClientRect(), i);
438
+ if (!n && (h.x < -.1 || h.y < -.1 || h.x + h.width > i.width + .1 || h.y + h.height > i.height + .1)) throw new b("SOURCE_OVERFLOW", "Source content must fit within the root border box.");
439
+ let g = f || p !== void 0;
440
+ if (g) {
441
+ if (d.position !== "static" || d.transform !== "none" || d.mixBlendMode !== "normal") throw new b("UNSUPPORTED_CSS", "A raster boundary must be static, untransformed, and independently compositable.");
442
+ if (p !== void 0 && ce(e, d), s.push({
443
+ kind: "raster",
444
+ bounds: h,
445
+ element: e
446
+ }), l.push({
447
+ code: "RASTER_FALLBACK",
448
+ message: `${p === void 0 ? "An explicit raster subtree" : `Automatic raster fallback on ${e.tagName} for ${p}`} uses invisible PDF text for extraction where supported; generated content and clipped or transformed text are not represented.`
449
+ }), d.overflowX !== "visible" || d.overflowY !== "visible" || d.clipPath !== "none" || d.maskImage !== "none" || d.opacity === "0") {
450
+ l.push({
451
+ code: "RASTER_TEXT_OMITTED",
452
+ message: `Raster text extraction omitted for clipped, masked, or hidden boundary ${e.tagName}.`
453
+ });
454
+ return;
455
+ }
456
+ } else if (!n) {
457
+ if (I(e, d), L(e, d), (e instanceof HTMLTableRowElement || e instanceof HTMLTableCellElement && e.rowSpan !== 1) && c.push(h), e instanceof HTMLImageElement) {
458
+ if (d.objectFit !== "fill" || d.borderTopWidth !== "0px") throw new b("UNSUPPORTED_CSS", "Image boxes require object-fit: fill without borders.");
459
+ if ([
460
+ "paddingTop",
461
+ "paddingRight",
462
+ "paddingBottom",
463
+ "paddingLeft"
464
+ ].some((e) => Number.parseFloat(d.getPropertyValue(e.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`))) !== 0) || d.backgroundColor !== "rgba(0, 0, 0, 0)") throw new b("UNSUPPORTED_CSS", "Image boxes require zero padding and a transparent background.");
465
+ s.push({
466
+ kind: "image",
467
+ bounds: h,
468
+ element: e
469
+ });
470
+ } else [
471
+ "BR",
472
+ "COL",
473
+ "COLGROUP"
474
+ ].includes(e.tagName) || s.push({
475
+ kind: "box",
476
+ bounds: h,
477
+ background: d.backgroundColor,
478
+ borderColor: d.borderTopColor,
479
+ borderWidth: Number.parseFloat(d.borderTopWidth)
480
+ });
481
+ }
482
+ let _ = n || g;
483
+ if (!_ || m) {
484
+ let t = Array.from(e.children).filter((e) => e instanceof HTMLElement && getComputedStyle(e).display !== "none" && getComputedStyle(e).visibility !== "hidden").map((e) => e.getBoundingClientRect());
485
+ for (let e = 0; e < t.length; e += 1) for (let n = e + 1; n < t.length; n += 1) {
486
+ let r = t[e], i = t[n];
487
+ if (Math.min(r.right, i.right) - Math.max(r.left, i.left) > .1 && Math.min(r.bottom, i.bottom) - Math.max(r.top, i.top) > .1) throw new b("UNSUPPORTED_CSS", "Overlapping sibling boxes are unsupported; isolate them in one raster subtree.");
488
+ }
489
+ }
490
+ for (let n of e.childNodes) if (n instanceof Text) s.push(...R(n, i, t, o, _));
491
+ else if (n instanceof HTMLElement) u(n, _, m);
492
+ else if (n instanceof Element) {
493
+ if (_) l.push({
494
+ code: "RASTER_TEXT_OMITTED",
495
+ message: `Raster text extraction omitted for ${n.tagName}.`
496
+ });
497
+ else throw new b("UNSUPPORTED_ELEMENT", `Cannot snapshot ${n.tagName}; use a raster subtree.`);
498
+ }
499
+ }
500
+ u(e, !1);
501
+ let d = [];
502
+ for (let e of s) {
503
+ if (e.kind === "text") {
504
+ e.invisible || d.push(e);
505
+ continue;
506
+ }
507
+ if (e.kind === "box" && (e.background.startsWith("rgba(") ? Number(e.background.slice(e.background.lastIndexOf(",") + 1, -1)) : 1) === 0 && e.borderWidth === 0) continue;
508
+ let t = e.bounds;
509
+ if (d.some((e) => Math.min(e.bounds.x + e.bounds.width, t.x + t.width) - Math.max(e.bounds.x, t.x) > .1 && Math.min(e.bounds.y + e.bounds.height, t.y + t.height) - Math.max(e.bounds.y, t.y) > .1)) throw new b("UNSUPPORTED_CSS", "Text overlaps later visible paint whose CSS paint phases cannot be represented safely; use an explicit containing raster region.");
510
+ }
511
+ if (s.some((e) => {
512
+ if (e.kind === "text" && e.invisible) return !1;
513
+ let t = e.bounds;
514
+ return t.x < -.1 || t.y < -.1 || t.x + t.width > i.width + .1 || t.y + t.height > i.height + .1;
515
+ })) throw new b("SOURCE_OVERFLOW", "Visible source text or paint overflows the root border box.");
516
+ return {
517
+ width: i.width,
518
+ height: i.height,
519
+ operations: s,
520
+ warnings: l,
521
+ atomicBounds: c
522
+ };
523
+ }
524
+ // src/page.ts
525
+ function V(e) {
526
+ if (!e || !Array.isArray(e.fonts) || e.fonts.length === 0) throw new b("INVALID_OPTIONS", "Provide at least one explicitly registered font.");
527
+ let t = {
528
+ A4: [595.28, 841.89],
529
+ A3: [841.89, 1190.55],
530
+ Letter: [612, 792]
531
+ }, n = e.format ?? "A4";
532
+ if (typeof n != "object" && !Object.hasOwn(t, n)) throw new b("INVALID_OPTIONS", `Unsupported page format: ${n}.`);
533
+ let r = e.orientation ?? "portrait";
534
+ if (r !== "portrait" && r !== "landscape") throw new b("INVALID_OPTIONS", `Unsupported page orientation: ${r}.`);
535
+ let i = e.margin ?? 24, a = typeof i == "number" ? {
536
+ top: i,
537
+ right: i,
538
+ bottom: i,
539
+ left: i
540
+ } : {
541
+ top: i?.top,
542
+ right: i?.right,
543
+ bottom: i?.bottom,
544
+ left: i?.left
545
+ };
546
+ if (Object.values(a).some((e) => !Number.isFinite(e) || e < 0)) throw new b("INVALID_OPTIONS", "Every page margin must be finite and nonnegative.");
547
+ let o = typeof n == "object" ? [n?.width, n?.height] : t[n].map((e) => e / .75);
548
+ if (o.some((e) => !Number.isFinite(e) || e <= 0)) throw new b("INVALID_OPTIONS", "Custom page width and height must be finite positive CSS pixel values.");
549
+ let s = o[r === "portrait" ? 0 : 1], c = o[+(r === "portrait")];
550
+ if (a.left + a.right >= s || a.top + a.bottom >= c) throw new b("INVALID_OPTIONS", "Page margins leave no positive content area.");
551
+ if (e.rasterScale !== void 0 && (!Number.isFinite(e.rasterScale) || e.rasterScale <= 0)) throw new b("INVALID_OPTIONS", "Raster scale must be a finite positive number.");
552
+ if (e.onWarning !== void 0 && typeof e.onWarning != "function") throw new b("INVALID_OPTIONS", "onWarning must be a function.");
553
+ if (e.fallback !== void 0 && !["auto", "strict"].includes(e.fallback)) throw new b("INVALID_OPTIONS", "fallback must be auto or strict.");
554
+ if (e.pageBreak !== void 0 && !["auto", "css"].includes(e.pageBreak)) throw new b("INVALID_OPTIONS", "pageBreak must be auto or css.");
555
+ if (e.signal !== void 0 && !(e.signal instanceof AbortSignal)) throw new b("INVALID_OPTIONS", "signal must be an AbortSignal.");
556
+ return {
557
+ width: s,
558
+ height: c,
559
+ margin: a
560
+ };
561
+ }
562
+ // src/pagination.ts
563
+ var H = .01;
564
+ function U(e, t, n) {
565
+ if (![
566
+ e.x,
567
+ e.y,
568
+ e.width,
569
+ e.height
570
+ ].every(Number.isFinite) || e.width < 0 || e.height < 0 || e.y < -.01 || e.y + e.height > t + H) throw new b("PAGINATION_FAILED", `${n} geometry must be finite, nonnegative and within the source height.`);
571
+ }
572
+ function W(e, t) {
573
+ return e.y < t - H && e.y + e.height > t + H;
574
+ }
575
+ function ue(e, t, n) {
576
+ let r = e;
577
+ for (;;) {
578
+ let e = n.reduce((e, t) => W(t, r) ? Math.min(e, t.y) : e, r);
579
+ if (e === r) return r;
580
+ if (e <= t + H) throw new b("PAGINATION_FAILED", "Overlapping atomic items cannot fit on one page.");
581
+ r = e;
582
+ }
583
+ }
584
+ function de(e, t, n) {
585
+ if (!Number.isFinite(t) || t <= 0) throw new b("PAGINATION_FAILED", "Page content height must be finite and positive.");
586
+ if (!Number.isFinite(e.height) || e.height <= 0) throw new b("PAGINATION_FAILED", "Source height must be finite and positive.");
587
+ let r = [], i = [...e.operations.filter((e) => e.kind !== "box").map((e) => e.bounds), ...e.atomicBounds ?? []];
588
+ for (let n of i) if (U(n, e.height, "Atomic"), n.height > t + H) throw new b("PAGINATION_FAILED", "An atomic item is taller than one page; this renderer cannot split it.");
589
+ let a = e.forcedBreaks ?? [];
590
+ for (let t of a) if (!Number.isFinite(t) || t < 0 || t > e.height) throw new b("PAGINATION_FAILED", "Forced page breaks must lie within the finite source height.");
591
+ let o = [...new Set(a)].filter((t) => t > H && t < e.height - H).sort((e, t) => e - t).filter((e, t, n) => t === 0 || e - n[t - 1] > H);
592
+ for (let e of o) if (i.some((t) => W(t, e))) throw new b("PAGINATION_FAILED", "A forced CSS page break crosses an atomic text, image, raster, table row or spanning cell.");
593
+ let s = !1;
594
+ function c() {
595
+ s || (s = !0, n?.({
596
+ code: "BREAK_AVOID_RELAXED",
597
+ message: "A CSS break-avoid preference could not fit on one page and was relaxed; native text, images and table rows remain indivisible."
598
+ }));
599
+ }
600
+ let l = [];
601
+ for (let n of e.avoidBreakBounds ?? []) U(n, e.height, "Preferred break-avoid"), !o.some((e) => W(n, e)) && (n.height > t + H ? c() : l.push(n));
602
+ let u = [...i, ...l], d = 0, f = 0;
603
+ for (; d < e.height;) {
604
+ for (; o[f] !== void 0 && o[f] <= d + H;) f += 1;
605
+ let n = o[f] ?? e.height, a = Math.min(d + t, n, e.height), s = ue(a, d, i), l = s;
606
+ if (Math.abs(a - n) > H) for (;;) {
607
+ let e = u.reduce((e, t) => W(t, l) ? Math.min(e, t.y) : e, l);
608
+ if (e === l) break;
609
+ if (e <= d + H) {
610
+ c(), l = s;
611
+ break;
612
+ }
613
+ l = e;
614
+ }
615
+ r.push({
616
+ start: d,
617
+ end: l
618
+ }), d = l;
619
+ }
620
+ return r;
621
+ }
622
+ // src/images.ts
623
+ function G() {
624
+ throw new b("RESOURCE_LOAD_FAILED", "JPEG EXIF orientation must be 1 with valid metadata; normalize the image pixels and remove orientation metadata before exporting.");
625
+ }
626
+ function fe(e, t, n) {
627
+ let r = new DataView(e.buffer, e.byteOffset + t, n - t);
628
+ r.byteLength < 8 && G();
629
+ let i = r.getUint16(0);
630
+ i !== 18761 && i !== 19789 && G();
631
+ let a = i === 18761;
632
+ r.getUint16(2, a) !== 42 && G();
633
+ let o = r.getUint32(4, a);
634
+ (o < 8 || o + 2 > r.byteLength) && G();
635
+ let s = r.getUint16(o, a), c = o + 2 + s * 12;
636
+ c + 4 > r.byteLength && G();
637
+ let l = !1;
638
+ for (let e = 0; e < s; e += 1) {
639
+ let t = o + 2 + e * 12;
640
+ r.getUint16(t, a) === 274 && ((l || r.getUint16(t + 2, a) !== 3 || r.getUint32(t + 4, a) !== 1 || r.getUint16(t + 8, a) !== 1) && G(), l = !0);
641
+ }
642
+ let u = r.getUint32(c, a);
643
+ u !== 0 && (u < 8 || u + 2 > r.byteLength) && G();
644
+ }
645
+ function pe(e) {
646
+ if (e[0] === 137 && e[1] === 80 && e[2] === 78 && e[3] === 71 && e[4] === 13 && e[5] === 10 && e[6] === 26 && e[7] === 10) return "png";
647
+ if (e[0] !== 255 || e[1] !== 216) throw new b("RESOURCE_LOAD_FAILED", "Native PDF images require PNG or JPEG bytes.");
648
+ let t = 2;
649
+ for (; t < e.length;) {
650
+ for (e[t] !== 255 && G(); e[t] === 255;) t += 1;
651
+ let n = e[t];
652
+ if ((n === void 0 || n === 0) && G(), t += 1, n === 217) return "jpeg";
653
+ if (n === 1 || n >= 208 && n <= 215) continue;
654
+ t + 2 > e.length && G();
655
+ let r = e[t] * 256 + e[t + 1], i = t + r;
656
+ if ((r < 2 || i > e.length) && G(), n === 218) return "jpeg";
657
+ let a = t + 2;
658
+ n === 225 && i - a >= 4 && e[a] === 69 && e[a + 1] === 120 && e[a + 2] === 105 && e[a + 3] === 102 && ((i - a < 6 || e[a + 4] !== 0 || e[a + 5] !== 0) && G(), fe(e, a + 6, i)), t = i;
659
+ }
660
+ G();
661
+ }
662
+ // src/raster.ts
663
+ var me = 16777216, K = 8192, q = /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z\d+/=\s]+$/i;
664
+ function he(e) {
665
+ let t = e.bytes;
666
+ if (!/^[\w -]+$/.test(e.family) || t.byteLength === 0) throw new b("RASTER_FAILED", "Raster capture requires nonempty registered fonts with plain CSS family names.");
667
+ let n = "";
668
+ for (let e = 0; e < t.length; e += 8192) n += String.fromCharCode(...t.subarray(e, e + 8192));
669
+ let r = t[0] === 79 && t[1] === 84 && t[2] === 84 && t[3] === 79;
670
+ return `@font-face { font-family: "${e.family}"; font-weight: ${e.weight}; font-style: ${e.style}; src: url("data:font/${r ? "otf" : "ttf"};base64,${btoa(n)}") format("${r ? "opentype" : "truetype"}"); }`;
671
+ }
672
+ function ge(e) {
673
+ for (let t of e) {
674
+ let n = e.getPropertyValue(t);
675
+ for (let e of n.matchAll(/url\(\s*(["']?)(.*?)\1\s*\)/gi)) if (!q.test(e[2] ?? "")) throw new b("RASTER_FAILED", `Raster capture requires inline bitmap resources (${t}).`);
676
+ }
677
+ }
678
+ function _e(e, t) {
679
+ let n = e.getBoundingClientRect(), r = [e, ...e.querySelectorAll("*")];
680
+ for (let i of r) {
681
+ if (!(i instanceof HTMLElement)) throw new b("RASTER_FAILED", "Raster capture supports HTML subtrees only; inline SVG needs a separate experiment.");
682
+ if (i.shadowRoot || i.tagName.includes("-") || i.tagName === "SLOT") throw new b("RASTER_FAILED", "Raster capture does not inspect shadow trees or distributed slot content in supported renderer.");
683
+ if (/^(CANVAS|IFRAME|OBJECT|EMBED|VIDEO|AUDIO|INPUT|TEXTAREA|SELECT|SCRIPT|STYLE|LINK)$/.test(i.tagName)) throw new b("RASTER_FAILED", `Raster capture does not support ${i.tagName.toLowerCase()} elements.`);
684
+ let r = getComputedStyle(i);
685
+ if (ge(r), r.mixBlendMode !== "normal" || r.backdropFilter !== "none") throw new b("RASTER_FAILED", "Raster capture cannot reproduce blending with pixels outside its subtree.");
686
+ if (r.position === "fixed" || r.position === "sticky") throw new b("RASTER_FAILED", "Raster capture does not reproduce viewport-dependent positioning.");
687
+ if (i !== e && r.position === "absolute") throw new b("RASTER_FAILED", "Raster capture does not normalize external containing blocks for positioned descendants.");
688
+ let a = r.boxShadow.split(/,(?![^(]*\))/);
689
+ if (r.filter !== "none" || r.boxShadow !== "none" && a.some((e) => !e.includes("inset"))) throw new b("RASTER_FAILED", "Raster capture requires effects contained in the border box; outer shadows and filters need expanded bounds.");
690
+ if (r.textShadow !== "none" || r.outlineStyle !== "none" && Number.parseFloat(r.outlineWidth) > 0) throw new b("RASTER_FAILED", "Raster capture requires expanded bounds before capturing text shadows or outlines.");
691
+ if (r.backgroundAttachment.includes("fixed")) throw new b("RASTER_FAILED", "Raster capture does not preserve viewport-dependent background attachment.");
692
+ if (i === e && r.transform !== "none") throw new b("RASTER_FAILED", "Raster capture does not normalize transformed region coordinates.");
693
+ if (r.display === "list-item") throw new b("RASTER_FAILED", "Raster capture does not preserve generated list markers in supported renderer.");
694
+ for (let e of ["::before", "::after"]) {
695
+ let t = getComputedStyle(i, e).content;
696
+ if (t !== "none" && t !== "normal") throw new b("RASTER_FAILED", "Raster capture does not support generated pseudo-element content in supported renderer.");
697
+ }
698
+ if (i instanceof HTMLImageElement) {
699
+ if (i.srcset || !q.test(i.currentSrc || i.src)) throw new b("RASTER_FAILED", "Raster capture requires inline bitmap images without srcset.");
700
+ if (!i.complete || i.naturalWidth === 0) throw new b("RASTER_FAILED", "Raster capture requires successfully decoded images.");
701
+ }
702
+ if ([...i.childNodes].some((e) => e.nodeType === Node.TEXT_NODE && !!e.textContent?.trim())) {
703
+ if (!r.font) throw new b("RASTER_FAILED", "Raster capture requires a serializable computed font shorthand to preserve exact font sizes.");
704
+ let e = r.fontFamily.split(",")[0]?.trim().replace(/^["']|["']$/g, "");
705
+ if (!t.some((t) => t.family.toLowerCase() === e?.toLowerCase() && t.weight === Number(r.fontWeight) && t.style === r.fontStyle)) throw new b("RASTER_FAILED", "Raster capture text requires an explicitly registered matching font face.");
706
+ }
707
+ let o = i.getBoundingClientRect();
708
+ if (o.width > 0 && o.height > 0 && (o.left < n.left - .5 || o.top < n.top - .5 || o.right > n.right + .5 || o.bottom > n.bottom + .5)) throw new b("RASTER_FAILED", "Raster capture descendants must stay inside the selected border box.");
709
+ }
710
+ }
711
+ async function ve(e, t, n, r = {
712
+ x: 0,
713
+ y: 0
714
+ }) {
715
+ if (!e.isConnected || e.ownerDocument !== document) throw new b("RASTER_FAILED", "Raster capture requires a connected element in the current document.");
716
+ if (!Number.isFinite(n) || n <= 0) throw new b("RASTER_FAILED", "Raster scale must be a finite positive number.");
717
+ if (!r || ![r.x, r.y].every((e) => Number.isFinite(e) && e >= 0 && e < 1)) throw new b("RASTER_FAILED", "Raster offsets must be finite CSS pixel fractions from zero inclusive to one exclusive.");
718
+ await document.fonts.ready;
719
+ let { width: i, height: a } = e.getBoundingClientRect(), o = Math.ceil(i + r.x), s = Math.ceil(a + r.y), c = Math.ceil(o * n), l = Math.ceil(s * n);
720
+ if (i <= 0 || a <= 0 || c < 1 || l < 1 || c > K || l > K || c * l > me) throw new b("RASTER_FAILED", "Raster region exceeds the supported renderer canvas budget or has empty bounds.");
721
+ _e(e, t);
722
+ let u = t.map(he).join("\n"), d = ["font", ...Array.from(getComputedStyle(e)).filter((e) => e !== "font-size")], f = (await y(e, {
723
+ width: o,
724
+ height: s,
725
+ pixelRatio: n,
726
+ skipAutoScale: !0,
727
+ fontEmbedCSS: u,
728
+ includeStyleProperties: d,
729
+ style: {
730
+ margin: "0",
731
+ top: "0",
732
+ left: "0",
733
+ right: "auto",
734
+ bottom: "auto",
735
+ boxSizing: "border-box",
736
+ width: `${i}px`,
737
+ height: `${a}px`,
738
+ transform: `translate(${r.x}px, ${r.y}px)`
739
+ }
740
+ })).match(/^data:image\/png;base64,(.+)$/)?.[1];
741
+ if (!f) throw new b("RASTER_FAILED", "Raster capture produced an empty or invalid PNG.");
742
+ let p = atob(f);
743
+ return Uint8Array.from(p, (e) => e.charCodeAt(0));
744
+ }
745
+ // src/text.ts
746
+ var ye = class {
747
+ font;
748
+ program;
749
+ words = /* @__PURE__ */ new Map();
750
+ unicode = /* @__PURE__ */ new Map();
751
+ widths = /* @__PURE__ */ new Map();
752
+ unitsPerEm;
753
+ constructor(t, n) {
754
+ this.font = t, this.program = e.create(n), this.unitsPerEm = this.program.unitsPerEm;
755
+ }
756
+ shape(e, t = !0) {
757
+ let n = `${t ? "1" : "0"}:${e}`, r = this.words.get(n);
758
+ if (r) return r;
759
+ let a = this.program.layout(e, { kern: t }), o = this.font.encodeText(e).asString();
760
+ if (o.length !== a.glyphs.length * 4) throw new b("PDF_WRITE_FAILED", "PDF font encoding disagrees with font shaping.");
761
+ let s = 0, c = 0, l = a.glyphs.map((e, t) => {
762
+ let n = o.slice(t * 4, t * 4 + 4);
763
+ if (Number.parseInt(n, 16) !== e.id) throw new b("PDF_WRITE_FAILED", "PDF glyph identifiers disagree with shaping.");
764
+ if (e.codePoints.length === 0) throw new b("PDF_WRITE_FAILED", "The font produced a shaped glyph without a Unicode source mapping.");
765
+ let r = a.positions[t];
766
+ this.unicode.has(n) || this.unicode.set(n, [...e.codePoints]), this.widths.set(n, e.advanceWidth * 1e3 / this.unitsPerEm);
767
+ let l = {
768
+ encoded: i.of(n),
769
+ x: s + r.xOffset,
770
+ y: c + r.yOffset
771
+ };
772
+ return s += r.xAdvance, c += r.yAdvance, l;
773
+ });
774
+ return this.words.set(n, l), l;
775
+ }
776
+ async embedUnicode(e) {
777
+ if (await this.font.embed(), this.unicode.size === 0) return;
778
+ let r = [...this.unicode].map(([e, t]) => {
779
+ let n = String.fromCodePoint(...t), r = "";
780
+ for (let e = 0; e < n.length; e += 1) r += n.charCodeAt(e).toString(16).padStart(4, "0");
781
+ return `<${e}> <${r}>`;
782
+ }), i = [];
783
+ for (let e = 0; e < r.length; e += 100) {
784
+ let t = r.slice(e, e + 100);
785
+ i.push(`${t.length} beginbfchar\n${t.join("\n")}\nendbfchar`);
786
+ }
787
+ let o = [
788
+ "/CIDInit /ProcSet findresource begin",
789
+ "12 dict begin",
790
+ "begincmap",
791
+ "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def",
792
+ "/CMapName /RenderPDFUnicode def",
793
+ "/CMapType 2 def",
794
+ "1 begincodespacerange",
795
+ "<0000> <ffff>",
796
+ "endcodespacerange",
797
+ ...i,
798
+ "endcmap",
799
+ "CMapName currentdict /CMap defineresource pop",
800
+ "end",
801
+ "end"
802
+ ].join("\n"), s = e.context.lookup(this.font.ref, n);
803
+ s.set(a.of("ToUnicode"), e.context.register(e.context.flateStream(o)));
804
+ let c = s.lookup(a.of("DescendantFonts"), t).lookup(0, n), l = [...this.widths].sort(([e], [t]) => Number.parseInt(e, 16) - Number.parseInt(t, 16)).flatMap(([e, t]) => [Number.parseInt(e, 16), [t]]);
805
+ c.set(a.of("W"), e.context.obj(l));
806
+ }
807
+ }, J = .75;
808
+ function Y(e) {
809
+ let t = e.match(/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/);
810
+ if (!t) throw new b("UNSUPPORTED_CSS", `Unsupported computed color: ${e}`);
811
+ return {
812
+ color: m(Number(t[1]) / 255, Number(t[2]) / 255, Number(t[3]) / 255),
813
+ opacity: Number(t[4] ?? 1)
814
+ };
815
+ }
816
+ function X(e, t) {
817
+ let n = t.find(({ definition: t }) => t.family.toLowerCase() === e.family.toLowerCase() && t.weight === e.weight && t.style === e.style);
818
+ if (!n) throw new b("MISSING_FONT", `Unregistered font face: ${e.family} ${e.weight} ${e.style}`);
819
+ for (let t of e.text) if (!n.characters.has(t.codePointAt(0))) throw new b("MISSING_GLYPH", `Missing glyph: ${t} (${e.family} ${e.weight} ${e.style})`);
820
+ return n;
821
+ }
822
+ function be(e, t, n, r, i, a) {
823
+ let c = Y(t.color), l = a.fonts.get(n.font);
824
+ if (l || (l = e.node.newFontDictionary(n.font.name, n.font.ref), a.fonts.set(n.font, l)), e.pushOperators(f(), h(c.color)), c.opacity !== 1) {
825
+ let t = a.opacity.get(c.opacity);
826
+ t || (t = e.node.newExtGState("TextOpacity", e.doc.context.obj({
827
+ Type: "ExtGState",
828
+ ca: c.opacity
829
+ })), a.opacity.set(c.opacity, t)), e.pushOperators(_(t));
830
+ }
831
+ e.pushOperators(s(), g(l, t.fontSize * J), ee(t.invisible ? o.Invisible : o.Fill));
832
+ let p = t.fontSize * J / n.positioned.unitsPerEm, m = (i.height - i.margin.top - (t.baseline - r)) * J;
833
+ for (let r of t.runs) {
834
+ let a = (i.margin.left + r.x) * J;
835
+ for (let i of n.positioned.shape(r.text, t.kerning ?? !0)) e.pushOperators(v(1, 0, 0, 1, a + i.x * p, m + i.y * p), te(i.encoded));
836
+ }
837
+ e.pushOperators(u(), d());
838
+ }
839
+ function Z(e) {
840
+ let t = Math.floor(e.x), n = Math.floor(e.y);
841
+ return {
842
+ x: t,
843
+ y: n,
844
+ width: Math.ceil(e.x + e.width) - t,
845
+ height: Math.ceil(e.y + e.height) - n
846
+ };
847
+ }
848
+ async function xe(e, t, n) {
849
+ let r = t.currentSrc || t.src;
850
+ try {
851
+ x(n);
852
+ let t = await fetch(r, {
853
+ mode: "cors",
854
+ credentials: "same-origin",
855
+ ...n ? { signal: n } : {}
856
+ });
857
+ if (!t.ok) throw Error(`Image request returned HTTP ${t.status}.`);
858
+ let i = new Uint8Array(await t.arrayBuffer());
859
+ return x(n), pe(i) === "png" ? await e.embedPng(i) : await e.embedJpg(i);
860
+ } catch (e) {
861
+ throw x(n), e instanceof b ? e : new b("RESOURCE_LOAD_FAILED", "The source image could not be embedded; provide a readable PNG/JPEG with same-origin or CORS access.", { cause: e });
862
+ }
863
+ }
864
+ async function Q(t, n, i, a, o = {}) {
865
+ try {
866
+ if (x(o.signal), t.width > i.width - i.margin.left - i.margin.right) throw new b("SOURCE_OVERFLOW", "Source is wider than the PDF content area.");
867
+ let s = await r.create();
868
+ x(o.signal), s.registerFontkit(e), s.setTitle("RenderPDF.js");
869
+ let u = [];
870
+ for (let e of n) {
871
+ x(o.signal);
872
+ let t = await s.embedFont(e.bytes);
873
+ u.push({
874
+ definition: e,
875
+ font: t,
876
+ characters: new Set(t.getCharacterSet()),
877
+ positioned: new ye(t, e.bytes)
878
+ });
879
+ }
880
+ for (let e of t.operations) e.kind !== "text" || e.invisible && o.includeRasterText === !1 || X(e, u);
881
+ let m = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map();
882
+ for (let e of t.operations) {
883
+ if (x(o.signal), e.kind === "raster") {
884
+ let t = Z(e.bounds);
885
+ try {
886
+ let r = await ve(e.element, n, o.rasterScale ?? 2, {
887
+ x: e.bounds.x - t.x,
888
+ y: e.bounds.y - t.y
889
+ });
890
+ x(o.signal), m.set(e, await s.embedPng(r));
891
+ } catch (e) {
892
+ throw x(o.signal), e instanceof b ? e : new b("RASTER_FAILED", "The selected local raster region could not be captured.", { cause: e });
893
+ }
894
+ }
895
+ if (e.kind === "image") {
896
+ let t = e.element.currentSrc || e.element.src, n = h.get(t);
897
+ n || (n = await xe(s, e.element, o.signal), h.set(t, n)), m.set(e, n);
898
+ }
899
+ }
900
+ for (let e of a) {
901
+ x(o.signal);
902
+ let n = s.addPage([i.width * J, i.height * J]), r = {
903
+ fonts: /* @__PURE__ */ new Map(),
904
+ opacity: /* @__PURE__ */ new Map()
905
+ };
906
+ n.pushOperators(f(), p(i.margin.left * J, (i.height - i.margin.top - (e.end - e.start)) * J, (i.width - i.margin.left - i.margin.right) * J, (e.end - e.start) * J), c(), l());
907
+ for (let a of t.operations) {
908
+ let t = a.bounds;
909
+ if (t.y >= e.end - .01 || t.y + t.height <= e.start + .01) continue;
910
+ if (a.kind === "text") {
911
+ a.invisible && o.includeRasterText === !1 || be(n, a, X(a, u), e.start, i, r);
912
+ continue;
913
+ }
914
+ let s = a.kind === "raster" ? Z(t) : t, c = {
915
+ x: (i.margin.left + s.x) * J,
916
+ y: (i.height - i.margin.top - (s.y - e.start) - s.height) * J,
917
+ width: s.width * J,
918
+ height: s.height * J
919
+ };
920
+ if (a.kind === "box") {
921
+ let e = Y(a.background), t = Y(a.borderColor);
922
+ if (n.drawRectangle({
923
+ ...c,
924
+ color: e.color,
925
+ opacity: e.opacity
926
+ }), a.borderWidth > 0) {
927
+ let e = a.borderWidth * J / 2;
928
+ n.drawRectangle({
929
+ x: c.x + e,
930
+ y: c.y + e,
931
+ width: c.width - e * 2,
932
+ height: c.height - e * 2,
933
+ borderWidth: a.borderWidth * J,
934
+ borderColor: t.color,
935
+ borderOpacity: t.opacity
936
+ });
937
+ }
938
+ } else n.drawImage(m.get(a), c);
939
+ }
940
+ n.pushOperators(d());
941
+ }
942
+ x(o.signal);
943
+ for (let e of u) await e.positioned.embedUnicode(s), x(o.signal);
944
+ let g = Uint8Array.from(await s.save());
945
+ return x(o.signal), {
946
+ bytes: g,
947
+ slices: a
948
+ };
949
+ } catch (e) {
950
+ throw x(o.signal), e instanceof b ? e : new b("PDF_WRITE_FAILED", "The measured content could not be serialized as a PDF.", { cause: e });
951
+ }
952
+ }
953
+ // src/prepare.ts
954
+ async function $(e, t) {
955
+ return x(t), t ? new Promise((n, r) => {
956
+ let i = () => r(new DOMException("PDF rendering was cancelled.", "AbortError"));
957
+ t.addEventListener("abort", i, { once: !0 }), e.then(n, r).finally(() => t.removeEventListener("abort", i));
958
+ }) : e;
959
+ }
960
+ function Se(e, t) {
961
+ if (x(t), typeof document > "u" || !(e instanceof HTMLElement) || !e.isConnected || e.ownerDocument !== document) throw new b("INVALID_SOURCE", "Provide a connected HTMLElement in the current document.");
962
+ let n = !1, r, i = /* @__PURE__ */ new Map(), a = new MutationObserver(() => {
963
+ n = !0;
964
+ }), o = [];
965
+ a.observe(e, {
966
+ subtree: !0,
967
+ attributes: !0,
968
+ childList: !0,
969
+ characterData: !0
970
+ });
971
+ let s = e.parentElement, c = e.getRootNode();
972
+ for (c instanceof ShadowRoot && (a.observe(c, {
973
+ subtree: !0,
974
+ attributes: !0,
975
+ childList: !0,
976
+ characterData: !0
977
+ }), s ??= c.host); s;) o.push(s), a.observe(s, { attributes: !0 }), s = s.parentElement ?? (s.getRootNode() instanceof ShadowRoot ? s.getRootNode().host : null);
978
+ a.observe(document.head, {
979
+ subtree: !0,
980
+ attributes: !0,
981
+ childList: !0,
982
+ characterData: !0
983
+ });
984
+ let l = Array.from(getComputedStyle(document.documentElement)).filter((e) => !e.startsWith("--"));
985
+ function u() {
986
+ let t = 2166136261, n = 5381;
987
+ function r(e) {
988
+ let r = i.get(e);
989
+ r === void 0 && (r = i.size + 1, i.set(e, r)), t = Math.imul(t ^ r, 16777619), n = Math.imul(n, 33) ^ r;
990
+ }
991
+ function a(e, t) {
992
+ let n = getComputedStyle(e, t);
993
+ if (r(t ?? "element"), t && (r(n.content), n.content === "none" || n.content === "normal")) return;
994
+ let i = n.length, a = i >= l.length ? l : [];
995
+ r(String(i));
996
+ for (let e = 0; e < i; e += 1) {
997
+ let t = a[e] ?? n[e];
998
+ e >= a.length && r(t), r(n.getPropertyValue(t));
999
+ }
1000
+ }
1001
+ let s = e.getBoundingClientRect();
1002
+ for (let e of o) a(e);
1003
+ for (let t of [e, ...e.querySelectorAll("*")]) {
1004
+ a(t), a(t, "::before"), a(t, "::after");
1005
+ let e = t.getBoundingClientRect();
1006
+ r(`${e.x - s.x},${e.y - s.y},${e.width},${e.height}`);
1007
+ }
1008
+ return `${t >>> 0}:${n >>> 0}`;
1009
+ }
1010
+ function d() {
1011
+ if (x(t), a.takeRecords().length && (n = !0), !e.isConnected || n || r !== void 0 && u() !== r) throw new b("SOURCE_CHANGED", "The source or its styles changed during PDF rendering. Retry with a stable source.");
1012
+ }
1013
+ function f() {
1014
+ if (d(), [...e.getAnimations({ subtree: !0 }), ...o.flatMap((e) => e.getAnimations())].some((e) => e.playState === "running")) throw new b("UNSUPPORTED_CSS", "Pause source animations before rendering a PDF.");
1015
+ r = u();
1016
+ }
1017
+ async function p() {
1018
+ await $(document.fonts.ready, t);
1019
+ try {
1020
+ await $(Promise.all([...e.querySelectorAll("img"), ...e instanceof HTMLImageElement ? [e] : []].map((e) => e.decode())), t);
1021
+ } catch (e) {
1022
+ throw x(t), new b("RESOURCE_LOAD_FAILED", "A source image could not be decoded.", { cause: e });
1023
+ }
1024
+ d();
1025
+ }
1026
+ return {
1027
+ ready: p,
1028
+ captureBaseline: f,
1029
+ assertUnchanged: d,
1030
+ dispose: () => a.disconnect()
1031
+ };
1032
+ }
1033
+ // src/result.ts
1034
+ function Ce(e, t, n) {
1035
+ let r = Uint8Array.from(e), i = Object.freeze(n.map((e) => Object.freeze({ ...e })));
1036
+ return Object.freeze({
1037
+ pageCount: t,
1038
+ warnings: i,
1039
+ async toUint8Array() {
1040
+ return Uint8Array.from(r);
1041
+ },
1042
+ async toBlob() {
1043
+ return new Blob([r], { type: "application/pdf" });
1044
+ },
1045
+ async download(e = "document.pdf") {
1046
+ if (typeof e != "string" || !e.trim() || /[/\\]/.test(e) || [...e].some((e) => e.codePointAt(0) < 32)) throw new b("INVALID_OPTIONS", "Provide a nonempty PDF filename without path separators or control characters.");
1047
+ let t = URL.createObjectURL(new Blob([r], { type: "application/pdf" }));
1048
+ try {
1049
+ let n = document.createElement("a");
1050
+ n.href = t, n.download = e, n.click();
1051
+ } finally {
1052
+ window.setTimeout(() => URL.revokeObjectURL(t), 1e3);
1053
+ }
1054
+ }
1055
+ });
1056
+ }
1057
+ // src/render-pdf.ts
1058
+ async function we(e, t, n = !0) {
1059
+ let r = V(t), i = [...t.fonts];
1060
+ A(i);
1061
+ let { signal: a, onWarning: o, rasterScale: s = 2, fallback: c = "auto", pageBreak: l = "css" } = t, u = Se(e, a);
1062
+ try {
1063
+ await u.ready(), u.assertUnchanged();
1064
+ let t = B(e, i, { fallback: c });
1065
+ if (u.captureBaseline(), t.width > r.width - r.margin.left - r.margin.right) throw new b("SOURCE_OVERFLOW", "Source is wider than the configured page content area. Set the source width explicitly; no implicit scaling is applied.");
1066
+ l === "css" && Object.assign(t, ae(e, t));
1067
+ let d = [], f = de(t, r.height - r.margin.top - r.margin.bottom, (e) => d.push(e)), p = [...t.warnings, ...d];
1068
+ t.operations.some((e) => e.kind === "text") && !p.some((e) => e.code === "TEXT_METRICS_APPROXIMATED") && p.unshift({
1069
+ code: "TEXT_METRICS_APPROXIMATED",
1070
+ message: "PDF text uses browser word origins and approximate baseline/kerning metrics; full glyph shaping fidelity is not guaranteed."
1071
+ });
1072
+ for (let e of p) o?.(Object.freeze(e));
1073
+ o && u.assertUnchanged();
1074
+ let m = await $(Q(t, i, r, f, {
1075
+ rasterScale: s,
1076
+ includeRasterText: n,
1077
+ ...a ? { signal: a } : {}
1078
+ }), a);
1079
+ return u.assertUnchanged(), A(i), x(a), {
1080
+ ...m,
1081
+ snapshot: t,
1082
+ warnings: p
1083
+ };
1084
+ } finally {
1085
+ u.dispose();
1086
+ }
1087
+ }
1088
+ async function Te(e, t) {
1089
+ let n = await we(e, t);
1090
+ return Ce(n.bytes, n.slices.length, n.warnings);
1091
+ }
1092
+ export { b as RenderPDFError, se as registerFont, Te as renderPDF };