renderpdf-js 0.1.0 → 0.2.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 +176 -10
- package/dist/api-types.d.ts +63 -4
- package/dist/diagnostics.d.ts +1 -1
- package/dist/export-options.d.ts +12 -0
- package/dist/image-geometry.d.ts +19 -0
- package/dist/image-input.d.ts +19 -0
- package/dist/image-pdf.d.ts +7 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1659 -363
- package/dist/layout.d.ts +4 -0
- package/dist/page-bands.d.ts +24 -0
- package/dist/page.d.ts +7 -3
- package/dist/pagination.d.ts +5 -1
- package/dist/pdf.d.ts +10 -1
- package/dist/progress.d.ts +11 -0
- package/dist/table-borders.d.ts +52 -0
- package/dist/text.d.ts +9 -0
- package/dist/tiff.d.ts +23 -0
- package/dist/types.d.ts +27 -1
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
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,
|
|
3
|
-
import { toPng as
|
|
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, concatTransformationMatrix as l, drawObject as u, endPath as d, endText as f, popGraphicsState as p, pushGraphicsState as m, rectangle as h, rgb as g, setFillingColor as _, setFontAndSize as v, setGraphicsState as y, setTextMatrix as b, setTextRenderingMode as x, showText as S } from "pdf-lib";
|
|
3
|
+
import { toPng as C } from "html-to-image";
|
|
4
4
|
// src/diagnostics.ts
|
|
5
|
-
var
|
|
5
|
+
var w = class extends Error {
|
|
6
6
|
code;
|
|
7
7
|
constructor(e, t, n) {
|
|
8
8
|
super(t, n), this.code = e, this.name = "RenderPDFError";
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
|
-
function
|
|
11
|
+
function T(e) {
|
|
12
12
|
if (e?.aborted) throw new DOMException("PDF rendering was cancelled.", "AbortError");
|
|
13
13
|
}
|
|
14
14
|
// src/breaks.ts
|
|
15
|
-
var
|
|
15
|
+
var E = /* @__PURE__ */ new Set([
|
|
16
16
|
"block",
|
|
17
17
|
"flow-root",
|
|
18
18
|
"flex",
|
|
@@ -24,14 +24,14 @@ var S = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"table-header-group",
|
|
25
25
|
"table-footer-group"
|
|
26
26
|
]);
|
|
27
|
-
function
|
|
27
|
+
function D(e, t) {
|
|
28
28
|
let n = e.getPropertyValue(`break-${t}`).trim(), r = e.getPropertyValue(`page-break-${t}`).trim();
|
|
29
29
|
return n && n !== "auto" ? n : r || n || "auto";
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
if (e !== "auto" && e !== "avoid" && e !== "avoid-page" && (t === "inside" || e !== "page" && e !== "always")) throw new
|
|
31
|
+
function O(e, t) {
|
|
32
|
+
if (e !== "auto" && e !== "avoid" && e !== "avoid-page" && (t === "inside" || e !== "page" && e !== "always")) throw new w("UNSUPPORTED_CSS", `Unsupported CSS break-${t}: ${e}; only page/always boundaries and avoid/avoid-page preferences are supported.`);
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function ee(e, t) {
|
|
35
35
|
let n = e.getBoundingClientRect();
|
|
36
36
|
return {
|
|
37
37
|
x: n.left - t.left,
|
|
@@ -40,20 +40,20 @@ function T(e, t) {
|
|
|
40
40
|
height: n.height
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function te(e) {
|
|
44
44
|
let t = getComputedStyle(e), n = e.getBoundingClientRect();
|
|
45
|
-
return t.visibility === "visible" &&
|
|
45
|
+
return t.visibility === "visible" && E.has(t.display) && n.width > 0 && n.height > 0;
|
|
46
46
|
}
|
|
47
|
-
function
|
|
47
|
+
function ne(e, t) {
|
|
48
48
|
let n = t === "previous" ? e.previousElementSibling : e.nextElementSibling;
|
|
49
49
|
for (; n;) {
|
|
50
50
|
if (!(n instanceof HTMLElement)) return;
|
|
51
51
|
let e = getComputedStyle(n);
|
|
52
|
-
if (e.display !== "none" && e.visibility === "visible") return
|
|
52
|
+
if (e.display !== "none" && e.visibility === "visible") return te(n) ? n : void 0;
|
|
53
53
|
n = t === "previous" ? n.previousElementSibling : n.nextElementSibling;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
function
|
|
56
|
+
function re(e, t) {
|
|
57
57
|
let n = Math.min(e.x, t.x), r = Math.min(e.y, t.y);
|
|
58
58
|
return {
|
|
59
59
|
x: n,
|
|
@@ -62,8 +62,8 @@ function ie(e, t) {
|
|
|
62
62
|
height: Math.max(e.y + e.height, t.y + t.height) - r
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
function
|
|
66
|
-
if (!e.isConnected || e.ownerDocument !== document) throw new
|
|
65
|
+
function ie(e, t) {
|
|
66
|
+
if (!e.isConnected || e.ownerDocument !== document) throw new w("INVALID_SOURCE", "CSS page-break collection requires a connected source in the current document.");
|
|
67
67
|
let n = e.getBoundingClientRect(), r = t.operations.filter((e) => e.kind === "raster"), i = /* @__PURE__ */ new Map(), a = [];
|
|
68
68
|
for (let t of [e, ...e.querySelectorAll("*")]) {
|
|
69
69
|
if (!(t instanceof HTMLElement)) continue;
|
|
@@ -71,25 +71,25 @@ function ae(e, t) {
|
|
|
71
71
|
if (e.display === "none" || e.visibility !== "visible") continue;
|
|
72
72
|
let o = t.getBoundingClientRect();
|
|
73
73
|
if (o.width === 0 && o.height === 0 && t.getClientRects().length === 0) continue;
|
|
74
|
-
let s =
|
|
75
|
-
|
|
74
|
+
let s = D(e, "before"), c = D(e, "after"), l = D(e, "inside");
|
|
75
|
+
O(s, "before"), O(c, "after"), O(l, "inside");
|
|
76
76
|
let u = r.find((e) => e.element.contains(t));
|
|
77
|
-
if (!u &&
|
|
77
|
+
if (!u && E.has(e.display) && (e.widows && e.widows !== "2" || e.orphans && e.orphans !== "2")) throw new w("UNSUPPORTED_CSS", "Nondefault CSS widows/orphans are unsupported; this renderer preserves measured text lines without a line-count pagination policy.");
|
|
78
78
|
if (s === "auto" && c === "auto" && l === "auto") continue;
|
|
79
79
|
let d = s === "page" || s === "always", f = c === "page" || c === "always";
|
|
80
80
|
if (u && u.element !== t) {
|
|
81
|
-
if (d || f) throw new
|
|
81
|
+
if (d || f) throw new w("PAGINATION_FAILED", "A forced CSS page break lies inside an atomic raster region; move the break outside that region.");
|
|
82
82
|
continue;
|
|
83
83
|
}
|
|
84
|
-
if (!
|
|
85
|
-
let p =
|
|
84
|
+
if (!E.has(e.display)) throw new w("UNSUPPORTED_CSS", "Explicit CSS page breaks require a block, table group or table row; inline fragments and table cells are unsupported.");
|
|
85
|
+
let p = ee(t, n);
|
|
86
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
87
|
for (let e of ["previous", "next"]) {
|
|
88
88
|
let r = e === "previous" ? s : c;
|
|
89
89
|
if (r !== "avoid" && r !== "avoid-page") continue;
|
|
90
|
-
let a =
|
|
90
|
+
let a = ne(t, e);
|
|
91
91
|
if (!a) continue;
|
|
92
|
-
let o =
|
|
92
|
+
let o = re(p, ee(a, n));
|
|
93
93
|
i.set(`${o.x}:${o.y}:${o.width}:${o.height}`, o);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -98,8 +98,28 @@ function ae(e, t) {
|
|
|
98
98
|
avoidBreakBounds: [...i.values()]
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
+
// src/export-options.ts
|
|
102
|
+
function ae(e) {
|
|
103
|
+
if (e === void 0) return;
|
|
104
|
+
if (!e || typeof e != "object" || Array.isArray(e)) throw new w("INVALID_OPTIONS", "PDF metadata must be an object.");
|
|
105
|
+
let { title: t, author: n, subject: r, keywords: i } = e;
|
|
106
|
+
if ([
|
|
107
|
+
t,
|
|
108
|
+
n,
|
|
109
|
+
r
|
|
110
|
+
].some((e) => e !== void 0 && typeof e != "string") || i !== void 0 && (!Array.isArray(i) || Array.from(i).some((e) => typeof e != "string"))) throw new w("INVALID_OPTIONS", "PDF metadata title, author and subject must be strings; keywords must be an array of strings.");
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
...t === void 0 ? {} : { title: t },
|
|
113
|
+
...n === void 0 ? {} : { author: n },
|
|
114
|
+
...r === void 0 ? {} : { subject: r },
|
|
115
|
+
...i === void 0 ? {} : { keywords: Object.freeze([...i]) }
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function oe(e, t) {
|
|
119
|
+
e.setTitle(t?.title ?? "RenderPDF.js"), t?.author !== void 0 && e.setAuthor(t.author), t?.subject !== void 0 && e.setSubject(t.subject), t?.keywords !== void 0 && e.setKeywords([...t.keywords]);
|
|
120
|
+
}
|
|
101
121
|
// src/fonts.ts
|
|
102
|
-
var
|
|
122
|
+
var se = /* @__PURE__ */ new WeakMap(), ce = /* @__PURE__ */ new WeakMap(), le = /* @__PURE__ */ new Set([
|
|
103
123
|
"serif",
|
|
104
124
|
"sans-serif",
|
|
105
125
|
"monospace",
|
|
@@ -119,40 +139,40 @@ var E = /* @__PURE__ */ new WeakMap(), D = /* @__PURE__ */ new WeakMap(), oe = /
|
|
|
119
139
|
"revert",
|
|
120
140
|
"revert-layer"
|
|
121
141
|
]);
|
|
122
|
-
function
|
|
123
|
-
if (e.byteLength < 12) throw new
|
|
142
|
+
function ue(e) {
|
|
143
|
+
if (e.byteLength < 12) throw new w("FONT_LOAD_FAILED", "Provide a complete static TTF/OTF font program.");
|
|
124
144
|
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = t.getUint32(0);
|
|
125
|
-
if (n !== 65536 && n !== 1330926671) throw new
|
|
145
|
+
if (n !== 65536 && n !== 1330926671) throw new w("FONT_LOAD_FAILED", "Only static TTF/OTF programs are supported; WOFF fonts and font collections are unsupported.");
|
|
126
146
|
let r = t.getUint16(4);
|
|
127
|
-
if (r === 0 || 12 + r * 16 > e.byteLength) throw new
|
|
128
|
-
for (let e = 0; e < r; e += 1) if (t.getUint32(12 + e * 16) === 1719034226) throw new
|
|
147
|
+
if (r === 0 || 12 + r * 16 > e.byteLength) throw new w("FONT_LOAD_FAILED", "The TTF/OTF font table directory is incomplete.");
|
|
148
|
+
for (let e = 0; e < r; e += 1) if (t.getUint32(12 + e * 16) === 1719034226) throw new w("FONT_LOAD_FAILED", "Variable fonts are unsupported. Provide an explicitly generated static TTF/OTF instance.");
|
|
129
149
|
}
|
|
130
150
|
function k(e, t, n, r, i) {
|
|
131
151
|
for (let a of e.fonts) {
|
|
132
152
|
if (a === i || a.family.replace(/^["']|["']$/g, "").toLowerCase() !== t.toLowerCase() || a.style !== r) continue;
|
|
133
153
|
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
|
|
154
|
+
if (e[0] === n || e.length === 2 && n >= e[0] && n <= e[1]) throw new w("INVALID_OPTIONS", `Font ${t} ${n} ${r} conflicts with an existing browser font face. Choose a family owned by this registration.`);
|
|
135
155
|
}
|
|
136
156
|
}
|
|
137
157
|
function A(e) {
|
|
138
158
|
for (let t of e) {
|
|
139
|
-
let e = t && typeof t == "object" ?
|
|
140
|
-
if (!e || typeof document > "u" || e.document !== document || !document.fonts.has(e.face)) throw new
|
|
159
|
+
let e = t && typeof t == "object" ? ce.get(t) : void 0;
|
|
160
|
+
if (!e || typeof document > "u" || e.document !== document || !document.fonts.has(e.face)) throw new w("MISSING_FONT", "Provide font handles returned by registerFont() whose browser faces remain registered in the current document.");
|
|
141
161
|
k(document, t.family, t.weight, t.style, e.face);
|
|
142
162
|
}
|
|
143
163
|
}
|
|
144
|
-
async function
|
|
145
|
-
if (!e || typeof e != "object" || typeof e.family != "string") throw new
|
|
164
|
+
async function de(e) {
|
|
165
|
+
if (!e || typeof e != "object" || typeof e.family != "string") throw new w("INVALID_OPTIONS", "Font registration requires a CSS family and font bytes.");
|
|
146
166
|
let t = e.family.trim(), n = e.weight ?? 400, r = e.style ?? "normal";
|
|
147
|
-
if (!t || !/^[\w -]+$/.test(t) ||
|
|
148
|
-
if (typeof document > "u" || typeof FontFace > "u" || !document.fonts) throw new
|
|
167
|
+
if (!t || !/^[\w -]+$/.test(t) || le.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 w("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.");
|
|
168
|
+
if (typeof document > "u" || typeof FontFace > "u" || !document.fonts) throw new w("FONT_LOAD_FAILED", "Font registration requires a browser document with FontFace support.");
|
|
149
169
|
let i = new Uint8Array(e.data instanceof Uint8Array ? e.data : new Uint8Array(e.data));
|
|
150
|
-
|
|
151
|
-
let a = `${t.toLowerCase()}:${n}:${r}`, o = document, s =
|
|
152
|
-
s || (s = /* @__PURE__ */ new Map(),
|
|
170
|
+
ue(i);
|
|
171
|
+
let a = `${t.toLowerCase()}:${n}:${r}`, o = document, s = se.get(o);
|
|
172
|
+
s || (s = /* @__PURE__ */ new Map(), se.set(o, s));
|
|
153
173
|
let c = s.get(a);
|
|
154
174
|
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
|
|
175
|
+
if (c.bytes.length !== i.length || c.bytes.some((e, t) => e !== i[t])) throw new w("INVALID_OPTIONS", `Font ${t} ${n} ${r} is already registered with different bytes.`);
|
|
156
176
|
return c.promise;
|
|
157
177
|
}
|
|
158
178
|
async function l() {
|
|
@@ -170,12 +190,12 @@ async function se(e) {
|
|
|
170
190
|
return i.slice();
|
|
171
191
|
}
|
|
172
192
|
});
|
|
173
|
-
return
|
|
193
|
+
return ce.set(a, {
|
|
174
194
|
document: o,
|
|
175
195
|
face: e
|
|
176
196
|
}), a;
|
|
177
197
|
} catch (e) {
|
|
178
|
-
throw s.delete(a), e instanceof
|
|
198
|
+
throw s.delete(a), e instanceof w ? e : new w("FONT_LOAD_FAILED", `Could not load font ${t} ${n} ${r}.`, { cause: e });
|
|
179
199
|
}
|
|
180
200
|
}
|
|
181
201
|
let u = Promise.resolve().then(l), d = {
|
|
@@ -185,8 +205,8 @@ async function se(e) {
|
|
|
185
205
|
return s.set(a, d), u;
|
|
186
206
|
}
|
|
187
207
|
// src/planner.ts
|
|
188
|
-
var
|
|
189
|
-
function
|
|
208
|
+
var fe = /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z\d+/=\s]+$/i;
|
|
209
|
+
function pe(e) {
|
|
190
210
|
let t = 0, n = "", r = 0, i = [];
|
|
191
211
|
for (let a = 0; a < e.length; a += 1) {
|
|
192
212
|
let o = e[a];
|
|
@@ -194,23 +214,23 @@ function M(e) {
|
|
|
194
214
|
}
|
|
195
215
|
return i.push(e.slice(r).trim()), i;
|
|
196
216
|
}
|
|
197
|
-
function
|
|
217
|
+
function me(e) {
|
|
198
218
|
let t = [];
|
|
199
219
|
if (e.backgroundImage !== "none") {
|
|
200
|
-
for (let t of
|
|
220
|
+
for (let t of pe(e.backgroundImage)) {
|
|
201
221
|
if (/^(?:repeating-)?(?:linear|radial|conic)-gradient\(/i.test(t)) continue;
|
|
202
222
|
let e = t.match(/^url\(\s*(["']?)(.*?)\1\s*\)$/i)?.[2];
|
|
203
|
-
if (!e || !
|
|
223
|
+
if (!e || !fe.test(e)) throw new w("UNSUPPORTED_CSS", "Unsupported CSS: automatic raster backgrounds require gradients or inline bitmap URLs.");
|
|
204
224
|
}
|
|
205
225
|
t.push("background-image");
|
|
206
226
|
}
|
|
207
227
|
if (e.borderRadius !== "0px" && t.push("border-radius"), e.boxShadow !== "none") {
|
|
208
|
-
if (
|
|
228
|
+
if (pe(e.boxShadow).some((e) => !/\binset\b/.test(e))) throw new w("UNSUPPORTED_CSS", "Unsupported CSS: outer shadows require expanded capture bounds; only inset shadows can fall back automatically.");
|
|
209
229
|
t.push("inset box-shadow");
|
|
210
230
|
}
|
|
211
231
|
return e.opacity !== "1" && t.push("opacity"), t.length ? t.join(", ") : void 0;
|
|
212
232
|
}
|
|
213
|
-
function
|
|
233
|
+
function he(e, t) {
|
|
214
234
|
if (!(e instanceof HTMLImageElement) && ![
|
|
215
235
|
"block",
|
|
216
236
|
"flow-root",
|
|
@@ -219,18 +239,278 @@ function ce(e, t) {
|
|
|
219
239
|
"inline-flex",
|
|
220
240
|
"grid",
|
|
221
241
|
"inline-grid"
|
|
222
|
-
].includes(t.display)) throw new
|
|
223
|
-
if (Array.from(e.getClientRects()).filter((e) => e.width > 0 && e.height > 0).length !== 1) throw new
|
|
242
|
+
].includes(t.display)) throw new w("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.");
|
|
243
|
+
if (Array.from(e.getClientRects()).filter((e) => e.width > 0 && e.height > 0).length !== 1) throw new w("UNSUPPORTED_CSS", "Automatic raster fallback cannot capture fragmented inline or multi-column regions.");
|
|
244
|
+
}
|
|
245
|
+
// src/table-borders.ts
|
|
246
|
+
var j = .001;
|
|
247
|
+
function M(e, t) {
|
|
248
|
+
let n = (e) => e.style === "hidden" ? 2 : +(e.style === "solid" && e.width > 0);
|
|
249
|
+
return n(e) - n(t) || e.width - t.width || Number(e.owner === "cell") - Number(t.owner === "cell") || (e.direction === t.direction ? e.direction === "vertical" ? t.column - e.column || t.row - e.row : t.row - e.row || t.column - e.column : Number(e.direction === "horizontal") - Number(t.direction === "horizontal"));
|
|
250
|
+
}
|
|
251
|
+
function ge(e) {
|
|
252
|
+
let t = /* @__PURE__ */ new Map();
|
|
253
|
+
for (let n of e) {
|
|
254
|
+
if (![
|
|
255
|
+
n.position,
|
|
256
|
+
n.start,
|
|
257
|
+
n.end,
|
|
258
|
+
n.width
|
|
259
|
+
].every(Number.isFinite) || n.width < 0 || n.end <= n.start) throw new w("INVALID_SOURCE", "Collapsed border geometry must be finite and positive.");
|
|
260
|
+
let e = `${n.direction}:${n.position.toFixed(4)}`, r = t.get(e) ?? [];
|
|
261
|
+
r.push(n), t.set(e, r);
|
|
262
|
+
}
|
|
263
|
+
let n = [];
|
|
264
|
+
for (let e of t.values()) {
|
|
265
|
+
let t = /* @__PURE__ */ new Map();
|
|
266
|
+
for (let n of e) {
|
|
267
|
+
let e = t.get(n.start) ?? {
|
|
268
|
+
starts: [],
|
|
269
|
+
ends: []
|
|
270
|
+
};
|
|
271
|
+
e.starts.push(n), t.set(n.start, e);
|
|
272
|
+
let r = t.get(n.end) ?? {
|
|
273
|
+
starts: [],
|
|
274
|
+
ends: []
|
|
275
|
+
};
|
|
276
|
+
r.ends.push(n), t.set(n.end, r);
|
|
277
|
+
}
|
|
278
|
+
let r = [...t.keys()].sort((e, t) => e - t), i = /* @__PURE__ */ new Set();
|
|
279
|
+
for (let e = 0; e < r.length - 1; e += 1) {
|
|
280
|
+
let a = r[e], o = r[e + 1], s = t.get(a);
|
|
281
|
+
for (let e of s.ends) i.delete(e);
|
|
282
|
+
for (let e of s.starts) i.add(e);
|
|
283
|
+
if (o - a <= j) continue;
|
|
284
|
+
let c;
|
|
285
|
+
for (let e of i) (!c || M(e, c) > 0) && (c = e);
|
|
286
|
+
c?.style === "solid" && c.width > 0 && n.push({
|
|
287
|
+
...c,
|
|
288
|
+
start: a,
|
|
289
|
+
end: o
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return n;
|
|
294
|
+
}
|
|
295
|
+
function _e(e, t) {
|
|
296
|
+
let n = Math.max(e.x, t.x), r = Math.min(e.x + e.width, t.x + t.width), i = Math.max(e.y, t.y), a = Math.min(e.y + e.height, t.y + t.height);
|
|
297
|
+
return r <= n + j || a <= i + j ? [e] : [
|
|
298
|
+
{
|
|
299
|
+
x: e.x,
|
|
300
|
+
y: e.y,
|
|
301
|
+
width: e.width,
|
|
302
|
+
height: i - e.y
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
x: e.x,
|
|
306
|
+
y: a,
|
|
307
|
+
width: e.width,
|
|
308
|
+
height: e.y + e.height - a
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
x: e.x,
|
|
312
|
+
y: i,
|
|
313
|
+
width: n - e.x,
|
|
314
|
+
height: a - i
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
x: r,
|
|
318
|
+
y: i,
|
|
319
|
+
width: e.x + e.width - r,
|
|
320
|
+
height: a - i
|
|
321
|
+
}
|
|
322
|
+
].filter((e) => e.width > j && e.height > j);
|
|
323
|
+
}
|
|
324
|
+
function ve(e) {
|
|
325
|
+
let t = [], n = /* @__PURE__ */ new Map();
|
|
326
|
+
for (let t of e) {
|
|
327
|
+
let e = `${t.direction}:${t.position.toFixed(4)}`, r = n.get(e) ?? [];
|
|
328
|
+
r.push(t), n.set(e, r);
|
|
329
|
+
}
|
|
330
|
+
for (let e of n.values()) e.sort((e, t) => e.start - t.start);
|
|
331
|
+
let r = /* @__PURE__ */ new Map(), i = (e) => {
|
|
332
|
+
let t = [];
|
|
333
|
+
for (let n = Math.floor(e.x / 64); n <= Math.floor((e.x + e.width) / 64); n += 1) for (let r = Math.floor(e.y / 64); r <= Math.floor((e.y + e.height) / 64); r += 1) t.push(`${n}:${r}`);
|
|
334
|
+
return t;
|
|
335
|
+
}, a = [...e].sort((e, t) => M(t, e));
|
|
336
|
+
for (let e of a) {
|
|
337
|
+
let a = (t) => {
|
|
338
|
+
let r = e.direction === "horizontal" ? "vertical" : "horizontal", i = n.get(`${r}:${t.toFixed(4)}`) ?? [], a = 0, o = i.length;
|
|
339
|
+
for (; a < o;) {
|
|
340
|
+
let t = a + o >>> 1;
|
|
341
|
+
i[t].start <= e.position + j ? a = t + 1 : o = t;
|
|
342
|
+
}
|
|
343
|
+
let s = 0;
|
|
344
|
+
for (let t = a - 1; t >= 0; --t) {
|
|
345
|
+
let n = i[t];
|
|
346
|
+
if (n.end < e.position - j) break;
|
|
347
|
+
s = Math.max(s, n.width / 2);
|
|
348
|
+
}
|
|
349
|
+
return s;
|
|
350
|
+
}, o = e.start - a(e.start), s = e.end + a(e.end), c = [e.direction === "horizontal" ? {
|
|
351
|
+
x: o,
|
|
352
|
+
y: e.position - e.width / 2,
|
|
353
|
+
width: s - o,
|
|
354
|
+
height: e.width
|
|
355
|
+
} : {
|
|
356
|
+
x: e.position - e.width / 2,
|
|
357
|
+
y: o,
|
|
358
|
+
width: e.width,
|
|
359
|
+
height: s - o
|
|
360
|
+
}], l = new Set(i(c[0]).flatMap((e) => r.get(e) ?? []));
|
|
361
|
+
for (let e of l) if (c = c.flatMap((t) => _e(t, e.bounds)), c.length === 0) break;
|
|
362
|
+
for (let n of c) {
|
|
363
|
+
let a = {
|
|
364
|
+
kind: "border",
|
|
365
|
+
bounds: n,
|
|
366
|
+
color: e.color,
|
|
367
|
+
width: e.width,
|
|
368
|
+
direction: e.direction
|
|
369
|
+
};
|
|
370
|
+
t.push(a);
|
|
371
|
+
for (let e of i(n)) {
|
|
372
|
+
let t = r.get(e) ?? [];
|
|
373
|
+
t.push(a), r.set(e, t);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return t;
|
|
378
|
+
}
|
|
379
|
+
function ye(e, t) {
|
|
380
|
+
if (![
|
|
381
|
+
"TABLE",
|
|
382
|
+
"THEAD",
|
|
383
|
+
"TBODY",
|
|
384
|
+
"TFOOT",
|
|
385
|
+
"TR",
|
|
386
|
+
"TD",
|
|
387
|
+
"TH",
|
|
388
|
+
"COL",
|
|
389
|
+
"COLGROUP"
|
|
390
|
+
].includes(e.tagName)) return;
|
|
391
|
+
let n = e instanceof HTMLTableElement ? e : e.closest("table");
|
|
392
|
+
return n && (e === n ? t : getComputedStyle(n)).borderCollapse === "collapse" ? n : void 0;
|
|
393
|
+
}
|
|
394
|
+
function be(e, t) {
|
|
395
|
+
if (!{
|
|
396
|
+
TABLE: ["table", "inline-table"],
|
|
397
|
+
THEAD: ["table-header-group"],
|
|
398
|
+
TBODY: ["table-row-group"],
|
|
399
|
+
TFOOT: ["table-footer-group"],
|
|
400
|
+
TR: ["table-row"],
|
|
401
|
+
TD: ["table-cell"],
|
|
402
|
+
TH: ["table-cell"],
|
|
403
|
+
COL: ["table-column"],
|
|
404
|
+
COLGROUP: ["table-column-group"]
|
|
405
|
+
}[e.tagName]?.includes(t.display)) throw new w("UNSUPPORTED_CSS", "Collapsed table parts require their native table-cell, table-row and table-group display modes.");
|
|
406
|
+
for (let n of [
|
|
407
|
+
"Top",
|
|
408
|
+
"Right",
|
|
409
|
+
"Bottom",
|
|
410
|
+
"Left"
|
|
411
|
+
]) {
|
|
412
|
+
let r = t[`border${n}Style`], i = Number.parseFloat(t[`border${n}Width`]);
|
|
413
|
+
if (![
|
|
414
|
+
"solid",
|
|
415
|
+
"none",
|
|
416
|
+
"hidden"
|
|
417
|
+
].includes(r)) throw new w("UNSUPPORTED_CSS", "Collapsed tables support only solid, none and hidden border styles.");
|
|
418
|
+
if (![
|
|
419
|
+
"TABLE",
|
|
420
|
+
"TD",
|
|
421
|
+
"TH"
|
|
422
|
+
].includes(e.tagName) && (r === "hidden" || i > 0)) throw new w("UNSUPPORTED_CSS", "Collapsed row, row-group, column and column-group border contributions are unsupported; put borders on cells or the table.");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function xe(e, t) {
|
|
426
|
+
if (e.parentElement?.closest("table") || e.querySelector("table") || e.caption || !["table", "inline-table"].includes(getComputedStyle(e).display)) throw new w("UNSUPPORTED_ELEMENT", "Native collapsed borders require a table without nested tables or captions.");
|
|
427
|
+
let n = [], r = Array.from(e.rows).flatMap((e) => Array.from(e.cells).filter((e) => {
|
|
428
|
+
let t = e.getBoundingClientRect();
|
|
429
|
+
return t.width > 0 && t.height > 0;
|
|
430
|
+
}));
|
|
431
|
+
if (r.length === 0) return {
|
|
432
|
+
operations: [],
|
|
433
|
+
repeatSafe: !0
|
|
434
|
+
};
|
|
435
|
+
let i = r.map((e) => e.getBoundingClientRect()), a = i.reduce((e, t) => ({
|
|
436
|
+
left: Math.min(e.left, t.left),
|
|
437
|
+
right: Math.max(e.right, t.right),
|
|
438
|
+
top: Math.min(e.top, t.top),
|
|
439
|
+
bottom: Math.max(e.bottom, t.bottom)
|
|
440
|
+
}), {
|
|
441
|
+
left: Infinity,
|
|
442
|
+
right: -Infinity,
|
|
443
|
+
top: Infinity,
|
|
444
|
+
bottom: -Infinity
|
|
445
|
+
}), o = (r, i) => {
|
|
446
|
+
let a = getComputedStyle(r), o = r === e ? "table" : "cell";
|
|
447
|
+
for (let e of [
|
|
448
|
+
"Top",
|
|
449
|
+
"Right",
|
|
450
|
+
"Bottom",
|
|
451
|
+
"Left"
|
|
452
|
+
]) {
|
|
453
|
+
let r = e === "Top" || e === "Bottom";
|
|
454
|
+
n.push({
|
|
455
|
+
direction: r ? "horizontal" : "vertical",
|
|
456
|
+
position: (e === "Top" ? i.top : e === "Bottom" ? i.bottom : e === "Left" ? i.left : i.right) - (r ? t.top : t.left),
|
|
457
|
+
start: (r ? i.left : i.top) - (r ? t.left : t.top),
|
|
458
|
+
end: (r ? i.right : i.bottom) - (r ? t.left : t.top),
|
|
459
|
+
width: Number.parseFloat(a[`border${e}Width`]),
|
|
460
|
+
style: a[`border${e}Style`],
|
|
461
|
+
color: a[`border${e}Color`],
|
|
462
|
+
owner: o,
|
|
463
|
+
row: i.top,
|
|
464
|
+
column: i.left
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
o(e, a), r.forEach((e, t) => o(e, i[t]));
|
|
469
|
+
let s = ge(n), c = ve(s), l = e.tHead?.getBoundingClientRect();
|
|
470
|
+
if (!l || l.height <= 0) return {
|
|
471
|
+
operations: c,
|
|
472
|
+
repeatSafe: !0
|
|
473
|
+
};
|
|
474
|
+
let u = l.bottom - t.top, d = Array.from(e.tBodies).flatMap((e) => Array.from(e.rows)), f = d.at(-1)?.getBoundingClientRect().bottom ?? l.bottom, p = [.../* @__PURE__ */ new Set([u, ...d.map((e) => e.getBoundingClientRect().top - t.top).filter((e) => e < f - t.top - j)])], m = /* @__PURE__ */ new Map();
|
|
475
|
+
for (let e of s) {
|
|
476
|
+
if (e.direction !== "horizontal") continue;
|
|
477
|
+
let t = e.position.toFixed(4), n = m.get(t) ?? [];
|
|
478
|
+
n.push(e), m.set(t, n);
|
|
479
|
+
}
|
|
480
|
+
let h = (e) => JSON.stringify((m.get(e.toFixed(4)) ?? []).sort((e, t) => e.start - t.start).map(({ start: e, end: t, width: n, color: r }) => ({
|
|
481
|
+
start: e,
|
|
482
|
+
end: t,
|
|
483
|
+
width: n,
|
|
484
|
+
color: r
|
|
485
|
+
}))), g = h(u), _ = p.every((e) => h(e) === g), v = c.filter((e) => e.bounds.y < u + j && e.bounds.y + e.bounds.height > l.top - t.top - j).reduce((e, { bounds: t }) => ({
|
|
486
|
+
left: Math.min(e.left, t.x),
|
|
487
|
+
right: Math.max(e.right, t.x + t.width),
|
|
488
|
+
top: Math.min(e.top, t.y)
|
|
489
|
+
}), {
|
|
490
|
+
left: l.left - t.left,
|
|
491
|
+
right: l.right - t.left,
|
|
492
|
+
top: l.top - t.top
|
|
493
|
+
});
|
|
494
|
+
return {
|
|
495
|
+
operations: c,
|
|
496
|
+
repeatSafe: _,
|
|
497
|
+
headerBounds: {
|
|
498
|
+
x: v.left,
|
|
499
|
+
y: v.top,
|
|
500
|
+
width: v.right - v.left,
|
|
501
|
+
height: u - v.top
|
|
502
|
+
}
|
|
503
|
+
};
|
|
224
504
|
}
|
|
225
505
|
// src/layout.ts
|
|
226
|
-
var
|
|
227
|
-
function
|
|
506
|
+
var Se = new Intl.Segmenter("en", { granularity: "grapheme" });
|
|
507
|
+
function N(e, t) {
|
|
228
508
|
if (![
|
|
229
509
|
e.x,
|
|
230
510
|
e.y,
|
|
231
511
|
e.width,
|
|
232
512
|
e.height
|
|
233
|
-
].every(Number.isFinite)) throw new
|
|
513
|
+
].every(Number.isFinite)) throw new w("INVALID_SOURCE", "Browser geometry must contain only finite CSS pixel values.");
|
|
234
514
|
return {
|
|
235
515
|
x: e.left - t.left,
|
|
236
516
|
y: e.top - t.top,
|
|
@@ -238,12 +518,12 @@ function P(e, t) {
|
|
|
238
518
|
height: e.height
|
|
239
519
|
};
|
|
240
520
|
}
|
|
241
|
-
function
|
|
521
|
+
function P(e) {
|
|
242
522
|
let t = e.getRootNode();
|
|
243
523
|
return e.parentElement ?? (t instanceof ShadowRoot && t.host instanceof HTMLElement ? t.host : null);
|
|
244
524
|
}
|
|
245
|
-
function
|
|
246
|
-
let
|
|
525
|
+
function F(e, t, n = !1, r = !1) {
|
|
526
|
+
let i = e instanceof HTMLImageElement, a = [
|
|
247
527
|
t.position !== "static" && `position: ${t.position}`,
|
|
248
528
|
t.zIndex !== "auto" && `z-index: ${t.zIndex}`,
|
|
249
529
|
t.transform !== "none" && "transform",
|
|
@@ -256,8 +536,8 @@ function I(e, t, n = !1) {
|
|
|
256
536
|
t.backgroundImage !== "none" && !n && "background-image",
|
|
257
537
|
t.boxShadow !== "none" && !n && "box-shadow",
|
|
258
538
|
t.borderRadius !== "0px" && !n && "border-radius",
|
|
259
|
-
t.overflowX !== "visible" && !(
|
|
260
|
-
t.overflowY !== "visible" && !(
|
|
539
|
+
t.overflowX !== "visible" && !(i && t.overflowX === "clip") && "overflow-x",
|
|
540
|
+
t.overflowY !== "visible" && !(i && t.overflowY === "clip") && "overflow-y",
|
|
261
541
|
t.cssFloat !== "none" && "float",
|
|
262
542
|
t.order !== "0" && "order",
|
|
263
543
|
t.direction !== "ltr" && "direction",
|
|
@@ -282,10 +562,10 @@ function I(e, t, n = !1) {
|
|
|
282
562
|
].filter(Boolean);
|
|
283
563
|
for (let t of ["::before", "::after"]) {
|
|
284
564
|
let n = getComputedStyle(e, t).content;
|
|
285
|
-
n !== "none" && n !== "normal" &&
|
|
565
|
+
n !== "none" && n !== "normal" && a.push(`generated content ${t}`);
|
|
286
566
|
}
|
|
287
|
-
if (
|
|
288
|
-
if (e instanceof HTMLTableElement && t.borderCollapse
|
|
567
|
+
if (a.length > 0) throw new w("UNSUPPORTED_CSS", `Unsupported CSS on ${e.tagName}: ${a.join(", ")}. Use a bounded data-raster subtree when safe.`);
|
|
568
|
+
if (e instanceof HTMLTableElement && !["separate", "collapse"].includes(t.borderCollapse)) throw new w("UNSUPPORTED_CSS", "Native table snapshots require separate or collapsed borders.");
|
|
289
569
|
if ([
|
|
290
570
|
"THEAD",
|
|
291
571
|
"TBODY",
|
|
@@ -293,17 +573,17 @@ function I(e, t, n = !1) {
|
|
|
293
573
|
"TR",
|
|
294
574
|
"COL",
|
|
295
575
|
"COLGROUP"
|
|
296
|
-
].includes(e.tagName) && t.backgroundColor !== "rgba(0, 0, 0, 0)") throw new
|
|
297
|
-
let
|
|
576
|
+
].includes(e.tagName) && t.backgroundColor !== "rgba(0, 0, 0, 0)") throw new w("UNSUPPORTED_CSS", "Native table snapshots require transparent row-group, row, and column backgrounds.");
|
|
577
|
+
let o = [
|
|
298
578
|
"Top",
|
|
299
579
|
"Right",
|
|
300
580
|
"Bottom",
|
|
301
581
|
"Left"
|
|
302
|
-
],
|
|
303
|
-
if (
|
|
304
|
-
if (!n && (t.backgroundColor !== "rgba(0, 0, 0, 0)" ||
|
|
582
|
+
], s = o.map((e) => t[`border${e}Width`]), c = o.map((e) => t[`border${e}Color`]), l = o.map((e) => t[`border${e}Style`]);
|
|
583
|
+
if (r && be(e, t), !r && (s.some((e) => e !== s[0]) || s[0] !== "0px" && (c.some((e) => e !== c[0]) || l.some((e) => e !== "solid")))) throw new w("UNSUPPORTED_CSS", "Unsupported CSS: only uniform solid borders are supported.");
|
|
584
|
+
if (!n && (t.backgroundColor !== "rgba(0, 0, 0, 0)" || s[0] !== "0px") && Array.from(e.getClientRects()).filter((e) => e.width > 0 && e.height > 0).length > 1) throw new w("UNSUPPORTED_CSS", "Fragmented inline backgrounds and borders require an explicit containing raster region.");
|
|
305
585
|
}
|
|
306
|
-
function
|
|
586
|
+
function I(e, t) {
|
|
307
587
|
if (!(e instanceof HTMLImageElement) && ![
|
|
308
588
|
"block",
|
|
309
589
|
"flow-root",
|
|
@@ -323,34 +603,34 @@ function L(e, t) {
|
|
|
323
603
|
"table-cell",
|
|
324
604
|
"table-column-group",
|
|
325
605
|
"table-column"
|
|
326
|
-
].includes(t.display)) throw new
|
|
606
|
+
].includes(t.display)) throw new w("UNSUPPORTED_CSS", `Unsupported CSS display: ${t.display}.`);
|
|
327
607
|
}
|
|
328
|
-
function
|
|
608
|
+
function Ce(e, t, n, r, i) {
|
|
329
609
|
let a = e.parentElement;
|
|
330
610
|
if (!a || !e.data.replace(/[\t\n\r\f ]+/g, "")) return [];
|
|
331
611
|
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
|
|
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
|
|
612
|
+
if (!l) throw new w("MISSING_FONT", `No exact registered font face for ${o.fontFamily} ${o.fontWeight} ${o.fontStyle}.`);
|
|
613
|
+
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 w("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
614
|
let u = Number.parseFloat(o.fontSize), d = `${l.style} ${l.weight} ${u}px "${l.family}"`, f = r.fonts.get(d);
|
|
335
615
|
if (!f) {
|
|
336
616
|
if (!Array.from(document.fonts).some((e) => {
|
|
337
617
|
let t = e.weight === "normal" ? 400 : e.weight === "bold" ? 700 : Number(e.weight);
|
|
338
618
|
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
|
|
619
|
+
}) || !document.fonts.check(d, e.data)) throw new w("MISSING_FONT", `Browser font is not loaded: ${d}.`);
|
|
340
620
|
r.context.font = d;
|
|
341
621
|
let t = r.context.measureText(e.data), n = t.fontBoundingBoxAscent, i = t.fontBoundingBoxDescent;
|
|
342
|
-
if (!Number.isFinite(n) || !Number.isFinite(i)) throw new
|
|
622
|
+
if (!Number.isFinite(n) || !Number.isFinite(i)) throw new w("UNSUPPORTED_CSS", "Font bounding metrics are unavailable in this browser.");
|
|
343
623
|
f = {
|
|
344
624
|
ascent: n,
|
|
345
625
|
descent: i
|
|
346
626
|
}, r.fonts.set(d, f);
|
|
347
627
|
}
|
|
348
|
-
let { ascent: p, descent: m } = f, h =
|
|
628
|
+
let { ascent: p, descent: m } = f, h = Se.segment(e.data), g = document.createRange(), _ = [];
|
|
349
629
|
for (let t of h) {
|
|
350
630
|
g.setStart(e, t.index), g.setEnd(e, t.index + t.segment.length);
|
|
351
631
|
let n = Array.from(g.getClientRects()), r = n.find((e) => e.width > 0 && e.height > 0);
|
|
352
632
|
if (!r) {
|
|
353
|
-
if (/[^\t\n\r\f ]/.test(t.segment) && n.some((e) => e.height > 0 && e.width === 0)) throw new
|
|
633
|
+
if (/[^\t\n\r\f ]/.test(t.segment) && n.some((e) => e.height > 0 && e.width === 0)) throw new w("UNSUPPORTED_CSS", "Text shaping crosses an inline boundary or uses an unsupported zero-width glyph. Keep each shaped word in one text node.");
|
|
354
634
|
continue;
|
|
355
635
|
}
|
|
356
636
|
let i = _.at(-1);
|
|
@@ -366,14 +646,14 @@ function R(e, t, n, r, i) {
|
|
|
366
646
|
for (; a > r && /[\t\n\r\f ]/.test(e.data[a - 1]);) --a;
|
|
367
647
|
if (r === a) return [];
|
|
368
648
|
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 =
|
|
649
|
+
let s = e.data.slice(r, a), c = s.replace(/[\t\n\r\f ]+/g, " "), d = N(g.getBoundingClientRect(), t);
|
|
370
650
|
return [{
|
|
371
651
|
kind: "text",
|
|
372
652
|
bounds: d,
|
|
373
653
|
text: c,
|
|
374
654
|
runs: Array.from(s.matchAll(/[^\t\n\r\f ]+/g), (n) => {
|
|
375
655
|
g.setStart(e, r + n.index), g.setEnd(e, r + n.index + n[0].length);
|
|
376
|
-
let i =
|
|
656
|
+
let i = N(g.getBoundingClientRect(), t);
|
|
377
657
|
return {
|
|
378
658
|
text: n[0],
|
|
379
659
|
x: i.x,
|
|
@@ -391,147 +671,210 @@ function R(e, t, n, r, i) {
|
|
|
391
671
|
}];
|
|
392
672
|
});
|
|
393
673
|
}
|
|
394
|
-
function
|
|
395
|
-
if (n !== "auto" && n !== "strict") throw new
|
|
396
|
-
if (
|
|
397
|
-
if (
|
|
398
|
-
|
|
674
|
+
function we(e, t, n, r = !1) {
|
|
675
|
+
if (n !== "auto" && n !== "strict") throw new w("INVALID_OPTIONS", "Raster fallback must be auto or strict.");
|
|
676
|
+
if (typeof r != "boolean") throw new w("INVALID_OPTIONS", "Table header repetition must be a boolean.");
|
|
677
|
+
if (!(e instanceof HTMLElement) || e.ownerDocument !== document || !e.isConnected || t.length === 0) throw new w("INVALID_SOURCE", "A connected source root and registered fonts are required.");
|
|
678
|
+
if (new Set(t.map((e) => `${e.family.toLowerCase()}:${e.weight}:${e.style}`)).size !== t.length) throw new w("INVALID_OPTIONS", "Registered fonts require unique family/weight/style descriptors.");
|
|
679
|
+
for (let t = P(e); t; t = P(t)) {
|
|
399
680
|
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
|
|
681
|
+
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 w("UNSUPPORTED_CSS", "Unsupported CSS: source ancestors must not transform, clip, blend, or fade the source.");
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function Te(e, t, n, r, i, a) {
|
|
685
|
+
let o = Array.from(e.querySelectorAll("table"));
|
|
686
|
+
e instanceof HTMLTableElement && o.unshift(e);
|
|
687
|
+
let s = [];
|
|
688
|
+
for (let c of o) {
|
|
689
|
+
let o = c.tHead;
|
|
690
|
+
if (!o || getComputedStyle(o).display === "none") continue;
|
|
691
|
+
let l = a.get(c), u = l?.headerBounds ?? N(o.getBoundingClientRect(), t);
|
|
692
|
+
if (u.width <= 0 || u.height <= 0) continue;
|
|
693
|
+
let d = Array.from(c.tBodies).flatMap((e) => Array.from(e.rows).filter((e) => e.getBoundingClientRect().height > 0));
|
|
694
|
+
if (d.length === 0) continue;
|
|
695
|
+
if (l && !l.repeatSafe) throw new w("UNSUPPORTED_CSS", "Repeated collapsed headers require matching horizontal border winners at the header/body boundary and all body row boundaries.");
|
|
696
|
+
if (c.parentElement?.closest("table") || c.querySelector("table") || Array.from(c.children).filter((e) => e.tagName === "THEAD").length !== 1 || getComputedStyle(c).display !== "table" || getComputedStyle(o).display !== "table-header-group") throw new w("UNSUPPORTED_ELEMENT", "Repeated headers require a standalone native table with one THEAD and no nested tables.");
|
|
697
|
+
if (Array.from(o.rows).some((e) => Array.from(e.cells).some((e) => e.rowSpan !== 1)) || n.some((e) => e.kind === "raster" && (e.element.contains(o) || o.contains(e.element)))) throw new w("UNSUPPORTED_ELEMENT", "Repeated table headers do not support header rowspans or rasterized headers and ancestors.");
|
|
698
|
+
let f = N(d[0].getBoundingClientRect(), t).y, p = N(d.at(-1).getBoundingClientRect(), t), m = p.y + p.height, h = r.get(o);
|
|
699
|
+
if (!h || f < u.y + u.height - .1 || m <= f || h.some((e) => e.kind !== "border" && (e.bounds.y < u.y - .1 || e.bounds.y + e.bounds.height > u.y + u.height + .1 || e.bounds.x < u.x - .1 || e.bounds.x + e.bounds.width > u.x + u.width + .1)) || d.some((e) => Array.from(e.cells).some((e) => {
|
|
700
|
+
let n = N(e.getBoundingClientRect(), t);
|
|
701
|
+
return n.y < f - .1 || n.y + n.height > m + .1;
|
|
702
|
+
}))) throw new w("UNSUPPORTED_CSS", "Repeated table headers require a separate, ordered header band without overflowing paint or cells spanning header/body boundaries.");
|
|
703
|
+
if (s.some((e) => Math.min(e.bodyEnd, m) - Math.max(e.bounds.y, u.y) > .01)) throw new w("UNSUPPORTED_CSS", "Repeated headers do not support tables whose vertical continuation intervals overlap.");
|
|
704
|
+
let g = new Set(h);
|
|
705
|
+
for (let t = o.parentElement; t; t = t.parentElement) {
|
|
706
|
+
let n = i.get(t);
|
|
707
|
+
if (n && g.add(n), t === e) break;
|
|
708
|
+
}
|
|
709
|
+
s.push({
|
|
710
|
+
bounds: u,
|
|
711
|
+
bodyStart: f,
|
|
712
|
+
bodyEnd: m,
|
|
713
|
+
operations: n.filter((e) => g.has(e))
|
|
714
|
+
});
|
|
401
715
|
}
|
|
716
|
+
return s;
|
|
402
717
|
}
|
|
403
|
-
function
|
|
404
|
-
let r = n.fallback ?? "auto";
|
|
405
|
-
|
|
406
|
-
let
|
|
407
|
-
if (
|
|
408
|
-
let
|
|
409
|
-
if (!
|
|
410
|
-
let
|
|
411
|
-
context:
|
|
718
|
+
function Ee(e, t, n = {}) {
|
|
719
|
+
let r = n.fallback ?? "auto", i = n.repeatTableHeaders ?? !1;
|
|
720
|
+
we(e, t, r, i);
|
|
721
|
+
let a = e.getBoundingClientRect();
|
|
722
|
+
if (a.width <= 0 || a.height <= 0) throw new w("INVALID_SOURCE", "The source root must have positive visible dimensions.");
|
|
723
|
+
let o = document.createElement("canvas").getContext("2d");
|
|
724
|
+
if (!o) throw new w("INVALID_SOURCE", "Canvas font measurement is unavailable.");
|
|
725
|
+
let s = {
|
|
726
|
+
context: o,
|
|
412
727
|
fonts: /* @__PURE__ */ new Map()
|
|
413
|
-
},
|
|
728
|
+
}, c = [], l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = [], p = /* @__PURE__ */ new Map(), m = [{
|
|
414
729
|
code: "TEXT_METRICS_APPROXIMATED",
|
|
415
730
|
message: "Baselines are estimated from Canvas font metrics; browser and PDF shaping engines may still differ for unsupported scripts or font features."
|
|
416
731
|
}];
|
|
417
|
-
function
|
|
418
|
-
let
|
|
419
|
-
if (
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
732
|
+
function h(e, n, o = !1) {
|
|
733
|
+
let g = c.length, _ = getComputedStyle(e);
|
|
734
|
+
if (_.display === "none") return;
|
|
735
|
+
let v = ye(e, _);
|
|
736
|
+
if (_.visibility !== "visible") {
|
|
737
|
+
if (!n || o) throw new w("UNSUPPORTED_CSS", "Unsupported CSS: visibility overrides are not supported.");
|
|
738
|
+
m.push({
|
|
423
739
|
code: "RASTER_TEXT_OMITTED",
|
|
424
740
|
message: `Raster text extraction omitted for visibility-controlled subtree ${e.tagName}.`
|
|
425
741
|
});
|
|
426
742
|
return;
|
|
427
743
|
}
|
|
428
|
-
if ((!n ||
|
|
429
|
-
let
|
|
430
|
-
if (
|
|
431
|
-
|
|
744
|
+
if ((!n || o) && !(/* @__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 w("UNSUPPORTED_ELEMENT", `Native snapshots do not support ${e.tagName}.`);
|
|
745
|
+
let y = !n && e.hasAttribute("data-raster"), b = !n && !y && r === "auto" ? me(_) : void 0, x = o || b !== void 0;
|
|
746
|
+
if (x && (o && me(_), F(e, _, !0, v !== void 0), I(e, _)), n && (_.transform !== "none" || _.writingMode !== "horizontal-tb" || _.direction !== "ltr" || _.opacity === "0" || _.clipPath !== "none" || _.maskImage !== "none" || _.overflowX !== "visible" || _.overflowY !== "visible")) {
|
|
747
|
+
m.push({
|
|
432
748
|
code: "RASTER_TEXT_OMITTED",
|
|
433
749
|
message: `Raster text extraction omitted for transformed, clipped, hidden, masked, or non-LTR subtree ${e.tagName}.`
|
|
434
750
|
});
|
|
435
751
|
return;
|
|
436
752
|
}
|
|
437
|
-
let
|
|
438
|
-
if (!n && (
|
|
439
|
-
let
|
|
440
|
-
if (
|
|
441
|
-
|
|
442
|
-
if (
|
|
753
|
+
let S = N(e.getBoundingClientRect(), a);
|
|
754
|
+
if (!n && (S.x < -.1 || S.y < -.1 || S.x + S.width > a.width + .1 || S.y + S.height > a.height + .1)) throw new w("SOURCE_OVERFLOW", "Source content must fit within the root border box.");
|
|
755
|
+
let C = y || b !== void 0;
|
|
756
|
+
if (C && v && !(e instanceof HTMLTableElement)) throw new w("UNSUPPORTED_CSS", "Collapsed table cells and internal groups cannot be independently rasterized.");
|
|
757
|
+
if (C) {
|
|
758
|
+
if (_.position !== "static" || _.transform !== "none" || _.mixBlendMode !== "normal") throw new w("UNSUPPORTED_CSS", "A raster boundary must be static, untransformed, and independently compositable.");
|
|
759
|
+
if (b !== void 0 && he(e, _), c.push({
|
|
443
760
|
kind: "raster",
|
|
444
|
-
bounds:
|
|
761
|
+
bounds: S,
|
|
445
762
|
element: e
|
|
446
|
-
}),
|
|
763
|
+
}), m.push({
|
|
447
764
|
code: "RASTER_FALLBACK",
|
|
448
|
-
message: `${
|
|
449
|
-
}),
|
|
450
|
-
|
|
765
|
+
message: `${b === void 0 ? "An explicit raster subtree" : `Automatic raster fallback on ${e.tagName} for ${b}`} uses invisible PDF text for extraction where supported; generated content and clipped or transformed text are not represented.`
|
|
766
|
+
}), _.overflowX !== "visible" || _.overflowY !== "visible" || _.clipPath !== "none" || _.maskImage !== "none" || _.opacity === "0") {
|
|
767
|
+
m.push({
|
|
451
768
|
code: "RASTER_TEXT_OMITTED",
|
|
452
769
|
message: `Raster text extraction omitted for clipped, masked, or hidden boundary ${e.tagName}.`
|
|
453
770
|
});
|
|
454
771
|
return;
|
|
455
772
|
}
|
|
456
773
|
} else if (!n) {
|
|
457
|
-
if (
|
|
458
|
-
|
|
774
|
+
if (F(e, _, !1, v !== void 0), I(e, _), e instanceof HTMLTableRowElement || e instanceof HTMLTableCellElement && e.rowSpan !== 1) {
|
|
775
|
+
let t = { ...S };
|
|
776
|
+
f.push(t), e instanceof HTMLTableRowElement && p.set(e, t);
|
|
777
|
+
}
|
|
778
|
+
if (e instanceof HTMLImageElement) {
|
|
779
|
+
if (_.objectFit !== "fill" || _.borderTopWidth !== "0px") throw new w("UNSUPPORTED_CSS", "Image boxes require object-fit: fill without borders.");
|
|
459
780
|
if ([
|
|
460
781
|
"paddingTop",
|
|
461
782
|
"paddingRight",
|
|
462
783
|
"paddingBottom",
|
|
463
784
|
"paddingLeft"
|
|
464
|
-
].some((e) => Number.parseFloat(
|
|
465
|
-
|
|
785
|
+
].some((e) => Number.parseFloat(_.getPropertyValue(e.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`))) !== 0) || _.backgroundColor !== "rgba(0, 0, 0, 0)") throw new w("UNSUPPORTED_CSS", "Image boxes require zero padding and a transparent background.");
|
|
786
|
+
c.push({
|
|
466
787
|
kind: "image",
|
|
467
|
-
bounds:
|
|
788
|
+
bounds: S,
|
|
468
789
|
element: e
|
|
469
790
|
});
|
|
470
|
-
} else [
|
|
791
|
+
} else if (![
|
|
471
792
|
"BR",
|
|
472
793
|
"COL",
|
|
473
794
|
"COLGROUP"
|
|
474
|
-
].includes(e.tagName)
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
795
|
+
].includes(e.tagName)) {
|
|
796
|
+
let t = {
|
|
797
|
+
kind: "box",
|
|
798
|
+
bounds: S,
|
|
799
|
+
background: _.backgroundColor,
|
|
800
|
+
borderColor: _.borderTopColor,
|
|
801
|
+
borderWidth: v ? 0 : Number.parseFloat(_.borderTopWidth)
|
|
802
|
+
};
|
|
803
|
+
c.push(t), i && u.set(e, t);
|
|
804
|
+
}
|
|
481
805
|
}
|
|
482
|
-
let
|
|
483
|
-
if (!
|
|
484
|
-
let t = Array.from(e.children).filter((e) => e instanceof HTMLElement && getComputedStyle(e).display !== "none" && getComputedStyle(e).visibility !== "hidden").map((e) => e.getBoundingClientRect());
|
|
806
|
+
let T = n || C;
|
|
807
|
+
if (!T || x) {
|
|
808
|
+
let t = Array.from(e.children).filter((e) => e instanceof HTMLElement && !(v && ["COL", "COLGROUP"].includes(e.tagName)) && getComputedStyle(e).display !== "none" && getComputedStyle(e).visibility !== "hidden").map((e) => e.getBoundingClientRect());
|
|
485
809
|
for (let e = 0; e < t.length; e += 1) for (let n = e + 1; n < t.length; n += 1) {
|
|
486
810
|
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
|
|
811
|
+
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 w("UNSUPPORTED_CSS", "Overlapping sibling boxes are unsupported; isolate them in one raster subtree.");
|
|
488
812
|
}
|
|
489
813
|
}
|
|
490
|
-
for (let n of e.childNodes) if (n instanceof Text)
|
|
491
|
-
else if (n instanceof HTMLElement)
|
|
814
|
+
for (let n of e.childNodes) if (n instanceof Text) c.push(...Ce(n, a, t, s, T));
|
|
815
|
+
else if (n instanceof HTMLElement) h(n, T, x);
|
|
492
816
|
else if (n instanceof Element) {
|
|
493
|
-
if (
|
|
817
|
+
if (T) m.push({
|
|
494
818
|
code: "RASTER_TEXT_OMITTED",
|
|
495
819
|
message: `Raster text extraction omitted for ${n.tagName}.`
|
|
496
820
|
});
|
|
497
|
-
else throw new
|
|
821
|
+
else throw new w("UNSUPPORTED_ELEMENT", `Cannot snapshot ${n.tagName}; use a raster subtree.`);
|
|
822
|
+
}
|
|
823
|
+
if (i && e instanceof HTMLTableSectionElement && e.tagName === "THEAD" && l.set(e, c.slice(g)), !T && e instanceof HTMLTableElement && v) {
|
|
824
|
+
let t = xe(e, a);
|
|
825
|
+
d.set(e, t);
|
|
826
|
+
for (let e of t.operations) c.push(e);
|
|
827
|
+
let n = Array.from(e.rows).filter((e) => p.has(e)), r = n[0] ? p.get(n[0]) : void 0, o = n.at(-1) ? p.get(n.at(-1)) : void 0, s = t.operations.reduce((e, { bounds: t }) => ({
|
|
828
|
+
top: Math.min(e.top, t.y),
|
|
829
|
+
bottom: Math.max(e.bottom, t.y + t.height)
|
|
830
|
+
}), {
|
|
831
|
+
top: r?.y ?? 0,
|
|
832
|
+
bottom: o ? o.y + o.height : 0
|
|
833
|
+
});
|
|
834
|
+
r && s.top < r.y && (r.height += r.y - s.top, r.y = s.top), o && (o.height = Math.max(o.height, s.bottom - o.y));
|
|
835
|
+
let u = e.tHead;
|
|
836
|
+
if (i && u && t.headerBounds) {
|
|
837
|
+
let e = t.headerBounds, n = t.operations.filter((t) => t.bounds.y < e.y + e.height + .001 && t.bounds.y + t.bounds.height > e.y - .001);
|
|
838
|
+
l.set(u, [...l.get(u) ?? [], ...n]);
|
|
839
|
+
}
|
|
498
840
|
}
|
|
499
841
|
}
|
|
500
|
-
|
|
501
|
-
let
|
|
502
|
-
for (let e of
|
|
842
|
+
h(e, !1);
|
|
843
|
+
let g = [];
|
|
844
|
+
for (let e of c) {
|
|
503
845
|
if (e.kind === "text") {
|
|
504
|
-
e.invisible ||
|
|
846
|
+
e.invisible || g.push(e);
|
|
505
847
|
continue;
|
|
506
848
|
}
|
|
507
849
|
if (e.kind === "box" && (e.background.startsWith("rgba(") ? Number(e.background.slice(e.background.lastIndexOf(",") + 1, -1)) : 1) === 0 && e.borderWidth === 0) continue;
|
|
508
850
|
let t = e.bounds;
|
|
509
|
-
if (
|
|
851
|
+
if (g.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 w("UNSUPPORTED_CSS", "Text overlaps later visible paint whose CSS paint phases cannot be represented safely; use an explicit containing raster region.");
|
|
510
852
|
}
|
|
511
|
-
if (
|
|
853
|
+
if (c.some((e) => {
|
|
512
854
|
if (e.kind === "text" && e.invisible) return !1;
|
|
513
855
|
let t = e.bounds;
|
|
514
|
-
return t.x < -.1 || t.y < -.1 || t.x + t.width >
|
|
515
|
-
})) throw new
|
|
856
|
+
return t.x < -.1 || t.y < -.1 || t.x + t.width > a.width + .1 || t.y + t.height > a.height + .1;
|
|
857
|
+
})) throw new w("SOURCE_OVERFLOW", "Visible source text or paint overflows the root border box.");
|
|
516
858
|
return {
|
|
517
|
-
width:
|
|
518
|
-
height:
|
|
519
|
-
operations:
|
|
520
|
-
warnings:
|
|
521
|
-
atomicBounds:
|
|
859
|
+
width: a.width,
|
|
860
|
+
height: a.height,
|
|
861
|
+
operations: c,
|
|
862
|
+
warnings: m,
|
|
863
|
+
atomicBounds: f,
|
|
864
|
+
...i ? { tableHeaders: Te(e, a, c, l, u, d) } : {}
|
|
522
865
|
};
|
|
523
866
|
}
|
|
524
867
|
// src/page.ts
|
|
525
|
-
function
|
|
526
|
-
if (!e ||
|
|
868
|
+
function L(e) {
|
|
869
|
+
if (!e || typeof e != "object" || Array.isArray(e)) throw new w("INVALID_OPTIONS", "PDF page options must be an object.");
|
|
527
870
|
let t = {
|
|
528
871
|
A4: [595.28, 841.89],
|
|
529
872
|
A3: [841.89, 1190.55],
|
|
530
873
|
Letter: [612, 792]
|
|
531
874
|
}, n = e.format ?? "A4";
|
|
532
|
-
if (typeof n != "object" && !Object.hasOwn(t, n)) throw new
|
|
875
|
+
if (typeof n != "object" && !Object.hasOwn(t, n)) throw new w("INVALID_OPTIONS", `Unsupported page format: ${n}.`);
|
|
533
876
|
let r = e.orientation ?? "portrait";
|
|
534
|
-
if (r !== "portrait" && r !== "landscape") throw new
|
|
877
|
+
if (r !== "portrait" && r !== "landscape") throw new w("INVALID_OPTIONS", `Unsupported page orientation: ${r}.`);
|
|
535
878
|
let i = e.margin ?? 24, a = typeof i == "number" ? {
|
|
536
879
|
top: i,
|
|
537
880
|
right: i,
|
|
@@ -543,183 +886,250 @@ function V(e) {
|
|
|
543
886
|
bottom: i?.bottom,
|
|
544
887
|
left: i?.left
|
|
545
888
|
};
|
|
546
|
-
if (Object.values(a).some((e) => !Number.isFinite(e) || e < 0)) throw new
|
|
889
|
+
if (Object.values(a).some((e) => !Number.isFinite(e) || e < 0)) throw new w("INVALID_OPTIONS", "Every page margin must be finite and nonnegative.");
|
|
547
890
|
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
|
|
891
|
+
if (o.some((e) => !Number.isFinite(e) || e <= 0)) throw new w("INVALID_OPTIONS", "Custom page width and height must be finite positive CSS pixel values.");
|
|
549
892
|
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
|
|
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.");
|
|
893
|
+
if (a.left + a.right >= s || a.top + a.bottom >= c) throw new w("INVALID_OPTIONS", "Page margins leave no positive content area.");
|
|
556
894
|
return {
|
|
557
895
|
width: s,
|
|
558
896
|
height: c,
|
|
559
897
|
margin: a
|
|
560
898
|
};
|
|
561
899
|
}
|
|
900
|
+
function De(e) {
|
|
901
|
+
if (!e || !Array.isArray(e.fonts) || e.fonts.length === 0) throw new w("INVALID_OPTIONS", "Provide at least one explicitly registered font.");
|
|
902
|
+
let t = L(e);
|
|
903
|
+
if (e.rasterScale !== void 0 && (!Number.isFinite(e.rasterScale) || e.rasterScale <= 0)) throw new w("INVALID_OPTIONS", "Raster scale must be a finite positive number.");
|
|
904
|
+
if (e.onWarning !== void 0 && typeof e.onWarning != "function") throw new w("INVALID_OPTIONS", "onWarning must be a function.");
|
|
905
|
+
if (e.onProgress !== void 0 && typeof e.onProgress != "function") throw new w("INVALID_OPTIONS", "onProgress must be a function.");
|
|
906
|
+
if (e.fallback !== void 0 && !["auto", "strict"].includes(e.fallback)) throw new w("INVALID_OPTIONS", "fallback must be auto or strict.");
|
|
907
|
+
if (e.pageBreak !== void 0 && !["auto", "css"].includes(e.pageBreak)) throw new w("INVALID_OPTIONS", "pageBreak must be auto or css.");
|
|
908
|
+
if (e.repeatTableHeaders !== void 0 && typeof e.repeatTableHeaders != "boolean") throw new w("INVALID_OPTIONS", "repeatTableHeaders must be a boolean.");
|
|
909
|
+
if (e.signal !== void 0 && !(e.signal instanceof AbortSignal)) throw new w("INVALID_OPTIONS", "signal must be an AbortSignal.");
|
|
910
|
+
return t;
|
|
911
|
+
}
|
|
912
|
+
// src/page-bands.ts
|
|
913
|
+
function R(e, t) {
|
|
914
|
+
if (e === void 0) return;
|
|
915
|
+
if (!e || typeof e != "object" || typeof e.text != "string" || !Number.isFinite(e.height) || e.height <= 0 || /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(e.text) || /[^\p{Script=Latin}\p{Script=Common}\p{Script=Inherited}]/u.test(e.text)) throw new w("INVALID_OPTIONS", "Page header/footer requires single-line Latin text and a finite positive reserved height.");
|
|
916
|
+
let n = e.font ?? t[0], r = e.fontSize ?? 12, i = e.align ?? "left";
|
|
917
|
+
if (!t.includes(n) || !Number.isFinite(r) || r <= 0 || ![
|
|
918
|
+
"left",
|
|
919
|
+
"center",
|
|
920
|
+
"right"
|
|
921
|
+
].includes(i)) throw new w("INVALID_OPTIONS", "Page header/footer needs a font included in fonts, a positive fontSize and left/center/right alignment.");
|
|
922
|
+
return Object.freeze({
|
|
923
|
+
text: e.text,
|
|
924
|
+
height: e.height,
|
|
925
|
+
font: n,
|
|
926
|
+
fontSize: r,
|
|
927
|
+
align: i
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
function Oe(e, t) {
|
|
931
|
+
let n = R(t.header, t.fonts), r = R(t.footer, t.fonts), i = {
|
|
932
|
+
...e,
|
|
933
|
+
margin: {
|
|
934
|
+
...e.margin,
|
|
935
|
+
top: e.margin.top + (n?.height ?? 0),
|
|
936
|
+
bottom: e.margin.bottom + (r?.height ?? 0)
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
if (i.margin.top + i.margin.bottom >= i.height) throw new w("INVALID_OPTIONS", "Page header/footer heights and margins leave no positive source content area.");
|
|
940
|
+
return {
|
|
941
|
+
content: i,
|
|
942
|
+
header: n,
|
|
943
|
+
footer: r
|
|
944
|
+
};
|
|
945
|
+
}
|
|
562
946
|
// src/pagination.ts
|
|
563
|
-
var
|
|
564
|
-
function
|
|
947
|
+
var z = .01;
|
|
948
|
+
function B(e, t, n) {
|
|
565
949
|
if (![
|
|
566
950
|
e.x,
|
|
567
951
|
e.y,
|
|
568
952
|
e.width,
|
|
569
953
|
e.height
|
|
570
|
-
].every(Number.isFinite) || e.width < 0 || e.height < 0 || e.y < -.01 || e.y + e.height > t +
|
|
954
|
+
].every(Number.isFinite) || e.width < 0 || e.height < 0 || e.y < -.01 || e.y + e.height > t + z) throw new w("PAGINATION_FAILED", `${n} geometry must be finite, nonnegative and within the source height.`);
|
|
571
955
|
}
|
|
572
|
-
function
|
|
573
|
-
return e.y < t -
|
|
956
|
+
function V(e, t) {
|
|
957
|
+
return e.y < t - z && e.y + e.height > t + z;
|
|
574
958
|
}
|
|
575
|
-
function
|
|
959
|
+
function ke(e, t, n) {
|
|
576
960
|
let r = e;
|
|
577
961
|
for (;;) {
|
|
578
|
-
let e = n.reduce((e, t) =>
|
|
962
|
+
let e = n.reduce((e, t) => V(t, r) ? Math.min(e, t.y) : e, r);
|
|
579
963
|
if (e === r) return r;
|
|
580
|
-
if (e <= t +
|
|
964
|
+
if (e <= t + z) throw new w("PAGINATION_FAILED", "Overlapping atomic items cannot fit on one page.");
|
|
581
965
|
r = e;
|
|
582
966
|
}
|
|
583
967
|
}
|
|
584
|
-
function
|
|
585
|
-
if (!Number.isFinite(t) || t <= 0) throw new
|
|
586
|
-
if (!Number.isFinite(e.height) || e.height <= 0) throw new
|
|
587
|
-
let r = [], i = [...e.operations.filter((e) => e.kind !== "box").map((e) => e.bounds), ...e.atomicBounds ?? []];
|
|
588
|
-
for (let n
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
968
|
+
function Ae(e, t, n) {
|
|
969
|
+
if (!Number.isFinite(t) || t <= 0) throw new w("PAGINATION_FAILED", "Page content height must be finite and positive.");
|
|
970
|
+
if (!Number.isFinite(e.height) || e.height <= 0) throw new w("PAGINATION_FAILED", "Source height must be finite and positive.");
|
|
971
|
+
let r = [], i = [...e.operations.filter((e) => e.kind !== "box" && e.kind !== "border").map((e) => e.bounds), ...e.atomicBounds ?? []], a = e.tableHeaders ?? [];
|
|
972
|
+
for (let [n, r] of a.entries()) {
|
|
973
|
+
if (B(r.bounds, e.height, "Table header"), r.bounds.width <= 0 || r.bounds.height <= 0 || !Number.isFinite(r.bodyStart) || !Number.isFinite(r.bodyEnd) || r.bodyStart < r.bounds.y + r.bounds.height - z || r.bodyEnd <= r.bodyStart || r.bodyEnd > e.height + z) throw new w("PAGINATION_FAILED", "Repeated table headers require a positive header followed by finite body row bounds.");
|
|
974
|
+
if (a.slice(0, n).some((e) => Math.min(e.bodyEnd, r.bodyEnd) - Math.max(e.bounds.y, r.bounds.y) > z)) throw new w("PAGINATION_FAILED", "Repeated table header continuation intervals must not overlap.");
|
|
975
|
+
let o = r.bodyStart;
|
|
976
|
+
for (;;) {
|
|
977
|
+
let e = i.reduce((e, t) => t.y >= r.bodyStart - z && t.y < r.bodyEnd - z && (t.y <= r.bodyStart + z || t.y < o - z) ? Math.max(e, t.y + t.height) : e, o);
|
|
978
|
+
if (e === o) break;
|
|
979
|
+
o = e;
|
|
980
|
+
}
|
|
981
|
+
if (o <= r.bodyStart + z) throw new w("PAGINATION_FAILED", "Repeated table headers require a measured atomic first body row.");
|
|
982
|
+
if (o - r.bounds.y > t + z) throw new w("PAGINATION_FAILED", "A table header and its first atomic body row cannot fit on one page.");
|
|
983
|
+
i.push({
|
|
984
|
+
...r.bounds,
|
|
985
|
+
height: o - r.bounds.y
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
for (let n of i) if (B(n, e.height, "Atomic"), n.height > t + z) throw new w("PAGINATION_FAILED", "An atomic item is taller than one page; this renderer cannot split it.");
|
|
989
|
+
let o = e.forcedBreaks ?? [];
|
|
990
|
+
for (let t of o) if (!Number.isFinite(t) || t < 0 || t > e.height) throw new w("PAGINATION_FAILED", "Forced page breaks must lie within the finite source height.");
|
|
991
|
+
let s = [...new Set(o)].filter((t) => t > z && t < e.height - z).sort((e, t) => e - t).filter((e, t, n) => t === 0 || e - n[t - 1] > z);
|
|
992
|
+
for (let e of s) if (i.some((t) => V(t, e))) throw new w("PAGINATION_FAILED", "A forced CSS page break crosses an atomic text, image, raster, table row or spanning cell.");
|
|
993
|
+
let c = !1;
|
|
994
|
+
function l() {
|
|
995
|
+
c || (c = !0, n?.({
|
|
596
996
|
code: "BREAK_AVOID_RELAXED",
|
|
597
997
|
message: "A CSS break-avoid preference could not fit on one page and was relaxed; native text, images and table rows remain indivisible."
|
|
598
998
|
}));
|
|
599
999
|
}
|
|
600
|
-
let
|
|
601
|
-
for (let n of e.avoidBreakBounds ?? [])
|
|
602
|
-
let
|
|
603
|
-
for (;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
1000
|
+
let u = [];
|
|
1001
|
+
for (let n of e.avoidBreakBounds ?? []) B(n, e.height, "Preferred break-avoid"), !s.some((e) => V(n, e)) && (n.height > t + z ? l() : u.push(n));
|
|
1002
|
+
let d = [...i, ...u], f = 0, p = 0;
|
|
1003
|
+
for (; f < e.height;) {
|
|
1004
|
+
let n = a.find((e) => f >= e.bodyStart - z && f < e.bodyEnd - z), o = n ? (e.atomicBounds ?? []).reduce((e, t) => t.y >= f - z && t.y < n.bodyEnd - z ? Math.min(e, t.y) : e, Infinity) : f, c = Number.isFinite(o) ? Math.max(0, o - f) : 0, u = n ? Math.max(n.bounds.height, n.bodyStart - n.bounds.y - c) : 0, m = t - u;
|
|
1005
|
+
if (m <= z) throw new w("PAGINATION_FAILED", "A repeated table header leaves no space for its body rows.");
|
|
1006
|
+
for (; s[p] !== void 0 && s[p] <= f + z;) p += 1;
|
|
1007
|
+
let h = s[p] ?? e.height, g = Math.min(f + m, h, e.height);
|
|
1008
|
+
if (n && i.some((e) => e.y <= f + z && V(e, f + m))) throw new w("PAGINATION_FAILED", "A repeated table header and its atomic body row cannot fit on one page.");
|
|
1009
|
+
let _ = ke(g, f, i), v = _;
|
|
1010
|
+
if (Math.abs(g - h) > z) for (;;) {
|
|
1011
|
+
let e = d.reduce((e, t) => V(t, v) ? Math.min(e, t.y) : e, v);
|
|
1012
|
+
if (e === v) break;
|
|
1013
|
+
if (e <= f + z) {
|
|
1014
|
+
l(), v = _;
|
|
611
1015
|
break;
|
|
612
1016
|
}
|
|
613
|
-
|
|
1017
|
+
v = e;
|
|
614
1018
|
}
|
|
1019
|
+
if (v <= f + z) throw new w("PAGINATION_FAILED", "Page planning must advance through the source.");
|
|
1020
|
+
if (n && !(e.atomicBounds ?? []).some((e) => e.y >= f - z && e.y < n.bodyEnd - z && e.y + e.height <= v + z && e.y + e.height > f + z)) throw new w("PAGINATION_FAILED", "A repeated table header must share its page with a complete atomic body row.");
|
|
615
1021
|
r.push({
|
|
616
|
-
start:
|
|
617
|
-
end:
|
|
618
|
-
|
|
1022
|
+
start: f,
|
|
1023
|
+
end: v,
|
|
1024
|
+
...n ? {
|
|
1025
|
+
header: n,
|
|
1026
|
+
headerHeight: u
|
|
1027
|
+
} : {}
|
|
1028
|
+
}), f = v;
|
|
619
1029
|
}
|
|
620
1030
|
return r;
|
|
621
1031
|
}
|
|
622
1032
|
// src/images.ts
|
|
623
|
-
function
|
|
624
|
-
throw new
|
|
1033
|
+
function H() {
|
|
1034
|
+
throw new w("RESOURCE_LOAD_FAILED", "JPEG EXIF orientation must be 1 with valid metadata; normalize the image pixels and remove orientation metadata before exporting.");
|
|
625
1035
|
}
|
|
626
|
-
function
|
|
1036
|
+
function je(e, t, n) {
|
|
627
1037
|
let r = new DataView(e.buffer, e.byteOffset + t, n - t);
|
|
628
|
-
r.byteLength < 8 &&
|
|
1038
|
+
r.byteLength < 8 && H();
|
|
629
1039
|
let i = r.getUint16(0);
|
|
630
|
-
i !== 18761 && i !== 19789 &&
|
|
1040
|
+
i !== 18761 && i !== 19789 && H();
|
|
631
1041
|
let a = i === 18761;
|
|
632
|
-
r.getUint16(2, a) !== 42 &&
|
|
1042
|
+
r.getUint16(2, a) !== 42 && H();
|
|
633
1043
|
let o = r.getUint32(4, a);
|
|
634
|
-
(o < 8 || o + 2 > r.byteLength) &&
|
|
1044
|
+
(o < 8 || o + 2 > r.byteLength) && H();
|
|
635
1045
|
let s = r.getUint16(o, a), c = o + 2 + s * 12;
|
|
636
|
-
c + 4 > r.byteLength &&
|
|
1046
|
+
c + 4 > r.byteLength && H();
|
|
637
1047
|
let l = !1;
|
|
638
1048
|
for (let e = 0; e < s; e += 1) {
|
|
639
1049
|
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) &&
|
|
1050
|
+
r.getUint16(t, a) === 274 && ((l || r.getUint16(t + 2, a) !== 3 || r.getUint32(t + 4, a) !== 1 || r.getUint16(t + 8, a) !== 1) && H(), l = !0);
|
|
641
1051
|
}
|
|
642
1052
|
let u = r.getUint32(c, a);
|
|
643
|
-
u !== 0 && (u < 8 || u + 2 > r.byteLength) &&
|
|
1053
|
+
u !== 0 && (u < 8 || u + 2 > r.byteLength) && H();
|
|
644
1054
|
}
|
|
645
|
-
function
|
|
1055
|
+
function Me(e) {
|
|
646
1056
|
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
|
|
1057
|
+
if (e[0] !== 255 || e[1] !== 216) throw new w("RESOURCE_LOAD_FAILED", "Native PDF images require PNG or JPEG bytes.");
|
|
648
1058
|
let t = 2;
|
|
649
1059
|
for (; t < e.length;) {
|
|
650
|
-
for (e[t] !== 255 &&
|
|
1060
|
+
for (e[t] !== 255 && H(); e[t] === 255;) t += 1;
|
|
651
1061
|
let n = e[t];
|
|
652
|
-
if ((n === void 0 || n === 0) &&
|
|
1062
|
+
if ((n === void 0 || n === 0) && H(), t += 1, n === 217) return "jpeg";
|
|
653
1063
|
if (n === 1 || n >= 208 && n <= 215) continue;
|
|
654
|
-
t + 2 > e.length &&
|
|
1064
|
+
t + 2 > e.length && H();
|
|
655
1065
|
let r = e[t] * 256 + e[t + 1], i = t + r;
|
|
656
|
-
if ((r < 2 || i > e.length) &&
|
|
1066
|
+
if ((r < 2 || i > e.length) && H(), n === 218) return "jpeg";
|
|
657
1067
|
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) &&
|
|
1068
|
+
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) && H(), je(e, a + 6, i)), t = i;
|
|
659
1069
|
}
|
|
660
|
-
|
|
1070
|
+
H();
|
|
661
1071
|
}
|
|
662
1072
|
// src/raster.ts
|
|
663
|
-
var
|
|
664
|
-
function
|
|
1073
|
+
var Ne = 16777216, Pe = 8192, Fe = /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z\d+/=\s]+$/i;
|
|
1074
|
+
function Ie(e) {
|
|
665
1075
|
let t = e.bytes;
|
|
666
|
-
if (!/^[\w -]+$/.test(e.family) || t.byteLength === 0) throw new
|
|
1076
|
+
if (!/^[\w -]+$/.test(e.family) || t.byteLength === 0) throw new w("RASTER_FAILED", "Raster capture requires nonempty registered fonts with plain CSS family names.");
|
|
667
1077
|
let n = "";
|
|
668
1078
|
for (let e = 0; e < t.length; e += 8192) n += String.fromCharCode(...t.subarray(e, e + 8192));
|
|
669
1079
|
let r = t[0] === 79 && t[1] === 84 && t[2] === 84 && t[3] === 79;
|
|
670
1080
|
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
1081
|
}
|
|
672
|
-
function
|
|
1082
|
+
function Le(e) {
|
|
673
1083
|
for (let t of e) {
|
|
674
1084
|
let n = e.getPropertyValue(t);
|
|
675
|
-
for (let e of n.matchAll(/url\(\s*(["']?)(.*?)\1\s*\)/gi)) if (!
|
|
1085
|
+
for (let e of n.matchAll(/url\(\s*(["']?)(.*?)\1\s*\)/gi)) if (!Fe.test(e[2] ?? "")) throw new w("RASTER_FAILED", `Raster capture requires inline bitmap resources (${t}).`);
|
|
676
1086
|
}
|
|
677
1087
|
}
|
|
678
|
-
function
|
|
1088
|
+
function Re(e, t) {
|
|
679
1089
|
let n = e.getBoundingClientRect(), r = [e, ...e.querySelectorAll("*")];
|
|
680
1090
|
for (let i of r) {
|
|
681
|
-
if (!(i instanceof HTMLElement)) throw new
|
|
682
|
-
if (i.shadowRoot || i.tagName.includes("-") || i.tagName === "SLOT") throw new
|
|
683
|
-
if (/^(CANVAS|IFRAME|OBJECT|EMBED|VIDEO|AUDIO|INPUT|TEXTAREA|SELECT|SCRIPT|STYLE|LINK)$/.test(i.tagName)) throw new
|
|
1091
|
+
if (!(i instanceof HTMLElement)) throw new w("RASTER_FAILED", "Raster capture supports HTML subtrees only; inline SVG needs a separate experiment.");
|
|
1092
|
+
if (i.shadowRoot || i.tagName.includes("-") || i.tagName === "SLOT") throw new w("RASTER_FAILED", "Raster capture does not inspect shadow trees or distributed slot content in supported renderer.");
|
|
1093
|
+
if (/^(CANVAS|IFRAME|OBJECT|EMBED|VIDEO|AUDIO|INPUT|TEXTAREA|SELECT|SCRIPT|STYLE|LINK)$/.test(i.tagName)) throw new w("RASTER_FAILED", `Raster capture does not support ${i.tagName.toLowerCase()} elements.`);
|
|
684
1094
|
let r = getComputedStyle(i);
|
|
685
|
-
if (
|
|
686
|
-
if (r.position === "fixed" || r.position === "sticky") throw new
|
|
687
|
-
if (i !== e && r.position === "absolute") throw new
|
|
1095
|
+
if (Le(r), r.mixBlendMode !== "normal" || r.backdropFilter !== "none") throw new w("RASTER_FAILED", "Raster capture cannot reproduce blending with pixels outside its subtree.");
|
|
1096
|
+
if (r.position === "fixed" || r.position === "sticky") throw new w("RASTER_FAILED", "Raster capture does not reproduce viewport-dependent positioning.");
|
|
1097
|
+
if (i !== e && r.position === "absolute") throw new w("RASTER_FAILED", "Raster capture does not normalize external containing blocks for positioned descendants.");
|
|
688
1098
|
let a = r.boxShadow.split(/,(?![^(]*\))/);
|
|
689
|
-
if (r.filter !== "none" || r.boxShadow !== "none" && a.some((e) => !e.includes("inset"))) throw new
|
|
690
|
-
if (r.textShadow !== "none" || r.outlineStyle !== "none" && Number.parseFloat(r.outlineWidth) > 0) throw new
|
|
691
|
-
if (r.backgroundAttachment.includes("fixed")) throw new
|
|
692
|
-
if (i === e && r.transform !== "none") throw new
|
|
693
|
-
if (r.display === "list-item") throw new
|
|
1099
|
+
if (r.filter !== "none" || r.boxShadow !== "none" && a.some((e) => !e.includes("inset"))) throw new w("RASTER_FAILED", "Raster capture requires effects contained in the border box; outer shadows and filters need expanded bounds.");
|
|
1100
|
+
if (r.textShadow !== "none" || r.outlineStyle !== "none" && Number.parseFloat(r.outlineWidth) > 0) throw new w("RASTER_FAILED", "Raster capture requires expanded bounds before capturing text shadows or outlines.");
|
|
1101
|
+
if (r.backgroundAttachment.includes("fixed")) throw new w("RASTER_FAILED", "Raster capture does not preserve viewport-dependent background attachment.");
|
|
1102
|
+
if (i === e && r.transform !== "none") throw new w("RASTER_FAILED", "Raster capture does not normalize transformed region coordinates.");
|
|
1103
|
+
if (r.display === "list-item") throw new w("RASTER_FAILED", "Raster capture does not preserve generated list markers in supported renderer.");
|
|
694
1104
|
for (let e of ["::before", "::after"]) {
|
|
695
1105
|
let t = getComputedStyle(i, e).content;
|
|
696
|
-
if (t !== "none" && t !== "normal") throw new
|
|
1106
|
+
if (t !== "none" && t !== "normal") throw new w("RASTER_FAILED", "Raster capture does not support generated pseudo-element content in supported renderer.");
|
|
697
1107
|
}
|
|
698
1108
|
if (i instanceof HTMLImageElement) {
|
|
699
|
-
if (i.srcset || !
|
|
700
|
-
if (!i.complete || i.naturalWidth === 0) throw new
|
|
1109
|
+
if (i.srcset || !Fe.test(i.currentSrc || i.src)) throw new w("RASTER_FAILED", "Raster capture requires inline bitmap images without srcset.");
|
|
1110
|
+
if (!i.complete || i.naturalWidth === 0) throw new w("RASTER_FAILED", "Raster capture requires successfully decoded images.");
|
|
701
1111
|
}
|
|
702
1112
|
if ([...i.childNodes].some((e) => e.nodeType === Node.TEXT_NODE && !!e.textContent?.trim())) {
|
|
703
|
-
if (!r.font) throw new
|
|
1113
|
+
if (!r.font) throw new w("RASTER_FAILED", "Raster capture requires a serializable computed font shorthand to preserve exact font sizes.");
|
|
704
1114
|
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
|
|
1115
|
+
if (!t.some((t) => t.family.toLowerCase() === e?.toLowerCase() && t.weight === Number(r.fontWeight) && t.style === r.fontStyle)) throw new w("RASTER_FAILED", "Raster capture text requires an explicitly registered matching font face.");
|
|
706
1116
|
}
|
|
707
1117
|
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
|
|
1118
|
+
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 w("RASTER_FAILED", "Raster capture descendants must stay inside the selected border box.");
|
|
709
1119
|
}
|
|
710
1120
|
}
|
|
711
|
-
async function
|
|
1121
|
+
async function ze(e, t, n, r = {
|
|
712
1122
|
x: 0,
|
|
713
1123
|
y: 0
|
|
714
1124
|
}) {
|
|
715
|
-
if (!e.isConnected || e.ownerDocument !== document) throw new
|
|
716
|
-
if (!Number.isFinite(n) || n <= 0) throw new
|
|
717
|
-
if (!r || ![r.x, r.y].every((e) => Number.isFinite(e) && e >= 0 && e < 1)) throw new
|
|
1125
|
+
if (!e.isConnected || e.ownerDocument !== document) throw new w("RASTER_FAILED", "Raster capture requires a connected element in the current document.");
|
|
1126
|
+
if (!Number.isFinite(n) || n <= 0) throw new w("RASTER_FAILED", "Raster scale must be a finite positive number.");
|
|
1127
|
+
if (!r || ![r.x, r.y].every((e) => Number.isFinite(e) && e >= 0 && e < 1)) throw new w("RASTER_FAILED", "Raster offsets must be finite CSS pixel fractions from zero inclusive to one exclusive.");
|
|
718
1128
|
await document.fonts.ready;
|
|
719
1129
|
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 >
|
|
721
|
-
|
|
722
|
-
let u = t.map(
|
|
1130
|
+
if (i <= 0 || a <= 0 || c < 1 || l < 1 || c > Pe || l > Pe || c * l > Ne) throw new w("RASTER_FAILED", "Raster region exceeds the supported renderer canvas budget or has empty bounds.");
|
|
1131
|
+
Re(e, t);
|
|
1132
|
+
let u = t.map(Ie).join("\n"), d = ["font", ...Array.from(getComputedStyle(e)).filter((e) => e !== "font-size")], f = (await C(e, {
|
|
723
1133
|
width: o,
|
|
724
1134
|
height: s,
|
|
725
1135
|
pixelRatio: n,
|
|
@@ -738,12 +1148,12 @@ async function ve(e, t, n, r = {
|
|
|
738
1148
|
transform: `translate(${r.x}px, ${r.y}px)`
|
|
739
1149
|
}
|
|
740
1150
|
})).match(/^data:image\/png;base64,(.+)$/)?.[1];
|
|
741
|
-
if (!f) throw new
|
|
1151
|
+
if (!f) throw new w("RASTER_FAILED", "Raster capture produced an empty or invalid PNG.");
|
|
742
1152
|
let p = atob(f);
|
|
743
1153
|
return Uint8Array.from(p, (e) => e.charCodeAt(0));
|
|
744
1154
|
}
|
|
745
1155
|
// src/text.ts
|
|
746
|
-
var
|
|
1156
|
+
var Be = class {
|
|
747
1157
|
font;
|
|
748
1158
|
program;
|
|
749
1159
|
words = /* @__PURE__ */ new Map();
|
|
@@ -757,11 +1167,11 @@ var ye = class {
|
|
|
757
1167
|
let n = `${t ? "1" : "0"}:${e}`, r = this.words.get(n);
|
|
758
1168
|
if (r) return r;
|
|
759
1169
|
let a = this.program.layout(e, { kern: t }), o = this.font.encodeText(e).asString();
|
|
760
|
-
if (o.length !== a.glyphs.length * 4) throw new
|
|
1170
|
+
if (o.length !== a.glyphs.length * 4) throw new w("PDF_WRITE_FAILED", "PDF font encoding disagrees with font shaping.");
|
|
761
1171
|
let s = 0, c = 0, l = a.glyphs.map((e, t) => {
|
|
762
1172
|
let n = o.slice(t * 4, t * 4 + 4);
|
|
763
|
-
if (Number.parseInt(n, 16) !== e.id) throw new
|
|
764
|
-
if (e.codePoints.length === 0) throw new
|
|
1173
|
+
if (Number.parseInt(n, 16) !== e.id) throw new w("PDF_WRITE_FAILED", "PDF glyph identifiers disagree with shaping.");
|
|
1174
|
+
if (e.codePoints.length === 0) throw new w("PDF_WRITE_FAILED", "The font produced a shaped glyph without a Unicode source mapping.");
|
|
765
1175
|
let r = a.positions[t];
|
|
766
1176
|
this.unicode.has(n) || this.unicode.set(n, [...e.codePoints]), this.widths.set(n, e.advanceWidth * 1e3 / this.unitsPerEm);
|
|
767
1177
|
let l = {
|
|
@@ -773,6 +1183,19 @@ var ye = class {
|
|
|
773
1183
|
});
|
|
774
1184
|
return this.words.set(n, l), l;
|
|
775
1185
|
}
|
|
1186
|
+
measure(e) {
|
|
1187
|
+
let t = this.program.layout(e), n = 0, r = 0, i = 0, a = 0, o = this.program.ascent, s = -this.program.descent;
|
|
1188
|
+
for (let e = 0; e < t.glyphs.length; e += 1) {
|
|
1189
|
+
let c = t.glyphs[e], l = t.positions[e];
|
|
1190
|
+
i = Math.min(i, n + l.xOffset + c.bbox.minX), a = Math.max(a, n + l.xOffset + c.bbox.maxX), o = Math.max(o, r + l.yOffset + c.bbox.maxY), s = Math.max(s, -(r + l.yOffset + c.bbox.minY)), n += l.xAdvance, r += l.yAdvance;
|
|
1191
|
+
}
|
|
1192
|
+
return {
|
|
1193
|
+
left: i,
|
|
1194
|
+
right: Math.max(a, n),
|
|
1195
|
+
ascent: o,
|
|
1196
|
+
descent: s
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
776
1199
|
async embedUnicode(e) {
|
|
777
1200
|
if (await this.font.embed(), this.unicode.size === 0) return;
|
|
778
1201
|
let r = [...this.unicode].map(([e, t]) => {
|
|
@@ -804,39 +1227,66 @@ var ye = class {
|
|
|
804
1227
|
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
1228
|
c.set(a.of("W"), e.context.obj(l));
|
|
806
1229
|
}
|
|
807
|
-
},
|
|
808
|
-
function
|
|
1230
|
+
}, U = .75;
|
|
1231
|
+
function W(e) {
|
|
809
1232
|
let t = e.match(/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/);
|
|
810
|
-
if (!t) throw new
|
|
1233
|
+
if (!t) throw new w("UNSUPPORTED_CSS", `Unsupported computed color: ${e}`);
|
|
811
1234
|
return {
|
|
812
|
-
color:
|
|
1235
|
+
color: g(Number(t[1]) / 255, Number(t[2]) / 255, Number(t[3]) / 255),
|
|
813
1236
|
opacity: Number(t[4] ?? 1)
|
|
814
1237
|
};
|
|
815
1238
|
}
|
|
816
|
-
function
|
|
1239
|
+
function G(e, t) {
|
|
817
1240
|
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
|
|
819
|
-
for (let t of e.text) if (!n.characters.has(t.codePointAt(0))) throw new
|
|
1241
|
+
if (!n) throw new w("MISSING_FONT", `Unregistered font face: ${e.family} ${e.weight} ${e.style}`);
|
|
1242
|
+
for (let t of e.text) if (!n.characters.has(t.codePointAt(0))) throw new w("MISSING_GLYPH", `Missing glyph: ${t} (${e.family} ${e.weight} ${e.style})`);
|
|
820
1243
|
return n;
|
|
821
1244
|
}
|
|
822
|
-
function
|
|
823
|
-
let c =
|
|
824
|
-
if (l || (l = e.node.newFontDictionary(n.font.name, n.font.ref), a.fonts.set(n.font, l)), e.pushOperators(
|
|
1245
|
+
function K(e, t, n, r, i, a) {
|
|
1246
|
+
let c = W(t.color), l = a.fonts.get(n.font);
|
|
1247
|
+
if (l || (l = e.node.newFontDictionary(n.font.name, n.font.ref), a.fonts.set(n.font, l)), e.pushOperators(m(), _(c.color)), c.opacity !== 1) {
|
|
825
1248
|
let t = a.opacity.get(c.opacity);
|
|
826
1249
|
t || (t = e.node.newExtGState("TextOpacity", e.doc.context.obj({
|
|
827
1250
|
Type: "ExtGState",
|
|
828
1251
|
ca: c.opacity
|
|
829
|
-
})), a.opacity.set(c.opacity, t)), e.pushOperators(
|
|
1252
|
+
})), a.opacity.set(c.opacity, t)), e.pushOperators(y(t));
|
|
830
1253
|
}
|
|
831
|
-
e.pushOperators(s(),
|
|
832
|
-
let
|
|
1254
|
+
e.pushOperators(s(), v(l, t.fontSize * U), x(t.invisible ? o.Invisible : o.Fill));
|
|
1255
|
+
let u = t.fontSize * U / n.positioned.unitsPerEm, d = (i.height - i.margin.top - (t.baseline - r)) * U;
|
|
833
1256
|
for (let r of t.runs) {
|
|
834
|
-
let a = (i.margin.left + r.x) *
|
|
835
|
-
for (let i of n.positioned.shape(r.text, t.kerning ?? !0)) e.pushOperators(
|
|
1257
|
+
let a = (i.margin.left + r.x) * U;
|
|
1258
|
+
for (let i of n.positioned.shape(r.text, t.kerning ?? !0)) e.pushOperators(b(1, 0, 0, 1, a + i.x * u, d + i.y * u), S(i.encoded));
|
|
836
1259
|
}
|
|
837
|
-
e.pushOperators(
|
|
1260
|
+
e.pushOperators(f(), p());
|
|
838
1261
|
}
|
|
839
|
-
function
|
|
1262
|
+
function Ve(e, t, n, r, i, a) {
|
|
1263
|
+
let o = e.text.replaceAll("{pageNumber}", String(t)).replaceAll("{pageCount}", String(n)), s = a.find((t) => t.definition === e.font), c = e.fontSize / s.positioned.unitsPerEm, l = s.positioned.measure(o), u = (l.right - l.left) * c, d = (l.ascent + l.descent) * c, f = i.width - i.margin.left - i.margin.right;
|
|
1264
|
+
if (u > f + .01 || d > e.height + .01) throw new w("SOURCE_OVERFLOW", "Page header/footer text does not fit its reserved height or page content width; increase its area or reduce fontSize.");
|
|
1265
|
+
let p = e.align === "right" ? f - u : e.align === "center" ? (f - u) / 2 : 0, m = p - l.left * c, h = r - i.margin.top + (e.height - d) / 2;
|
|
1266
|
+
return {
|
|
1267
|
+
kind: "text",
|
|
1268
|
+
bounds: {
|
|
1269
|
+
x: p,
|
|
1270
|
+
y: h,
|
|
1271
|
+
width: u,
|
|
1272
|
+
height: d
|
|
1273
|
+
},
|
|
1274
|
+
text: o,
|
|
1275
|
+
runs: [{
|
|
1276
|
+
text: o,
|
|
1277
|
+
x: m,
|
|
1278
|
+
width: u
|
|
1279
|
+
}],
|
|
1280
|
+
baseline: h + l.ascent * c,
|
|
1281
|
+
fontSize: e.fontSize,
|
|
1282
|
+
family: e.font.family,
|
|
1283
|
+
weight: e.font.weight,
|
|
1284
|
+
style: e.font.style,
|
|
1285
|
+
color: "rgb(0, 0, 0)",
|
|
1286
|
+
invisible: !1
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function He(e) {
|
|
840
1290
|
let t = Math.floor(e.x), n = Math.floor(e.y);
|
|
841
1291
|
return {
|
|
842
1292
|
x: t,
|
|
@@ -845,10 +1295,10 @@ function Z(e) {
|
|
|
845
1295
|
height: Math.ceil(e.y + e.height) - n
|
|
846
1296
|
};
|
|
847
1297
|
}
|
|
848
|
-
async function
|
|
1298
|
+
async function Ue(e, t, n) {
|
|
849
1299
|
let r = t.currentSrc || t.src;
|
|
850
1300
|
try {
|
|
851
|
-
|
|
1301
|
+
T(n);
|
|
852
1302
|
let t = await fetch(r, {
|
|
853
1303
|
mode: "cors",
|
|
854
1304
|
credentials: "same-origin",
|
|
@@ -856,109 +1306,182 @@ async function xe(e, t, n) {
|
|
|
856
1306
|
});
|
|
857
1307
|
if (!t.ok) throw Error(`Image request returned HTTP ${t.status}.`);
|
|
858
1308
|
let i = new Uint8Array(await t.arrayBuffer());
|
|
859
|
-
return
|
|
1309
|
+
return T(n), Me(i) === "png" ? await e.embedPng(i) : await e.embedJpg(i);
|
|
860
1310
|
} catch (e) {
|
|
861
|
-
throw
|
|
1311
|
+
throw T(n), e instanceof w ? e : new w("RESOURCE_LOAD_FAILED", "The source image could not be embedded; provide a readable PNG/JPEG with same-origin or CORS access.", { cause: e });
|
|
862
1312
|
}
|
|
863
1313
|
}
|
|
864
|
-
async function
|
|
1314
|
+
async function We(t, n, i, a, o = {}) {
|
|
865
1315
|
try {
|
|
866
|
-
if (
|
|
1316
|
+
if (T(o.signal), t.width > i.width - i.margin.left - i.margin.right) throw new w("SOURCE_OVERFLOW", "Source is wider than the PDF content area.");
|
|
867
1317
|
let s = await r.create();
|
|
868
|
-
|
|
869
|
-
let u =
|
|
1318
|
+
T(o.signal), s.registerFontkit(e), oe(s, o.metadata);
|
|
1319
|
+
let l = o.reportProgress ? n.length + t.operations.filter((e) => e.kind === "image" || e.kind === "raster").length : 0, u = 0;
|
|
1320
|
+
o.reportProgress && await o.reportProgress({
|
|
1321
|
+
stage: "resources",
|
|
1322
|
+
completed: 0,
|
|
1323
|
+
total: l
|
|
1324
|
+
});
|
|
1325
|
+
let f = [];
|
|
870
1326
|
for (let e of n) {
|
|
871
|
-
|
|
1327
|
+
T(o.signal);
|
|
872
1328
|
let t = await s.embedFont(e.bytes);
|
|
873
|
-
|
|
1329
|
+
f.push({
|
|
874
1330
|
definition: e,
|
|
875
1331
|
font: t,
|
|
876
1332
|
characters: new Set(t.getCharacterSet()),
|
|
877
|
-
positioned: new
|
|
1333
|
+
positioned: new Be(t, e.bytes)
|
|
1334
|
+
}), u += 1, o.reportProgress && await o.reportProgress({
|
|
1335
|
+
stage: "resources",
|
|
1336
|
+
completed: u,
|
|
1337
|
+
total: l
|
|
878
1338
|
});
|
|
879
1339
|
}
|
|
880
|
-
for (let e of t.operations) e.kind !== "text" || e.invisible && o.includeRasterText === !1 ||
|
|
881
|
-
let
|
|
1340
|
+
for (let e of t.operations) e.kind !== "text" || e.invisible && o.includeRasterText === !1 || G(e, f);
|
|
1341
|
+
let g = a.map((e, t) => {
|
|
1342
|
+
let n = [];
|
|
1343
|
+
o.header && n.push(Ve(o.header, t + 1, a.length, i.margin.top, i, f)), o.footer && n.push(Ve(o.footer, t + 1, a.length, i.height - i.margin.bottom - o.footer.height, i, f));
|
|
1344
|
+
for (let e of n) G(e, f);
|
|
1345
|
+
return n;
|
|
1346
|
+
}), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map();
|
|
882
1347
|
for (let e of t.operations) {
|
|
883
|
-
if (
|
|
884
|
-
let t =
|
|
1348
|
+
if (T(o.signal), e.kind === "raster") {
|
|
1349
|
+
let t = He(e.bounds);
|
|
885
1350
|
try {
|
|
886
|
-
let r = await
|
|
1351
|
+
let r = await ze(e.element, n, o.rasterScale ?? 2, {
|
|
887
1352
|
x: e.bounds.x - t.x,
|
|
888
1353
|
y: e.bounds.y - t.y
|
|
889
1354
|
});
|
|
890
|
-
|
|
1355
|
+
T(o.signal), _.set(e, await s.embedPng(r));
|
|
891
1356
|
} catch (e) {
|
|
892
|
-
throw
|
|
1357
|
+
throw T(o.signal), e instanceof w ? e : new w("RASTER_FAILED", "The selected local raster region could not be captured.", { cause: e });
|
|
893
1358
|
}
|
|
894
1359
|
}
|
|
895
1360
|
if (e.kind === "image") {
|
|
896
|
-
let t = e.element.currentSrc || e.element.src, n =
|
|
897
|
-
n || (n = await
|
|
1361
|
+
let t = e.element.currentSrc || e.element.src, n = v.get(t);
|
|
1362
|
+
n || (n = await Ue(s, e.element, o.signal), v.set(t, n)), _.set(e, n);
|
|
898
1363
|
}
|
|
1364
|
+
(e.kind === "image" || e.kind === "raster") && (u += 1, o.reportProgress && await o.reportProgress({
|
|
1365
|
+
stage: "resources",
|
|
1366
|
+
completed: u,
|
|
1367
|
+
total: l
|
|
1368
|
+
}));
|
|
899
1369
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1370
|
+
o.reportProgress && await o.reportProgress({
|
|
1371
|
+
stage: "pages",
|
|
1372
|
+
completed: 0,
|
|
1373
|
+
total: a.length
|
|
1374
|
+
});
|
|
1375
|
+
for (let [e, n] of a.entries()) {
|
|
1376
|
+
T(o.signal);
|
|
1377
|
+
let r = s.addPage([i.width * U, i.height * U]), l = {
|
|
903
1378
|
fonts: /* @__PURE__ */ new Map(),
|
|
904
1379
|
opacity: /* @__PURE__ */ new Map()
|
|
905
1380
|
};
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
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
|
|
1381
|
+
function u(e, t, n) {
|
|
1382
|
+
let a = {
|
|
1383
|
+
...i,
|
|
1384
|
+
margin: {
|
|
1385
|
+
...i.margin,
|
|
1386
|
+
top: n.y
|
|
1387
|
+
}
|
|
919
1388
|
};
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
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
|
-
});
|
|
1389
|
+
r.pushOperators(m(), h(n.x * U, (i.height - n.y - n.height) * U, n.width * U, n.height * U), c(), d());
|
|
1390
|
+
for (let s of e) {
|
|
1391
|
+
let e = s.bounds;
|
|
1392
|
+
if (e.y >= t + n.height - .01 || e.y + e.height <= t + .01) continue;
|
|
1393
|
+
if (s.kind === "text") {
|
|
1394
|
+
s.invisible && o.includeRasterText === !1 || K(r, s, G(s, f), t, a, l);
|
|
1395
|
+
continue;
|
|
937
1396
|
}
|
|
938
|
-
|
|
1397
|
+
let c = s.kind === "raster" ? He(e) : e, u = {
|
|
1398
|
+
x: (i.margin.left + c.x) * U,
|
|
1399
|
+
y: (i.height - n.y - (c.y - t) - c.height) * U,
|
|
1400
|
+
width: c.width * U,
|
|
1401
|
+
height: c.height * U
|
|
1402
|
+
};
|
|
1403
|
+
if (s.kind === "box") {
|
|
1404
|
+
let e = W(s.background), t = W(s.borderColor);
|
|
1405
|
+
if (r.drawRectangle({
|
|
1406
|
+
...u,
|
|
1407
|
+
color: e.color,
|
|
1408
|
+
opacity: e.opacity
|
|
1409
|
+
}), s.borderWidth > 0) {
|
|
1410
|
+
let e = s.borderWidth * U / 2;
|
|
1411
|
+
r.drawRectangle({
|
|
1412
|
+
x: u.x + e,
|
|
1413
|
+
y: u.y + e,
|
|
1414
|
+
width: u.width - e * 2,
|
|
1415
|
+
height: u.height - e * 2,
|
|
1416
|
+
borderWidth: s.borderWidth * U,
|
|
1417
|
+
borderColor: t.color,
|
|
1418
|
+
borderOpacity: t.opacity
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
} else if (s.kind === "border") {
|
|
1422
|
+
let e = W(s.color);
|
|
1423
|
+
r.drawRectangle({
|
|
1424
|
+
...u,
|
|
1425
|
+
color: e.color,
|
|
1426
|
+
opacity: e.opacity
|
|
1427
|
+
});
|
|
1428
|
+
} else r.drawImage(_.get(s), u);
|
|
1429
|
+
}
|
|
1430
|
+
r.pushOperators(p());
|
|
1431
|
+
}
|
|
1432
|
+
let v = i.margin.top + (o.header?.height ?? 0), y = n.headerHeight ?? (n.header ? n.header.bodyStart - n.header.bounds.y : 0);
|
|
1433
|
+
if (o.header) {
|
|
1434
|
+
let t = g[e][0];
|
|
1435
|
+
K(r, t, G(t, f), 0, i, l);
|
|
1436
|
+
}
|
|
1437
|
+
if (n.header && u(n.header.operations, n.header.bounds.y, {
|
|
1438
|
+
x: i.margin.left + n.header.bounds.x,
|
|
1439
|
+
y: v,
|
|
1440
|
+
width: n.header.bounds.width,
|
|
1441
|
+
height: y
|
|
1442
|
+
}), u(t.operations, n.start, {
|
|
1443
|
+
x: i.margin.left,
|
|
1444
|
+
y: v + y,
|
|
1445
|
+
width: i.width - i.margin.left - i.margin.right,
|
|
1446
|
+
height: n.end - n.start
|
|
1447
|
+
}), o.footer) {
|
|
1448
|
+
let t = g[e].at(-1);
|
|
1449
|
+
K(r, t, G(t, f), 0, i, l);
|
|
939
1450
|
}
|
|
940
|
-
|
|
1451
|
+
o.reportProgress && await o.reportProgress({
|
|
1452
|
+
stage: "pages",
|
|
1453
|
+
completed: e + 1,
|
|
1454
|
+
total: a.length
|
|
1455
|
+
});
|
|
941
1456
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1457
|
+
T(o.signal), o.reportProgress && await o.reportProgress({
|
|
1458
|
+
stage: "saving",
|
|
1459
|
+
completed: 0,
|
|
1460
|
+
total: 1
|
|
1461
|
+
});
|
|
1462
|
+
for (let e of f) await e.positioned.embedUnicode(s), T(o.signal);
|
|
1463
|
+
let y = Uint8Array.from(await s.save());
|
|
1464
|
+
return T(o.signal), o.reportProgress && await o.reportProgress({
|
|
1465
|
+
stage: "saving",
|
|
1466
|
+
completed: 1,
|
|
1467
|
+
total: 1
|
|
1468
|
+
}), {
|
|
1469
|
+
bytes: y,
|
|
947
1470
|
slices: a
|
|
948
1471
|
};
|
|
949
1472
|
} catch (e) {
|
|
950
|
-
throw
|
|
1473
|
+
throw T(o.signal), e instanceof w ? e : new w("PDF_WRITE_FAILED", "The measured content could not be serialized as a PDF.", { cause: e });
|
|
951
1474
|
}
|
|
952
1475
|
}
|
|
953
1476
|
// src/prepare.ts
|
|
954
|
-
async function
|
|
955
|
-
return
|
|
1477
|
+
async function q(e, t) {
|
|
1478
|
+
return T(t), t ? new Promise((n, r) => {
|
|
956
1479
|
let i = () => r(new DOMException("PDF rendering was cancelled.", "AbortError"));
|
|
957
1480
|
t.addEventListener("abort", i, { once: !0 }), e.then(n, r).finally(() => t.removeEventListener("abort", i));
|
|
958
1481
|
}) : e;
|
|
959
1482
|
}
|
|
960
|
-
function
|
|
961
|
-
if (
|
|
1483
|
+
function Ge(e, t) {
|
|
1484
|
+
if (T(t), typeof document > "u" || !(e instanceof HTMLElement) || !e.isConnected || e.ownerDocument !== document) throw new w("INVALID_SOURCE", "Provide a connected HTMLElement in the current document.");
|
|
962
1485
|
let n = !1, r, i = /* @__PURE__ */ new Map(), a = new MutationObserver(() => {
|
|
963
1486
|
n = !0;
|
|
964
1487
|
}), o = [];
|
|
@@ -1008,18 +1531,18 @@ function Se(e, t) {
|
|
|
1008
1531
|
return `${t >>> 0}:${n >>> 0}`;
|
|
1009
1532
|
}
|
|
1010
1533
|
function d() {
|
|
1011
|
-
if (
|
|
1534
|
+
if (T(t), a.takeRecords().length && (n = !0), !e.isConnected || n || r !== void 0 && u() !== r) throw new w("SOURCE_CHANGED", "The source or its styles changed during PDF rendering. Retry with a stable source.");
|
|
1012
1535
|
}
|
|
1013
1536
|
function f() {
|
|
1014
|
-
if (d(), [...e.getAnimations({ subtree: !0 }), ...o.flatMap((e) => e.getAnimations())].some((e) => e.playState === "running")) throw new
|
|
1537
|
+
if (d(), [...e.getAnimations({ subtree: !0 }), ...o.flatMap((e) => e.getAnimations())].some((e) => e.playState === "running")) throw new w("UNSUPPORTED_CSS", "Pause source animations before rendering a PDF.");
|
|
1015
1538
|
r = u();
|
|
1016
1539
|
}
|
|
1017
1540
|
async function p() {
|
|
1018
|
-
await
|
|
1541
|
+
await q(document.fonts.ready, t);
|
|
1019
1542
|
try {
|
|
1020
|
-
await
|
|
1543
|
+
await q(Promise.all([...e.querySelectorAll("img"), ...e instanceof HTMLImageElement ? [e] : []].map((e) => e.decode())), t);
|
|
1021
1544
|
} catch (e) {
|
|
1022
|
-
throw
|
|
1545
|
+
throw T(t), new w("RESOURCE_LOAD_FAILED", "A source image could not be decoded.", { cause: e });
|
|
1023
1546
|
}
|
|
1024
1547
|
d();
|
|
1025
1548
|
}
|
|
@@ -1030,8 +1553,26 @@ function Se(e, t) {
|
|
|
1030
1553
|
dispose: () => a.disconnect()
|
|
1031
1554
|
};
|
|
1032
1555
|
}
|
|
1556
|
+
// src/progress.ts
|
|
1557
|
+
function Ke(e, t) {
|
|
1558
|
+
let n, r = 0;
|
|
1559
|
+
return {
|
|
1560
|
+
report: e ? async (i) => {
|
|
1561
|
+
T(t);
|
|
1562
|
+
try {
|
|
1563
|
+
e(Object.freeze({ ...i }));
|
|
1564
|
+
} catch (e) {
|
|
1565
|
+
throw n = { error: e }, e;
|
|
1566
|
+
}
|
|
1567
|
+
T(t), i.stage !== "complete" && (i.completed === 0 || i.completed === i.total || performance.now() - r >= 32) && (await new Promise((e) => setTimeout(e, 0)), r = performance.now(), T(t));
|
|
1568
|
+
} : void 0,
|
|
1569
|
+
rethrow(e) {
|
|
1570
|
+
throw n ? n.error : (T(t), e);
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1033
1574
|
// src/result.ts
|
|
1034
|
-
function
|
|
1575
|
+
function qe(e, t, n) {
|
|
1035
1576
|
let r = Uint8Array.from(e), i = Object.freeze(n.map((e) => Object.freeze({ ...e })));
|
|
1036
1577
|
return Object.freeze({
|
|
1037
1578
|
pageCount: t,
|
|
@@ -1043,7 +1584,7 @@ function Ce(e, t, n) {
|
|
|
1043
1584
|
return new Blob([r], { type: "application/pdf" });
|
|
1044
1585
|
},
|
|
1045
1586
|
async download(e = "document.pdf") {
|
|
1046
|
-
if (typeof e != "string" || !e.trim() || /[/\\]/.test(e) || [...e].some((e) => e.codePointAt(0) < 32)) throw new
|
|
1587
|
+
if (typeof e != "string" || !e.trim() || /[/\\]/.test(e) || [...e].some((e) => e.codePointAt(0) < 32)) throw new w("INVALID_OPTIONS", "Provide a nonempty PDF filename without path separators or control characters.");
|
|
1047
1588
|
let t = URL.createObjectURL(new Blob([r], { type: "application/pdf" }));
|
|
1048
1589
|
try {
|
|
1049
1590
|
let n = document.createElement("a");
|
|
@@ -1055,38 +1596,793 @@ function Ce(e, t, n) {
|
|
|
1055
1596
|
});
|
|
1056
1597
|
}
|
|
1057
1598
|
// src/render-pdf.ts
|
|
1058
|
-
async function
|
|
1059
|
-
let r =
|
|
1060
|
-
A(
|
|
1061
|
-
let { signal:
|
|
1599
|
+
async function Je(e, t, n = !0) {
|
|
1600
|
+
let r = De(t), i = Oe(r, t), a = ae(t.metadata), o = [...t.fonts];
|
|
1601
|
+
A(o);
|
|
1602
|
+
let { signal: s, onWarning: c, onProgress: l, rasterScale: u = 2, fallback: d = "auto", pageBreak: f = "css", repeatTableHeaders: p = !1 } = t, m = Ge(e, s), h = Ke(l, s), g = h.report;
|
|
1062
1603
|
try {
|
|
1063
|
-
await
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1604
|
+
g && await g({
|
|
1605
|
+
stage: "preparing",
|
|
1606
|
+
completed: 0,
|
|
1607
|
+
total: 1
|
|
1608
|
+
}), await m.ready(), g && m.captureBaseline(), g && await g({
|
|
1609
|
+
stage: "preparing",
|
|
1610
|
+
completed: 1,
|
|
1611
|
+
total: 1
|
|
1612
|
+
}), g && await g({
|
|
1613
|
+
stage: "layout",
|
|
1614
|
+
completed: 0,
|
|
1615
|
+
total: 1
|
|
1616
|
+
}), m.assertUnchanged();
|
|
1617
|
+
let t = Ee(e, o, {
|
|
1618
|
+
fallback: d,
|
|
1619
|
+
repeatTableHeaders: p
|
|
1620
|
+
});
|
|
1621
|
+
if (g || m.captureBaseline(), g && await g({
|
|
1622
|
+
stage: "layout",
|
|
1623
|
+
completed: 1,
|
|
1624
|
+
total: 1
|
|
1625
|
+
}), g && await g({
|
|
1626
|
+
stage: "pagination",
|
|
1627
|
+
completed: 0,
|
|
1628
|
+
total: 1
|
|
1629
|
+
}), g && m.assertUnchanged(), t.width > r.width - r.margin.left - r.margin.right) throw new w("SOURCE_OVERFLOW", "Source is wider than the configured page content area. Set the source width explicitly; no implicit scaling is applied.");
|
|
1630
|
+
f === "css" && Object.assign(t, ie(e, t));
|
|
1631
|
+
let l = [], h = Ae(t, i.content.height - i.content.margin.top - i.content.margin.bottom, (e) => l.push(e));
|
|
1632
|
+
g && await g({
|
|
1633
|
+
stage: "pagination",
|
|
1634
|
+
completed: 1,
|
|
1635
|
+
total: 1
|
|
1636
|
+
});
|
|
1637
|
+
let _ = [...t.warnings, ...l];
|
|
1638
|
+
t.operations.some((e) => e.kind === "text") && !_.some((e) => e.code === "TEXT_METRICS_APPROXIMATED") && _.unshift({
|
|
1069
1639
|
code: "TEXT_METRICS_APPROXIMATED",
|
|
1070
1640
|
message: "PDF text uses browser word origins and approximate baseline/kerning metrics; full glyph shaping fidelity is not guaranteed."
|
|
1071
1641
|
});
|
|
1072
|
-
for (let e of
|
|
1073
|
-
|
|
1074
|
-
let
|
|
1075
|
-
rasterScale:
|
|
1642
|
+
for (let e of _) c?.(Object.freeze(e));
|
|
1643
|
+
(c || g) && m.assertUnchanged();
|
|
1644
|
+
let v = await q(We(t, o, r, h, {
|
|
1645
|
+
rasterScale: u,
|
|
1076
1646
|
includeRasterText: n,
|
|
1077
|
-
...
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
...
|
|
1647
|
+
...i.header ? { header: i.header } : {},
|
|
1648
|
+
...i.footer ? { footer: i.footer } : {},
|
|
1649
|
+
...a ? { metadata: a } : {},
|
|
1650
|
+
...g ? { reportProgress: g } : {},
|
|
1651
|
+
...s ? { signal: s } : {}
|
|
1652
|
+
}), s);
|
|
1653
|
+
return m.assertUnchanged(), A(o), T(s), g && (await g({
|
|
1654
|
+
stage: "complete",
|
|
1655
|
+
completed: 1,
|
|
1656
|
+
total: 1
|
|
1657
|
+
}), m.assertUnchanged(), A(o)), {
|
|
1658
|
+
...v,
|
|
1081
1659
|
snapshot: t,
|
|
1082
|
-
warnings:
|
|
1660
|
+
warnings: _
|
|
1083
1661
|
};
|
|
1662
|
+
} catch (e) {
|
|
1663
|
+
return h.rethrow(e);
|
|
1084
1664
|
} finally {
|
|
1085
|
-
|
|
1665
|
+
m.dispose();
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
async function Ye(e, t) {
|
|
1669
|
+
let n = await Je(e, t);
|
|
1670
|
+
return qe(n.bytes, n.slices.length, n.warnings);
|
|
1671
|
+
}
|
|
1672
|
+
// src/image-geometry.ts
|
|
1673
|
+
var Xe = 4e7;
|
|
1674
|
+
function J(e, t) {
|
|
1675
|
+
if (!Number.isSafeInteger(e) || !Number.isSafeInteger(t) || e <= 0 || t <= 0) throw new w("INVALID_SOURCE", "Image dimensions must be positive safe integers.");
|
|
1676
|
+
if (e > 4e7 / t) throw new w("UNSUPPORTED_IMAGE", `Each image frame must contain at most ${Xe} pixels.`);
|
|
1677
|
+
}
|
|
1678
|
+
function Ze(e, t, n, r) {
|
|
1679
|
+
if (J(e, t), !Number.isInteger(n) || n < 1 || n > 8) throw new w("INVALID_SOURCE", "Image orientation must be an integer from 1 through 8.");
|
|
1680
|
+
let i = n >= 5 ? t : e, a = n >= 5 ? e : t, o = r.width - r.margin.left - r.margin.right, s = r.height - r.margin.top - r.margin.bottom, c = Math.min(o / i, s / a), l = i * c, u = a * c, d = r.margin.left + (o - l) / 2, f = r.margin.bottom + (s - u) / 2, [p, m, h, g, _, v] = [
|
|
1681
|
+
[
|
|
1682
|
+
1,
|
|
1683
|
+
0,
|
|
1684
|
+
0,
|
|
1685
|
+
1,
|
|
1686
|
+
0,
|
|
1687
|
+
0
|
|
1688
|
+
],
|
|
1689
|
+
[
|
|
1690
|
+
-1,
|
|
1691
|
+
0,
|
|
1692
|
+
0,
|
|
1693
|
+
1,
|
|
1694
|
+
1,
|
|
1695
|
+
0
|
|
1696
|
+
],
|
|
1697
|
+
[
|
|
1698
|
+
-1,
|
|
1699
|
+
0,
|
|
1700
|
+
0,
|
|
1701
|
+
-1,
|
|
1702
|
+
1,
|
|
1703
|
+
1
|
|
1704
|
+
],
|
|
1705
|
+
[
|
|
1706
|
+
1,
|
|
1707
|
+
0,
|
|
1708
|
+
0,
|
|
1709
|
+
-1,
|
|
1710
|
+
0,
|
|
1711
|
+
1
|
|
1712
|
+
],
|
|
1713
|
+
[
|
|
1714
|
+
0,
|
|
1715
|
+
-1,
|
|
1716
|
+
-1,
|
|
1717
|
+
0,
|
|
1718
|
+
1,
|
|
1719
|
+
1
|
|
1720
|
+
],
|
|
1721
|
+
[
|
|
1722
|
+
0,
|
|
1723
|
+
-1,
|
|
1724
|
+
1,
|
|
1725
|
+
0,
|
|
1726
|
+
0,
|
|
1727
|
+
1
|
|
1728
|
+
],
|
|
1729
|
+
[
|
|
1730
|
+
0,
|
|
1731
|
+
1,
|
|
1732
|
+
1,
|
|
1733
|
+
0,
|
|
1734
|
+
0,
|
|
1735
|
+
0
|
|
1736
|
+
],
|
|
1737
|
+
[
|
|
1738
|
+
0,
|
|
1739
|
+
1,
|
|
1740
|
+
-1,
|
|
1741
|
+
0,
|
|
1742
|
+
1,
|
|
1743
|
+
0
|
|
1744
|
+
]
|
|
1745
|
+
][n - 1];
|
|
1746
|
+
return [
|
|
1747
|
+
p * l,
|
|
1748
|
+
m * u,
|
|
1749
|
+
h * l,
|
|
1750
|
+
g * u,
|
|
1751
|
+
d + _ * l,
|
|
1752
|
+
f + v * u
|
|
1753
|
+
];
|
|
1754
|
+
}
|
|
1755
|
+
// src/image-input.ts
|
|
1756
|
+
function Y(e) {
|
|
1757
|
+
throw new w("INVALID_SOURCE", e);
|
|
1758
|
+
}
|
|
1759
|
+
var Qe = Uint32Array.from({ length: 256 }, (e, t) => {
|
|
1760
|
+
let n = t;
|
|
1761
|
+
for (let e = 0; e < 8; e += 1) n = n >>> 1 ^ (n & 1 ? 3988292384 : 0);
|
|
1762
|
+
return n >>> 0;
|
|
1763
|
+
});
|
|
1764
|
+
function $e(e, t, n) {
|
|
1765
|
+
let r = 4294967295;
|
|
1766
|
+
for (let i = t; i < n; i += 1) r = Qe[(r ^ e[i]) & 255] ^ r >>> 8;
|
|
1767
|
+
return (r ^ 4294967295) >>> 0;
|
|
1768
|
+
}
|
|
1769
|
+
function et(e) {
|
|
1770
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = 8, r = 0, i = 0, a = -1, o = 0, s = 0, c = !1, l = !1, u = 1, d = !1, f = !1, p = 0;
|
|
1771
|
+
for (; n < e.length;) {
|
|
1772
|
+
n + 12 > e.length && Y("PNG contains a truncated chunk header.");
|
|
1773
|
+
let m = t.getUint32(n), h = n + 12 + m;
|
|
1774
|
+
h > e.length && Y("PNG chunk data extends beyond the input.");
|
|
1775
|
+
let g = e.subarray(n + 4, n + 8);
|
|
1776
|
+
g.some((e) => !(e >= 65 && e <= 90 || e >= 97 && e <= 122)) && Y("PNG chunk names must contain four ASCII letters.");
|
|
1777
|
+
let _ = String.fromCharCode(...g);
|
|
1778
|
+
$e(e, n + 4, h - 4) !== t.getUint32(h - 4) && Y(`PNG ${_} chunk checksum is invalid.`), n === 8 && _ !== "IHDR" && Y("PNG must begin with its IHDR chunk.");
|
|
1779
|
+
let v = n + 8;
|
|
1780
|
+
if (_ === "IHDR") (n !== 8 || m !== 13) && Y("PNG requires exactly one 13-byte IHDR chunk."), r = t.getUint32(v), i = t.getUint32(v + 4), J(r, i), o = e[v + 8], a = e[v + 9], {
|
|
1781
|
+
0: [
|
|
1782
|
+
1,
|
|
1783
|
+
2,
|
|
1784
|
+
4,
|
|
1785
|
+
8,
|
|
1786
|
+
16
|
|
1787
|
+
],
|
|
1788
|
+
2: [8, 16],
|
|
1789
|
+
3: [
|
|
1790
|
+
1,
|
|
1791
|
+
2,
|
|
1792
|
+
4,
|
|
1793
|
+
8
|
|
1794
|
+
],
|
|
1795
|
+
4: [8, 16],
|
|
1796
|
+
6: [8, 16]
|
|
1797
|
+
}[a]?.includes(o) || Y("PNG bit depth and color type are incompatible."), (e[v + 10] !== 0 || e[v + 11] !== 0 || e[v + 12] > 1) && Y("PNG compression, filtering or interlace settings are invalid.");
|
|
1798
|
+
else if (_ === "acTL" || _ === "fcTL" || _ === "fdAT") throw new w("UNSUPPORTED_IMAGE", "Animated PNG is unsupported; provide a static PNG or a multipage TIFF.");
|
|
1799
|
+
else if (_ === "PLTE") (s || d || m === 0 || m % 3 != 0 || m > 768 || a === 0 || a === 4) && Y("PNG palette is invalid or appears after image data."), s = m / 3, a === 3 && s > 2 ** o && Y("PNG palette exceeds its indexed bit depth.");
|
|
1800
|
+
else if (_ === "tRNS") (c || d || !(a === 0 && m === 2 || a === 2 && m === 6 || a === 3 && m > 0 && m <= s)) && Y("PNG transparency is incompatible with its color type or palette."), c = !0;
|
|
1801
|
+
else if (_ === "eXIf") l && Y("PNG requires at most one eXIf chunk."), u = X(e, v, h - 4), l = !0;
|
|
1802
|
+
else if (_ === "IDAT") (f || a === 3 && s === 0) && Y("PNG image data must be contiguous and follow its palette."), d = !0, p += m;
|
|
1803
|
+
else if (_ === "IEND") return m === 0 && d && p !== 0 && h === e.length || Y("PNG must end with IEND after nonempty image data."), {
|
|
1804
|
+
format: "png",
|
|
1805
|
+
width: r,
|
|
1806
|
+
height: i,
|
|
1807
|
+
orientation: u
|
|
1808
|
+
};
|
|
1809
|
+
else if (g[0] < 97) throw new w("UNSUPPORTED_IMAGE", `Unsupported critical PNG chunk: ${_}.`);
|
|
1810
|
+
d && _ !== "IDAT" && (f = !0), n = h;
|
|
1811
|
+
}
|
|
1812
|
+
Y("PNG is missing its final IEND chunk.");
|
|
1813
|
+
}
|
|
1814
|
+
function X(e, t, n) {
|
|
1815
|
+
let r = new DataView(e.buffer, e.byteOffset + t, n - t);
|
|
1816
|
+
r.byteLength < 8 && Y("Image EXIF TIFF header is truncated.");
|
|
1817
|
+
let i = r.getUint16(0);
|
|
1818
|
+
i !== 18761 && i !== 19789 && Y("Image EXIF byte order is invalid.");
|
|
1819
|
+
let a = i === 18761;
|
|
1820
|
+
r.getUint16(2, a) !== 42 && Y("Image EXIF requires a classic TIFF header.");
|
|
1821
|
+
let o = r.getUint32(4, a);
|
|
1822
|
+
(o < 8 || o + 2 > r.byteLength) && Y("Image EXIF IFD0 offset is outside its metadata segment.");
|
|
1823
|
+
let s = r.getUint16(o, a), c = o + 2 + s * 12;
|
|
1824
|
+
c + 4 > r.byteLength && Y("Image EXIF directory extends beyond its metadata segment.");
|
|
1825
|
+
let l = 1, u = !1;
|
|
1826
|
+
for (let e = 0; e < s; e += 1) {
|
|
1827
|
+
let t = o + 2 + e * 12;
|
|
1828
|
+
if (r.getUint16(t, a) !== 274) continue;
|
|
1829
|
+
let n = r.getUint16(t + 8, a);
|
|
1830
|
+
(u || r.getUint16(t + 2, a) !== 3 || r.getUint32(t + 4, a) !== 1 || n < 1 || n > 8) && Y("Image EXIF orientation must be one unambiguous SHORT value from 1 to 8."), l = n, u = !0;
|
|
1086
1831
|
}
|
|
1832
|
+
let d = r.getUint32(c, a);
|
|
1833
|
+
return d !== 0 && (d < 8 || d + 2 > r.byteLength) && Y("Image EXIF thumbnail directory is outside its metadata segment."), l;
|
|
1087
1834
|
}
|
|
1088
|
-
|
|
1089
|
-
let
|
|
1090
|
-
|
|
1835
|
+
function tt(e) {
|
|
1836
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = 2, r = 0, i = 0, a = 1, o = !1, s = 0, c = !1, l = /* @__PURE__ */ new Set();
|
|
1837
|
+
for (; n < e.length;) {
|
|
1838
|
+
for (e[n] !== 255 && Y("JPEG marker structure is invalid."), n += 1; e[n] === 255;) n += 1;
|
|
1839
|
+
let u = e[n++];
|
|
1840
|
+
if ((u === void 0 || u === 0 || u === 216) && Y("JPEG contains an invalid or truncated marker."), u === 217) return s && c && n === e.length || Y("JPEG must end after a complete frame and scan."), {
|
|
1841
|
+
format: "jpeg",
|
|
1842
|
+
width: r,
|
|
1843
|
+
height: i,
|
|
1844
|
+
orientation: a
|
|
1845
|
+
};
|
|
1846
|
+
(u === 1 || u >= 208 && u <= 215) && Y("JPEG standalone markers are only supported inside scan data."), n + 2 > e.length && Y("JPEG segment length is truncated.");
|
|
1847
|
+
let d = t.getUint16(n), f = n + d;
|
|
1848
|
+
(d < 2 || f > e.length) && Y("JPEG segment extends beyond the input.");
|
|
1849
|
+
let p = n + 2;
|
|
1850
|
+
if (u >= 192 && u <= 207 && ![
|
|
1851
|
+
196,
|
|
1852
|
+
200,
|
|
1853
|
+
204
|
|
1854
|
+
].includes(u)) {
|
|
1855
|
+
if (![
|
|
1856
|
+
192,
|
|
1857
|
+
193,
|
|
1858
|
+
194
|
|
1859
|
+
].includes(u)) throw new w("UNSUPPORTED_IMAGE", "JPEG requires baseline, extended sequential or progressive Huffman encoding.");
|
|
1860
|
+
(s || d < 8) && Y("JPEG contains an invalid or duplicate frame header.");
|
|
1861
|
+
let n = e[p + 5];
|
|
1862
|
+
if (d !== 8 + n * 3 && Y("JPEG frame components are truncated."), e[p] !== 8 || ![
|
|
1863
|
+
1,
|
|
1864
|
+
3,
|
|
1865
|
+
4
|
|
1866
|
+
].includes(n)) throw new w("UNSUPPORTED_IMAGE", "JPEG requires 8-bit grayscale, RGB or CMYK pixels.");
|
|
1867
|
+
i = t.getUint16(p + 1), r = t.getUint16(p + 3), J(r, i);
|
|
1868
|
+
for (let t = 0; t < n; t += 1) {
|
|
1869
|
+
let n = p + 6 + t * 3, r = e[n], i = e[n + 1];
|
|
1870
|
+
(l.has(r) || !(i >> 4) || i >> 4 > 4 || !(i & 15) || (i & 15) > 4 || e[n + 2] > 3) && Y("JPEG frame component identifiers or sampling settings are invalid."), l.add(r);
|
|
1871
|
+
}
|
|
1872
|
+
s = u;
|
|
1873
|
+
} else if (u === 225 && d >= 6 && e[p] === 69 && e[p + 1] === 120 && e[p + 2] === 105 && e[p + 3] === 102) (o || d < 8 || e[p + 4] !== 0 || e[p + 5] !== 0) && Y("JPEG contains ambiguous or malformed EXIF APP1 metadata."), a = X(e, p + 6, f), o = !0;
|
|
1874
|
+
else if (u === 218) {
|
|
1875
|
+
let t = e[p];
|
|
1876
|
+
(!s || t === void 0 || t < 1 || t > l.size || d !== 6 + t * 2) && Y("JPEG scan header must follow a complete frame and select its components.");
|
|
1877
|
+
let r = /* @__PURE__ */ new Set();
|
|
1878
|
+
for (let n = 0; n < t; n += 1) {
|
|
1879
|
+
let t = e[p + 1 + n * 2], i = e[p + 2 + n * 2];
|
|
1880
|
+
(!l.has(t) || r.has(t) || i >> 4 > 3 || (i & 15) > 3) && Y("JPEG scan components or Huffman table selectors are invalid."), r.add(t);
|
|
1881
|
+
}
|
|
1882
|
+
let i = p + 1 + t * 2;
|
|
1883
|
+
(e[i] > e[i + 1] || e[i + 1] > 63 || e[i + 2] >> 4 > 13 || (e[i + 2] & 15) > 13 || s !== 194 && (e[i] !== 0 || e[i + 1] !== 63 || e[i + 2] !== 0)) && Y("JPEG scan spectral settings are invalid."), c = !0, n = f;
|
|
1884
|
+
let a = 0;
|
|
1885
|
+
for (; n < e.length;) {
|
|
1886
|
+
if (e[n] !== 255) {
|
|
1887
|
+
a += 1, n += 1;
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
let t = n;
|
|
1891
|
+
for (n += 1; e[n] === 255;) n += 1;
|
|
1892
|
+
let r = e[n];
|
|
1893
|
+
if (r === 0 || r !== void 0 && r >= 208 && r <= 215) r === 0 && (a += 1), n += 1;
|
|
1894
|
+
else {
|
|
1895
|
+
n = t;
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
a === 0 && Y("JPEG scan data is empty or truncated.");
|
|
1900
|
+
continue;
|
|
1901
|
+
} else if ([
|
|
1902
|
+
220,
|
|
1903
|
+
222,
|
|
1904
|
+
223
|
|
1905
|
+
].includes(u)) throw new w("UNSUPPORTED_IMAGE", "JPEG deferred-height and hierarchical frames are unsupported.");
|
|
1906
|
+
n = f;
|
|
1907
|
+
}
|
|
1908
|
+
Y("JPEG is missing its final EOI marker.");
|
|
1909
|
+
}
|
|
1910
|
+
function nt(e) {
|
|
1911
|
+
if (e.length >= 8 && [
|
|
1912
|
+
137,
|
|
1913
|
+
80,
|
|
1914
|
+
78,
|
|
1915
|
+
71,
|
|
1916
|
+
13,
|
|
1917
|
+
10,
|
|
1918
|
+
26,
|
|
1919
|
+
10
|
|
1920
|
+
].every((t, n) => e[n] === t)) return et(e);
|
|
1921
|
+
if (e[0] === 255 && e[1] === 216) return tt(e);
|
|
1922
|
+
throw new w("UNSUPPORTED_IMAGE", "Provide PNG, JPEG or classic TIFF image bytes.");
|
|
1923
|
+
}
|
|
1924
|
+
async function rt(e, t) {
|
|
1925
|
+
T(t);
|
|
1926
|
+
let n = e.buffer instanceof ArrayBuffer ? new Uint8Array(e.buffer, e.byteOffset, e.byteLength) : Uint8Array.from(e), r = nt(n);
|
|
1927
|
+
if (r.format !== "png" && Y("PNG data validation requires PNG bytes."), typeof DecompressionStream != "function") throw new w("UNSUPPORTED_IMAGE", "PNG validation requires DecompressionStream support.");
|
|
1928
|
+
let i = {
|
|
1929
|
+
0: 1,
|
|
1930
|
+
2: 3,
|
|
1931
|
+
3: 1,
|
|
1932
|
+
4: 2,
|
|
1933
|
+
6: 4
|
|
1934
|
+
}[n[25]] * n[24], a = (n[28] === 0 ? [[
|
|
1935
|
+
0,
|
|
1936
|
+
0,
|
|
1937
|
+
1,
|
|
1938
|
+
1
|
|
1939
|
+
]] : [
|
|
1940
|
+
[
|
|
1941
|
+
0,
|
|
1942
|
+
0,
|
|
1943
|
+
8,
|
|
1944
|
+
8
|
|
1945
|
+
],
|
|
1946
|
+
[
|
|
1947
|
+
4,
|
|
1948
|
+
0,
|
|
1949
|
+
8,
|
|
1950
|
+
8
|
|
1951
|
+
],
|
|
1952
|
+
[
|
|
1953
|
+
0,
|
|
1954
|
+
4,
|
|
1955
|
+
4,
|
|
1956
|
+
8
|
|
1957
|
+
],
|
|
1958
|
+
[
|
|
1959
|
+
2,
|
|
1960
|
+
0,
|
|
1961
|
+
4,
|
|
1962
|
+
4
|
|
1963
|
+
],
|
|
1964
|
+
[
|
|
1965
|
+
0,
|
|
1966
|
+
2,
|
|
1967
|
+
2,
|
|
1968
|
+
4
|
|
1969
|
+
],
|
|
1970
|
+
[
|
|
1971
|
+
1,
|
|
1972
|
+
0,
|
|
1973
|
+
2,
|
|
1974
|
+
2
|
|
1975
|
+
],
|
|
1976
|
+
[
|
|
1977
|
+
0,
|
|
1978
|
+
1,
|
|
1979
|
+
1,
|
|
1980
|
+
2
|
|
1981
|
+
]
|
|
1982
|
+
]).flatMap(([e = 0, t = 0, n = 1, a = 1]) => {
|
|
1983
|
+
let o = Math.max(0, Math.ceil((r.width - e) / n)), s = Math.max(0, Math.ceil((r.height - t) / a));
|
|
1984
|
+
return o && s ? [{
|
|
1985
|
+
rows: s,
|
|
1986
|
+
stride: Math.ceil(o * i / 8) + 1
|
|
1987
|
+
}] : [];
|
|
1988
|
+
}), o = a.reduce((e, t) => e + t.rows * t.stride, 0), s = new DataView(n.buffer, n.byteOffset, n.byteLength), c = 8, l = 0, u = 0, d = new ReadableStream({ pull(e) {
|
|
1989
|
+
for (; l === u && c < n.length;) {
|
|
1990
|
+
let e = s.getUint32(c), t = c + 8, r = n[c + 4] === 73 && n[c + 5] === 68 && n[c + 6] === 65 && n[c + 7] === 84;
|
|
1991
|
+
c += e + 12, r && e > 0 && (l = t, u = t + e);
|
|
1992
|
+
}
|
|
1993
|
+
if (l === u) {
|
|
1994
|
+
e.close();
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
let t = Math.min(l + 8192, u);
|
|
1998
|
+
e.enqueue(n.subarray(l, t)), l = t;
|
|
1999
|
+
} }).pipeThrough(new DecompressionStream("deflate")).getReader(), f = () => {
|
|
2000
|
+
d.cancel().catch(() => {});
|
|
2001
|
+
};
|
|
2002
|
+
t?.addEventListener("abort", f, { once: !0 });
|
|
2003
|
+
let p = !1, m = 0, h = 0, g = a[0]?.rows ?? 0, _ = 0;
|
|
2004
|
+
try {
|
|
2005
|
+
for (;;) {
|
|
2006
|
+
T(t);
|
|
2007
|
+
let e = await d.read();
|
|
2008
|
+
if (T(t), e.done) break;
|
|
2009
|
+
m += e.value.length, m > o && Y("PNG decompressed data exceeds its declared scanline dimensions.");
|
|
2010
|
+
let n = 0;
|
|
2011
|
+
for (; n < e.value.length;) {
|
|
2012
|
+
let t = a[h];
|
|
2013
|
+
t || Y("PNG decompressed data contains unexpected image rows."), _ === 0 && (e.value[n] > 4 && Y("PNG scanline filter must be between zero and four."), n += 1, _ = 1);
|
|
2014
|
+
let r = Math.min(e.value.length - n, t.stride - _);
|
|
2015
|
+
n += r, _ += r, _ === t.stride && (_ = 0, --g, g === 0 && (h += 1, g = a[h]?.rows ?? 0));
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
(m !== o || h !== a.length || _ !== 0) && Y("PNG decompressed data is shorter than its declared scanline dimensions."), p = !0;
|
|
2019
|
+
} catch (e) {
|
|
2020
|
+
throw T(t), e instanceof w ? e : new w("INVALID_SOURCE", "PNG compressed data or zlib checksum is invalid.", { cause: e });
|
|
2021
|
+
} finally {
|
|
2022
|
+
t?.removeEventListener("abort", f), p || await d.cancel().catch(() => {}), d.releaseLock();
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
// src/tiff.ts
|
|
2026
|
+
var it = 1e3, at = [
|
|
2027
|
+
0,
|
|
2028
|
+
1,
|
|
2029
|
+
1,
|
|
2030
|
+
2,
|
|
2031
|
+
4,
|
|
2032
|
+
8,
|
|
2033
|
+
1,
|
|
2034
|
+
1,
|
|
2035
|
+
2,
|
|
2036
|
+
4,
|
|
2037
|
+
8,
|
|
2038
|
+
4,
|
|
2039
|
+
8,
|
|
2040
|
+
4
|
|
2041
|
+
], ot = /* @__PURE__ */ new Set([
|
|
2042
|
+
256,
|
|
2043
|
+
257,
|
|
2044
|
+
258,
|
|
2045
|
+
259,
|
|
2046
|
+
262,
|
|
2047
|
+
266,
|
|
2048
|
+
273,
|
|
2049
|
+
274,
|
|
2050
|
+
277,
|
|
2051
|
+
278,
|
|
2052
|
+
279,
|
|
2053
|
+
284,
|
|
2054
|
+
292,
|
|
2055
|
+
293,
|
|
2056
|
+
317,
|
|
2057
|
+
320,
|
|
2058
|
+
322,
|
|
2059
|
+
323,
|
|
2060
|
+
324,
|
|
2061
|
+
325,
|
|
2062
|
+
330,
|
|
2063
|
+
338,
|
|
2064
|
+
339
|
|
2065
|
+
]);
|
|
2066
|
+
function Z(e) {
|
|
2067
|
+
throw new w("INVALID_SOURCE", `Invalid TIFF: ${e}`);
|
|
2068
|
+
}
|
|
2069
|
+
function Q(e) {
|
|
2070
|
+
throw new w("UNSUPPORTED_IMAGE", `Unsupported TIFF: ${e}`);
|
|
2071
|
+
}
|
|
2072
|
+
function $(e, t, n) {
|
|
2073
|
+
let r = e[`t${t}`];
|
|
2074
|
+
return !r && n !== void 0 ? n : (r && r.length === 1 && Number.isSafeInteger(r[0]) || Z(`tag ${t} requires one integer value.`), r[0]);
|
|
2075
|
+
}
|
|
2076
|
+
function st(e, t) {
|
|
2077
|
+
let n = $(e, 256), r = $(e, 257);
|
|
2078
|
+
J(n, r);
|
|
2079
|
+
let i = $(e, 274, 1);
|
|
2080
|
+
(i < 1 || i > 8) && Z("orientation must be between 1 and 8.");
|
|
2081
|
+
let a = $(e, 259, 1);
|
|
2082
|
+
[
|
|
2083
|
+
1,
|
|
2084
|
+
2,
|
|
2085
|
+
3,
|
|
2086
|
+
4,
|
|
2087
|
+
5,
|
|
2088
|
+
8,
|
|
2089
|
+
32946,
|
|
2090
|
+
32773
|
|
2091
|
+
].includes(a) || Q(`compression ${a}; use uncompressed, CCITT, LZW, Deflate or PackBits strips.`), [
|
|
2092
|
+
322,
|
|
2093
|
+
323,
|
|
2094
|
+
324,
|
|
2095
|
+
325,
|
|
2096
|
+
330
|
|
2097
|
+
].some((t) => e[`t${t}`]) && Q("tiled images and SubIFDs are not supported."), $(e, 284, 1) !== 1 && Q("separate planar samples are not supported.");
|
|
2098
|
+
let o = $(e, 277, 1), s = e.t258 ?? [1], c = s[0], l = e.t339 ?? [1];
|
|
2099
|
+
(![1, o].includes(s.length) || s.some((e) => e !== c) || ![1, o].includes(l.length) || l.some((e) => e !== 1)) && Q("sample depths must match and samples must be unsigned integers.");
|
|
2100
|
+
let u = $(e, 262), d = o === 1 && (u === 0 && [
|
|
2101
|
+
1,
|
|
2102
|
+
4,
|
|
2103
|
+
8
|
|
2104
|
+
].includes(c) || u === 1 && [
|
|
2105
|
+
1,
|
|
2106
|
+
2,
|
|
2107
|
+
8
|
|
2108
|
+
].includes(c)), f = u === 2 && c === 8 && [3, 4].includes(o), p = u === 3 && o === 1 && [
|
|
2109
|
+
1,
|
|
2110
|
+
2,
|
|
2111
|
+
4,
|
|
2112
|
+
8
|
|
2113
|
+
].includes(c);
|
|
2114
|
+
d || f || p || Q("photometric interpretation, channels or bit depth.");
|
|
2115
|
+
let m = e.t338 ?? [];
|
|
2116
|
+
o !== 4 || m.length === 1 && [1, 2].includes(m[0]) || Q("four-channel RGB requires an explicit associated or unassociated alpha sample."), o !== 4 && m.length > 0 && Q("extra samples are unsupported in this pixel mode."), p && e.t320?.length !== 3 * (1 << c) && Z("the palette has an invalid size."), p && e.t320.some((e) => e > 65535) && Z("palette entries must be sixteen-bit values.");
|
|
2117
|
+
let h = $(e, 266, 1), g = [
|
|
2118
|
+
2,
|
|
2119
|
+
3,
|
|
2120
|
+
4
|
|
2121
|
+
].includes(a);
|
|
2122
|
+
[1, 2].includes(h) || Z("fill order must be 1 or 2."), h === 2 && !g && Q("reversed fill order is supported only for CCITT scans."), g && (!d || c !== 1 || o !== 1) && Q("CCITT compression requires bilevel grayscale."), a === 3 && ![0, 1].includes($(e, 292, 0)) && Q("unsupported Group 3 options."), a === 4 && $(e, 293, 0) !== 0 && Q("uncompressed Group 4 extension mode.");
|
|
2123
|
+
let _ = $(e, 317, 1);
|
|
2124
|
+
_ !== 1 && !(_ === 2 && c === 8 && [
|
|
2125
|
+
1,
|
|
2126
|
+
5,
|
|
2127
|
+
8,
|
|
2128
|
+
32946,
|
|
2129
|
+
32773
|
|
2130
|
+
].includes(a)) && Q("only normal and eight-bit horizontal differencing predictors are supported.");
|
|
2131
|
+
let v = Math.min($(e, 278, r), r);
|
|
2132
|
+
v <= 0 && Z("RowsPerStrip must be positive.");
|
|
2133
|
+
let y = e.t273, b = e.t279;
|
|
2134
|
+
y && b && y.length === b.length && y.length === Math.ceil(r / v) || Z("strip offsets and byte counts must cover exactly the declared rows.");
|
|
2135
|
+
for (let e = 0; e < y.length; e += 1) {
|
|
2136
|
+
let n = y[e], r = b[e];
|
|
2137
|
+
(n < 8 || r <= 0 || n > t - r) && Z("a strip extends outside the input.");
|
|
2138
|
+
}
|
|
2139
|
+
return {
|
|
2140
|
+
tags: e,
|
|
2141
|
+
width: n,
|
|
2142
|
+
height: r,
|
|
2143
|
+
orientation: i,
|
|
2144
|
+
bits: c,
|
|
2145
|
+
samples: o,
|
|
2146
|
+
compression: a,
|
|
2147
|
+
rowsPerStrip: v,
|
|
2148
|
+
offsets: y,
|
|
2149
|
+
counts: b,
|
|
2150
|
+
associatedAlpha: o === 4 && m[0] === 1
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
function ct(e) {
|
|
2154
|
+
e.byteLength < 8 && Z("the header is truncated.");
|
|
2155
|
+
let t = e[0] === 73 && e[1] === 73;
|
|
2156
|
+
t || e[0] === 77 && e[1] === 77 || Z("byte order must be II or MM.");
|
|
2157
|
+
let n = new DataView(e.buffer, e.byteOffset, e.byteLength), r = n.getUint16(2, t);
|
|
2158
|
+
r === 43 && Q("BigTIFF is not supported."), r !== 42 && Z("the classic TIFF signature is missing.");
|
|
2159
|
+
let i = n.getUint32(4, t), a = /* @__PURE__ */ new Set(), o = [];
|
|
2160
|
+
for (; i !== 0;) {
|
|
2161
|
+
a.has(i) && Z("the main IFD chain contains a cycle."), o.length >= it && Q("the file exceeds the 1000 frame limit."), a.add(i), (i < 8 || i > e.length - 2) && Z("an IFD offset is outside the input.");
|
|
2162
|
+
let r = n.getUint16(i, t), s = i + 2 + r * 12;
|
|
2163
|
+
s > e.length - 4 && Z("an IFD directory is truncated.");
|
|
2164
|
+
let c = {};
|
|
2165
|
+
for (let a = 0; a < r; a += 1) {
|
|
2166
|
+
let r = i + 2 + a * 12, o = n.getUint16(r, t), s = n.getUint16(r + 2, t), l = n.getUint32(r + 4, t), u = at[s];
|
|
2167
|
+
u && l !== 0 || Z("an IFD field has an invalid type or count.");
|
|
2168
|
+
let d = u * l, f = d <= 4 ? r + 8 : n.getUint32(r + 8, t);
|
|
2169
|
+
if (f > e.length - d && Z("an IFD value extends outside the input."), !ot.has(o)) continue;
|
|
2170
|
+
[3, 4].includes(s) || Q(`rendering tag ${o} must use SHORT or LONG values.`), c[`t${o}`] && Z(`rendering tag ${o} occurs more than once.`), l > 1e6 && Q("a rendering tag contains too many values.");
|
|
2171
|
+
let p = [];
|
|
2172
|
+
for (let e = 0; e < l; e += 1) p.push(s === 3 ? n.getUint16(f + e * 2, t) : n.getUint32(f + e * 4, t));
|
|
2173
|
+
c[`t${o}`] = p;
|
|
2174
|
+
}
|
|
2175
|
+
o.push(st(c, e.length)), i = n.getUint32(s, t);
|
|
2176
|
+
}
|
|
2177
|
+
return o.length === 0 && Z("no main image IFD exists."), o;
|
|
2178
|
+
}
|
|
2179
|
+
function lt(e, t) {
|
|
2180
|
+
let n = 0, r = 0;
|
|
2181
|
+
for (; n < e.length;) {
|
|
2182
|
+
let i = e[n++];
|
|
2183
|
+
if (i <= 127) {
|
|
2184
|
+
let t = i + 1;
|
|
2185
|
+
n + t > e.length && Z("a PackBits literal is truncated."), n += t, r += t;
|
|
2186
|
+
} else i !== 128 && (n >= e.length && Z("a PackBits repeat is truncated."), n += 1, r += 257 - i);
|
|
2187
|
+
r > t && Z("PackBits output exceeds the declared strip size.");
|
|
2188
|
+
}
|
|
2189
|
+
r !== t && Z("PackBits output does not cover the declared strip.");
|
|
2190
|
+
}
|
|
2191
|
+
function ut(e, t) {
|
|
2192
|
+
let n = /* @__PURE__ */ new Uint32Array(4096);
|
|
2193
|
+
for (let e = 0; e < 256; e += 1) n[e] = 1;
|
|
2194
|
+
let r = 0, i = 9, a = 258, o = 0, s = 0, c = !1;
|
|
2195
|
+
for (; r + i <= e.length * 8;) {
|
|
2196
|
+
let l = 0;
|
|
2197
|
+
for (let t = 0; t < i; t += 1) l = l << 1 | e[r >>> 3] >>> 7 - (r & 7) & 1, r += 1;
|
|
2198
|
+
if (l === 256) {
|
|
2199
|
+
i = 9, a = 258, o = 0, c = !0;
|
|
2200
|
+
continue;
|
|
2201
|
+
}
|
|
2202
|
+
if (c || Z("an LZW strip must start with its clear code."), l === 257) {
|
|
2203
|
+
s !== t && Z("LZW output does not cover the declared strip.");
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
let u = l < a ? n[l] : l === a && o > 0 ? o + 1 : 0;
|
|
2207
|
+
u || Z("an LZW strip contains an invalid dictionary reference."), s += u, s > t && Z("LZW output exceeds the declared strip size."), o > 0 && a < 4096 && (n[a++] = o + 1, i < 12 && a === (1 << i) - 1 && (i += 1)), o = u;
|
|
2208
|
+
}
|
|
2209
|
+
Z("an LZW strip is missing its end code.");
|
|
2210
|
+
}
|
|
2211
|
+
async function dt(e, t, n) {
|
|
2212
|
+
typeof DecompressionStream != "function" && Q("Deflate requires DecompressionStream support.");
|
|
2213
|
+
let r = new Blob([Uint8Array.from(e)]).stream().pipeThrough(new DecompressionStream("deflate")).getReader(), i = 0;
|
|
2214
|
+
try {
|
|
2215
|
+
for (;;) {
|
|
2216
|
+
T(n);
|
|
2217
|
+
let { value: e, done: a } = await r.read();
|
|
2218
|
+
if (a) break;
|
|
2219
|
+
i += e.byteLength, i > t && Z("Deflate output exceeds the declared strip size.");
|
|
2220
|
+
}
|
|
2221
|
+
i !== t && Z("Deflate output does not cover the declared strip.");
|
|
2222
|
+
} catch (e) {
|
|
2223
|
+
throw await r.cancel().catch(() => void 0), T(n), e instanceof w ? e : new w("INVALID_SOURCE", "Invalid TIFF: a Deflate strip is corrupt or truncated.", { cause: e });
|
|
2224
|
+
} finally {
|
|
2225
|
+
r.releaseLock();
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
async function ft(e, t) {
|
|
2229
|
+
T(t);
|
|
2230
|
+
let n = Uint8Array.from(e), r = ct(n);
|
|
2231
|
+
return T(t), {
|
|
2232
|
+
pageCount: r.length,
|
|
2233
|
+
async decodeFrame(e) {
|
|
2234
|
+
T(t), (!Number.isSafeInteger(e) || e < 0 || e >= r.length) && Z("frame index is outside the document.");
|
|
2235
|
+
let i = r[e], a = Math.ceil(i.width * i.samples * i.bits / 8);
|
|
2236
|
+
for (let e = 0; e < i.offsets.length; e += 1) {
|
|
2237
|
+
let r = Math.min(i.rowsPerStrip, i.height - e * i.rowsPerStrip) * a, o = i.offsets[e], s = i.counts[e];
|
|
2238
|
+
i.compression === 1 && s !== r && Z("an uncompressed strip has the wrong byte length."), i.compression === 5 && ut(n.subarray(o, o + s), r), i.compression === 32773 && lt(n.subarray(o, o + s), r), [8, 32946].includes(i.compression) && await dt(n.subarray(o, o + s), r, t);
|
|
2239
|
+
}
|
|
2240
|
+
let o = Object.fromEntries(Object.entries(i.tags).map(([e, t]) => [e, [...t]])), s;
|
|
2241
|
+
try {
|
|
2242
|
+
let e = (await import("utif2")).default;
|
|
2243
|
+
T(t), e.decodeImage(n.buffer, o), o.data instanceof Uint8Array && o.data.length === a * i.height || Z("the decoder returned an incomplete raster."), s = e.toRGBA8(o);
|
|
2244
|
+
} catch (e) {
|
|
2245
|
+
throw T(t), e instanceof w ? e : new w("RESOURCE_LOAD_FAILED", "The TIFF frame could not be decoded.", { cause: e });
|
|
2246
|
+
}
|
|
2247
|
+
if (s.length !== i.width * i.height * 4 && Z("the decoder returned an invalid RGBA raster."), i.associatedAlpha) for (let e = 0; e < s.length; e += 4) {
|
|
2248
|
+
let t = s[e + 3];
|
|
2249
|
+
for (let n = 0; n < 3; n += 1) s[e + n] = t === 0 ? 0 : Math.min(255, Math.round(s[e + n] * 255 / t));
|
|
2250
|
+
}
|
|
2251
|
+
return T(t), {
|
|
2252
|
+
width: i.width,
|
|
2253
|
+
height: i.height,
|
|
2254
|
+
rgba: s,
|
|
2255
|
+
orientation: i.orientation
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
// src/image-pdf.ts
|
|
2261
|
+
function pt(e, t) {
|
|
2262
|
+
let { width: n, height: r, rgba: i, orientation: a } = t;
|
|
2263
|
+
J(n, r);
|
|
2264
|
+
let o = n * r;
|
|
2265
|
+
if (i.length !== o * 4) throw new w("RESOURCE_LOAD_FAILED", "Decoded TIFF pixels do not match the frame dimensions.");
|
|
2266
|
+
let s = new Uint8Array(o * 3), c;
|
|
2267
|
+
for (let e = 0; e < o; e += 1) {
|
|
2268
|
+
s[e * 3] = i[e * 4], s[e * 3 + 1] = i[e * 4 + 1], s[e * 3 + 2] = i[e * 4 + 2];
|
|
2269
|
+
let t = i[e * 4 + 3];
|
|
2270
|
+
t !== 255 && !c && (c = new Uint8Array(o).fill(255)), c && (c[e] = t);
|
|
2271
|
+
}
|
|
2272
|
+
let l = c ? e.context.register(e.context.flateStream(c, {
|
|
2273
|
+
Type: "XObject",
|
|
2274
|
+
Subtype: "Image",
|
|
2275
|
+
Width: n,
|
|
2276
|
+
Height: r,
|
|
2277
|
+
ColorSpace: "DeviceGray",
|
|
2278
|
+
BitsPerComponent: 8
|
|
2279
|
+
})) : void 0;
|
|
2280
|
+
return {
|
|
2281
|
+
ref: e.context.register(e.context.flateStream(s, {
|
|
2282
|
+
Type: "XObject",
|
|
2283
|
+
Subtype: "Image",
|
|
2284
|
+
Width: n,
|
|
2285
|
+
Height: r,
|
|
2286
|
+
ColorSpace: "DeviceRGB",
|
|
2287
|
+
BitsPerComponent: 8,
|
|
2288
|
+
...l ? { SMask: l } : {}
|
|
2289
|
+
})),
|
|
2290
|
+
width: n,
|
|
2291
|
+
height: r,
|
|
2292
|
+
orientation: a
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
async function mt(e, t) {
|
|
2296
|
+
try {
|
|
2297
|
+
return new Uint8Array(await q(e.arrayBuffer(), t));
|
|
2298
|
+
} catch (e) {
|
|
2299
|
+
throw T(t), new w("RESOURCE_LOAD_FAILED", "The source image file could not be read.", { cause: e });
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
async function ht(e, t = {}) {
|
|
2303
|
+
let n = L(t), i = ae(t.metadata), { signal: a, onProgress: o } = t;
|
|
2304
|
+
if (o !== void 0 && typeof o != "function") throw new w("INVALID_OPTIONS", "onProgress must be a function.");
|
|
2305
|
+
if (a !== void 0 && !(a instanceof AbortSignal)) throw new w("INVALID_OPTIONS", "signal must be an AbortSignal.");
|
|
2306
|
+
T(a);
|
|
2307
|
+
let s = e instanceof Uint8Array ? Uint8Array.from(e) : e instanceof ArrayBuffer ? new Uint8Array(e.slice(0)) : void 0, c = typeof Blob < "u" && e instanceof Blob ? e : void 0;
|
|
2308
|
+
if (!s && !c) throw new w("INVALID_SOURCE", "Provide image bytes, an ArrayBuffer, or a File/Blob.");
|
|
2309
|
+
let d = Ke(o, a), f = d.report;
|
|
2310
|
+
try {
|
|
2311
|
+
f && await f({
|
|
2312
|
+
stage: "preparing",
|
|
2313
|
+
completed: 0,
|
|
2314
|
+
total: 1
|
|
2315
|
+
});
|
|
2316
|
+
let e = s ?? await mt(c, a);
|
|
2317
|
+
if (e.length === 0) throw new w("INVALID_SOURCE", "The source image is empty.");
|
|
2318
|
+
let t = e.length >= 4 && (e[0] === 73 && e[1] === 73 && (e[2] === 42 || e[2] === 43) && e[3] === 0 || e[0] === 77 && e[1] === 77 && e[2] === 0 && (e[3] === 42 || e[3] === 43)) ? await q(ft(e, a), a) : void 0, o = t ? void 0 : nt(e), d = t?.pageCount ?? 1;
|
|
2319
|
+
f && await f({
|
|
2320
|
+
stage: "preparing",
|
|
2321
|
+
completed: 1,
|
|
2322
|
+
total: 1
|
|
2323
|
+
});
|
|
2324
|
+
let h = await r.create();
|
|
2325
|
+
oe(h, i);
|
|
2326
|
+
let g = [];
|
|
2327
|
+
f && await f({
|
|
2328
|
+
stage: "resources",
|
|
2329
|
+
completed: 0,
|
|
2330
|
+
total: d
|
|
2331
|
+
});
|
|
2332
|
+
for (let n = 0; n < d; n += 1) {
|
|
2333
|
+
if (T(a), t) {
|
|
2334
|
+
let e = await q(t.decodeFrame(n), a);
|
|
2335
|
+
g.push(pt(h, e));
|
|
2336
|
+
} else try {
|
|
2337
|
+
o.format === "png" && await rt(e, a);
|
|
2338
|
+
let t = o.format === "png" ? await h.embedPng(e) : await h.embedJpg(e);
|
|
2339
|
+
if (t.width !== o.width || t.height !== o.height) throw new w("INVALID_SOURCE", "Decoded image dimensions disagree with its header.");
|
|
2340
|
+
g.push({
|
|
2341
|
+
ref: t.ref,
|
|
2342
|
+
width: t.width,
|
|
2343
|
+
height: t.height,
|
|
2344
|
+
orientation: o.orientation
|
|
2345
|
+
});
|
|
2346
|
+
} catch (e) {
|
|
2347
|
+
throw e instanceof w ? e : new w("RESOURCE_LOAD_FAILED", "The PNG/JPEG image could not be embedded.", { cause: e });
|
|
2348
|
+
}
|
|
2349
|
+
f && await f({
|
|
2350
|
+
stage: "resources",
|
|
2351
|
+
completed: n + 1,
|
|
2352
|
+
total: d
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
f && await f({
|
|
2356
|
+
stage: "pages",
|
|
2357
|
+
completed: 0,
|
|
2358
|
+
total: d
|
|
2359
|
+
});
|
|
2360
|
+
for (let [e, t] of g.entries()) {
|
|
2361
|
+
T(a);
|
|
2362
|
+
let r = h.addPage([n.width * .75, n.height * .75]), i = Ze(t.width, t.height, t.orientation, n), o = r.node.newXObject("Image", t.ref);
|
|
2363
|
+
r.pushOperators(m(), l(i[0] * .75, i[1] * .75, i[2] * .75, i[3] * .75, i[4] * .75, i[5] * .75), u(o), p()), f && await f({
|
|
2364
|
+
stage: "pages",
|
|
2365
|
+
completed: e + 1,
|
|
2366
|
+
total: d
|
|
2367
|
+
});
|
|
2368
|
+
}
|
|
2369
|
+
f && await f({
|
|
2370
|
+
stage: "saving",
|
|
2371
|
+
completed: 0,
|
|
2372
|
+
total: 1
|
|
2373
|
+
});
|
|
2374
|
+
let _ = await q(h.save(), a);
|
|
2375
|
+
return T(a), f && await f({
|
|
2376
|
+
stage: "saving",
|
|
2377
|
+
completed: 1,
|
|
2378
|
+
total: 1
|
|
2379
|
+
}), f && await f({
|
|
2380
|
+
stage: "complete",
|
|
2381
|
+
completed: 1,
|
|
2382
|
+
total: 1
|
|
2383
|
+
}), T(a), qe(_, d, []);
|
|
2384
|
+
} catch (e) {
|
|
2385
|
+
return d.rethrow(e instanceof w ? e : new w("PDF_WRITE_FAILED", "The standalone image could not be written as PDF.", { cause: e }));
|
|
2386
|
+
}
|
|
1091
2387
|
}
|
|
1092
|
-
export {
|
|
2388
|
+
export { w as RenderPDFError, ht as imageToPDF, de as registerFont, Ye as renderPDF };
|