@reportwright/viewer 0.12.1 → 0.13.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/CHANGELOG.md +78 -0
- package/README.md +16 -1
- package/THIRD-PARTY-NOTICES.md +52 -0
- package/dist/{chunk-S2IUUI6N.js → chunk-BF7GCWZY.js} +67 -49
- package/dist/chunk-BF7GCWZY.js.map +6 -0
- package/dist/chunk-BR5K6SBL.js +324 -0
- package/dist/chunk-BR5K6SBL.js.map +6 -0
- package/dist/{peer/chunk-BQFI3DHK.js → chunk-CNDUJ7IV.js} +289 -25
- package/dist/chunk-CNDUJ7IV.js.map +6 -0
- package/dist/{chunk-VNOWPSE6.js → chunk-EK5CJY22.js} +1223 -899
- package/dist/chunk-EK5CJY22.js.map +6 -0
- package/dist/{chunk-2BPBQMH2.js → chunk-F5EPQTPF.js} +3 -3
- package/dist/chunk-FEM2QVOO.js +18 -0
- package/dist/{chunk-3D2KFKG2.js → chunk-IFYCJZNS.js} +8 -6
- package/dist/chunk-IFYCJZNS.js.map +6 -0
- package/dist/{chunk-NR2G4TMG.js → chunk-L6YEIVVD.js} +43 -22
- package/dist/chunk-L6YEIVVD.js.map +6 -0
- package/dist/{chunk-DPVJEFKP.js → chunk-PQNM6ET7.js} +4 -4
- package/dist/{chunk-DPVJEFKP.js.map → chunk-PQNM6ET7.js.map} +1 -1
- package/dist/{chunk-Z7MKH66Z.js → chunk-QFLVVM3H.js} +225 -11
- package/dist/chunk-QFLVVM3H.js.map +6 -0
- package/dist/{chunk-PGP3QA6L.js → chunk-TZXEEVKE.js} +1301 -70
- package/dist/chunk-TZXEEVKE.js.map +6 -0
- package/dist/{chunk-Q6MMPKQA.js → chunk-UHHURTSV.js} +11 -10
- package/dist/chunk-UHHURTSV.js.map +6 -0
- package/dist/{chunk-M6AYND5G.js → chunk-UJL7C2AS.js} +16 -7
- package/dist/chunk-UJL7C2AS.js.map +6 -0
- package/dist/chunk-YIX3OJXU.js +34 -0
- package/dist/designer.d.ts +11 -3
- package/dist/designer.js +587 -386
- package/dist/designer.js.map +3 -3
- package/dist/engine.worker.js +16729 -18
- package/dist/engine.worker.js.map +3 -3
- package/dist/peer/{chunk-6I2EAAVN.js → chunk-2CD5COHN.js} +43 -22
- package/dist/peer/chunk-2CD5COHN.js.map +6 -0
- package/dist/peer/{chunk-BMAXIBP2.js → chunk-3CBV5SAI.js} +4 -4
- package/dist/peer/{chunk-BMAXIBP2.js.map → chunk-3CBV5SAI.js.map} +1 -1
- package/dist/peer/{chunk-WSNRD2AQ.js → chunk-45GVDKP5.js} +11 -10
- package/dist/{chunk-Q6MMPKQA.js.map → peer/chunk-45GVDKP5.js.map} +1 -1
- package/dist/peer/{chunk-R4VX5UC7.js → chunk-LWXQX3NJ.js} +3 -3
- package/dist/{chunk-6TPZ7G74.js → peer/chunk-MKY3SDXU.js} +289 -25
- package/dist/peer/chunk-MKY3SDXU.js.map +6 -0
- package/dist/peer/chunk-S6LSPHSU.js +17 -0
- package/dist/peer/chunk-S6LSPHSU.js.map +6 -0
- package/dist/peer/{chunk-TSC4RAH3.js → chunk-VZHHNQYB.js} +1301 -70
- package/dist/peer/chunk-VZHHNQYB.js.map +6 -0
- package/dist/peer/{chunk-WQGENQZO.js → chunk-YITWGAR4.js} +8 -6
- package/dist/peer/chunk-YITWGAR4.js.map +6 -0
- package/dist/peer/chunk-Z5II55QT.js +33 -0
- package/dist/peer/chunk-Z5II55QT.js.map +6 -0
- package/dist/peer/designer.js +444 -243
- package/dist/peer/designer.js.map +3 -3
- package/dist/peer/engine.worker.js +16729 -17
- package/dist/peer/engine.worker.js.map +3 -3
- package/dist/peer/viewer.js +14 -11
- package/dist/peer/viewer.js.map +1 -1
- package/dist/viewer.d.ts +2 -1
- package/dist/viewer.js +14 -11
- package/dist/viewer.js.map +1 -1
- package/package.json +4 -2
- package/dist/chunk-3D2KFKG2.js.map +0 -6
- package/dist/chunk-6TPZ7G74.js.map +0 -6
- package/dist/chunk-BRB34AJ2.js +0 -16
- package/dist/chunk-M6AYND5G.js.map +0 -6
- package/dist/chunk-NR2G4TMG.js.map +0 -6
- package/dist/chunk-PGP3QA6L.js.map +0 -6
- package/dist/chunk-S2IUUI6N.js.map +0 -6
- package/dist/chunk-ULKEEARQ.js +0 -553
- package/dist/chunk-ULKEEARQ.js.map +0 -6
- package/dist/chunk-VNOWPSE6.js.map +0 -6
- package/dist/chunk-Z7MKH66Z.js.map +0 -6
- package/dist/peer/chunk-2FZTYEDE.js +0 -15
- package/dist/peer/chunk-6I2EAAVN.js.map +0 -6
- package/dist/peer/chunk-BQFI3DHK.js.map +0 -6
- package/dist/peer/chunk-TSC4RAH3.js.map +0 -6
- package/dist/peer/chunk-WQGENQZO.js.map +0 -6
- package/dist/peer/chunk-WSNRD2AQ.js.map +0 -6
- /package/dist/{chunk-2BPBQMH2.js.map → chunk-F5EPQTPF.js.map} +0 -0
- /package/dist/{chunk-BRB34AJ2.js.map → chunk-FEM2QVOO.js.map} +0 -0
- /package/dist/{peer/chunk-2FZTYEDE.js.map → chunk-YIX3OJXU.js.map} +0 -0
- /package/dist/peer/{chunk-R4VX5UC7.js.map → chunk-LWXQX3NJ.js.map} +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FORMAT_CHAR
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-EK5CJY22.js";
|
|
4
|
+
import "../chunk-BR5K6SBL.js";
|
|
4
5
|
import {
|
|
5
6
|
asciiUrl,
|
|
6
7
|
drillUrl,
|
|
7
8
|
safeUrl
|
|
8
9
|
} from "../chunk-72S6DETS.js";
|
|
10
|
+
import "../chunk-GJS242RR.js";
|
|
9
11
|
import {
|
|
10
12
|
withDeadline
|
|
11
13
|
} from "../chunk-D2NTLAKL.js";
|
|
@@ -18,24 +20,39 @@ import {
|
|
|
18
20
|
cellVisuals,
|
|
19
21
|
figures,
|
|
20
22
|
parseColor
|
|
21
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-UJL7C2AS.js";
|
|
22
24
|
import {
|
|
23
25
|
IMAGE_LIMITS,
|
|
26
|
+
PDFArray,
|
|
27
|
+
PDFBool,
|
|
28
|
+
PDFDict,
|
|
29
|
+
PDFDocument,
|
|
30
|
+
PDFHexString,
|
|
31
|
+
PDFName,
|
|
32
|
+
PDFNumber,
|
|
33
|
+
PDFRawStream,
|
|
34
|
+
PDFStream,
|
|
35
|
+
PDFString,
|
|
36
|
+
concatTransformationMatrix,
|
|
24
37
|
dataUriBytes,
|
|
25
38
|
dataUriBytesOf,
|
|
39
|
+
embeddedFace,
|
|
40
|
+
fontCss,
|
|
41
|
+
fontkit,
|
|
26
42
|
imageInfoOf,
|
|
43
|
+
isStandard,
|
|
44
|
+
loadFontkit,
|
|
45
|
+
loadPdfLib,
|
|
46
|
+
popGraphicsState,
|
|
47
|
+
pushGraphicsState,
|
|
48
|
+
rgb,
|
|
27
49
|
svgLength,
|
|
28
50
|
svgRootAttrs,
|
|
29
51
|
xmlAttrs,
|
|
30
52
|
xmlTags
|
|
31
|
-
} from "../chunk-
|
|
32
|
-
|
|
33
|
-
// src/exporters/pdf.js
|
|
34
|
-
import { PDFDocument, PDFName as PDFName3, PDFString as PDFString4, PDFHexString as PDFHexString5, PDFRawStream as PDFRawStream2, rgb as rgb3 } from "pdf-lib";
|
|
35
|
-
import fontkitModule from "@pdf-lib/fontkit";
|
|
53
|
+
} from "../chunk-QFLVVM3H.js";
|
|
36
54
|
|
|
37
55
|
// src/exporters/pdfa.js
|
|
38
|
-
import { PDFName, PDFNumber, PDFString, PDFHexString, PDFArray, PDFDict } from "pdf-lib";
|
|
39
56
|
var xml = (s) => String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
40
57
|
function makePdfA(doc, { icc, title = "Report", author, created = /* @__PURE__ */ new Date(), conformance = "B", ua = false, id } = {}) {
|
|
41
58
|
if (!icc?.length) throw new Error("PDF/A needs an sRGB colour profile: pass pdfa.icc (public/icc/sRGB-v2-magic.icc)");
|
|
@@ -106,7 +123,6 @@ function setUaMetadata(doc, { title = "Report", author = void 0, created = /* @_
|
|
|
106
123
|
}
|
|
107
124
|
|
|
108
125
|
// src/exporters/svgimage.js
|
|
109
|
-
import { pushGraphicsState, popGraphicsState, concatTransformationMatrix, rgb } from "pdf-lib";
|
|
110
126
|
var mul = (a, b) => [a[0] * b[0] + a[2] * b[1], a[1] * b[0] + a[3] * b[1], a[0] * b[2] + a[2] * b[3], a[1] * b[2] + a[3] * b[3], a[0] * b[4] + a[2] * b[5] + a[4], a[1] * b[4] + a[3] * b[5] + a[5]];
|
|
111
127
|
var I = [1, 0, 0, 1, 0, 0];
|
|
112
128
|
var TRANSFORMS = /* @__PURE__ */ new Set(["matrix", "translate", "scale", "rotate", "skewX", "skewY"]);
|
|
@@ -263,7 +279,6 @@ function drawSvg(page, svg, at) {
|
|
|
263
279
|
}
|
|
264
280
|
|
|
265
281
|
// src/exporters/encrypt.js
|
|
266
|
-
import { PDFArray as PDFArray2, PDFDict as PDFDict2, PDFNumber as PDFNumber2, PDFString as PDFString2, PDFHexString as PDFHexString2, PDFRawStream, PDFStream, PDFBool } from "pdf-lib";
|
|
267
282
|
var subtle = () => {
|
|
268
283
|
const s = globalThis.crypto?.subtle;
|
|
269
284
|
if (!s) throw new Error("PDF encryption needs WebCrypto (a browser, or Node 20 or later)");
|
|
@@ -337,12 +352,12 @@ async function encryptPdf(doc, opt) {
|
|
|
337
352
|
};
|
|
338
353
|
const seen = /* @__PURE__ */ new Set();
|
|
339
354
|
const walk = async (obj) => {
|
|
340
|
-
if (obj instanceof
|
|
341
|
-
if (obj instanceof
|
|
355
|
+
if (obj instanceof PDFString || obj instanceof PDFHexString) return PDFHexString.of(hex(await enc(obj.asBytes())));
|
|
356
|
+
if (obj instanceof PDFArray) {
|
|
342
357
|
for (let i = 0; i < obj.size(); i++) obj.set(i, await walk(obj.get(i)));
|
|
343
358
|
return obj;
|
|
344
359
|
}
|
|
345
|
-
if (obj instanceof
|
|
360
|
+
if (obj instanceof PDFDict) {
|
|
346
361
|
if (seen.has(obj)) return obj;
|
|
347
362
|
seen.add(obj);
|
|
348
363
|
for (const [k, v] of obj.entries()) obj.set(k, await walk(v));
|
|
@@ -367,21 +382,20 @@ async function encryptPdf(doc, opt) {
|
|
|
367
382
|
CF: { StdCF: { AuthEvent: "DocOpen", CFM: "AESV3", Length: 32 } },
|
|
368
383
|
StmF: "StdCF",
|
|
369
384
|
StrF: "StdCF",
|
|
370
|
-
O:
|
|
371
|
-
U:
|
|
372
|
-
OE:
|
|
373
|
-
UE:
|
|
374
|
-
P:
|
|
375
|
-
Perms:
|
|
385
|
+
O: PDFHexString.of(hex(O)),
|
|
386
|
+
U: PDFHexString.of(hex(U)),
|
|
387
|
+
OE: PDFHexString.of(hex(OE)),
|
|
388
|
+
UE: PDFHexString.of(hex(UE)),
|
|
389
|
+
P: PDFNumber.of(P),
|
|
390
|
+
Perms: PDFHexString.of(hex(Perms)),
|
|
376
391
|
EncryptMetadata: PDFBool.True
|
|
377
392
|
});
|
|
378
393
|
ctx.trailerInfo.Encrypt = ctx.register(encrypt);
|
|
379
|
-
const id =
|
|
394
|
+
const id = PDFHexString.of(hex(random(16)));
|
|
380
395
|
ctx.trailerInfo.ID = ctx.obj([id, id]);
|
|
381
396
|
}
|
|
382
397
|
|
|
383
398
|
// src/exporters/pdfua.js
|
|
384
|
-
import { PDFName as PDFName2, PDFNumber as PDFNumber3, PDFHexString as PDFHexString3, PDFDict as PDFDict3, PDFArray as PDFArray3, PDFString as PDFString3 } from "pdf-lib";
|
|
385
399
|
var MARKER = /^\s*(?:[•◦▪▫‣·○●■□–—-]|\d{1,4}[.)]|[a-zA-Z][.)]|[ivxlcdmIVXLCDM]{1,6}[.)])\s*$/;
|
|
386
400
|
function createTagger(model, doc) {
|
|
387
401
|
const ctx = doc.context;
|
|
@@ -411,6 +425,11 @@ function createTagger(model, doc) {
|
|
|
411
425
|
/** A link annotation of item ii (or a field's widget): its structure element; returns its StructParent key. */
|
|
412
426
|
annot(pi, ii, ref, kind) {
|
|
413
427
|
const p = plans[pi].get(ii);
|
|
428
|
+
if (p?.link) {
|
|
429
|
+
p.link.kids.push({ objr: ref, pi });
|
|
430
|
+
annots.push({ ref, el: p.link, pi });
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
414
433
|
const el = node(kind === "field" ? "Form" : "Link");
|
|
415
434
|
(p?.near || root).kids.push(el);
|
|
416
435
|
el.parent = p?.near || root;
|
|
@@ -435,14 +454,14 @@ function createTagger(model, doc) {
|
|
|
435
454
|
let key = 0;
|
|
436
455
|
pages.forEach((pg, pi) => {
|
|
437
456
|
if (!mcids[pi].length) return;
|
|
438
|
-
pg.node.set(
|
|
439
|
-
nums.push(
|
|
457
|
+
pg.node.set(PDFName.of("StructParents"), PDFNumber.of(key));
|
|
458
|
+
nums.push(PDFNumber.of(key++), ctx.obj(mcids[pi].map((n) => refOf.get(n))));
|
|
440
459
|
});
|
|
441
460
|
for (const a of annots) {
|
|
442
461
|
const d = ctx.lookup(a.ref);
|
|
443
|
-
if (d instanceof
|
|
444
|
-
nums.push(
|
|
445
|
-
pages[a.pi]?.node.set(
|
|
462
|
+
if (d instanceof PDFDict) d.set(PDFName.of("StructParent"), PDFNumber.of(key));
|
|
463
|
+
nums.push(PDFNumber.of(key++), refOf.get(a.el));
|
|
464
|
+
pages[a.pi]?.node.set(PDFName.of("Tabs"), PDFName.of("S"));
|
|
446
465
|
}
|
|
447
466
|
const treeRef = ctx.nextRef();
|
|
448
467
|
for (const n of all) {
|
|
@@ -450,20 +469,20 @@ function createTagger(model, doc) {
|
|
|
450
469
|
const K = n.kids.map((k) => {
|
|
451
470
|
if (k.S) return refOf.get(k);
|
|
452
471
|
if (k.objr) return ctx.obj({ Type: "OBJR", Obj: k.objr, Pg: pages[k.pi].ref });
|
|
453
|
-
return k.pi === pgOf ?
|
|
472
|
+
return k.pi === pgOf ? PDFNumber.of(k.mcid) : ctx.obj({ Type: "MCR", Pg: pages[k.pi].ref, MCID: k.mcid });
|
|
454
473
|
});
|
|
455
474
|
const d = ctx.obj({ Type: "StructElem", S: n.S, P: n === root ? treeRef : refOf.get(n.parent || root), K });
|
|
456
|
-
if (pgOf != null) d.set(
|
|
457
|
-
if (n.alt != null) d.set(
|
|
458
|
-
if (n.attrs) d.set(
|
|
475
|
+
if (pgOf != null) d.set(PDFName.of("Pg"), pages[pgOf].ref);
|
|
476
|
+
if (n.alt != null) d.set(PDFName.of("Alt"), PDFHexString.fromText(n.alt));
|
|
477
|
+
if (n.attrs) d.set(PDFName.of("A"), ctx.obj(n.attrs));
|
|
459
478
|
ctx.assign(refOf.get(n), d);
|
|
460
479
|
}
|
|
461
480
|
ctx.assign(treeRef, ctx.obj({ Type: "StructTreeRoot", K: refOf.get(root), ParentTree: ctx.obj({ Nums: nums }), ParentTreeNextKey: key }));
|
|
462
481
|
const cat2 = doc.catalog;
|
|
463
|
-
cat2.set(
|
|
464
|
-
cat2.set(
|
|
465
|
-
cat2.set(
|
|
466
|
-
cat2.set(
|
|
482
|
+
cat2.set(PDFName.of("StructTreeRoot"), treeRef);
|
|
483
|
+
cat2.set(PDFName.of("MarkInfo"), ctx.obj({ Marked: true }));
|
|
484
|
+
cat2.set(PDFName.of("Lang"), PDFString.of(String(lang).replace(/[^A-Za-z0-9-]/g, "") || "en"));
|
|
485
|
+
cat2.set(PDFName.of("ViewerPreferences"), ctx.obj({ DisplayDocTitle: true }));
|
|
467
486
|
doc.setTitle(title, { showInWindowTitleBar: true });
|
|
468
487
|
}
|
|
469
488
|
};
|
|
@@ -515,8 +534,38 @@ function plan(model, pg, pi, root) {
|
|
|
515
534
|
return el;
|
|
516
535
|
};
|
|
517
536
|
let lastText = null;
|
|
537
|
+
const tocLink = (e) => {
|
|
538
|
+
const toc = root.toc || (root.toc = { el: null, last: -1, entries: /* @__PURE__ */ new Map() });
|
|
539
|
+
if (!toc.el || e < toc.last) {
|
|
540
|
+
toc.el = add(node("TOC"));
|
|
541
|
+
toc.entries = /* @__PURE__ */ new Map();
|
|
542
|
+
}
|
|
543
|
+
toc.last = Math.max(toc.last, e);
|
|
544
|
+
let link = toc.entries.get(e);
|
|
545
|
+
if (!link) {
|
|
546
|
+
const toci = node("TOCI"), ref = node("Reference");
|
|
547
|
+
link = node("Link");
|
|
548
|
+
toci.parent = toc.el;
|
|
549
|
+
toc.el.kids.push(toci);
|
|
550
|
+
ref.parent = toci;
|
|
551
|
+
toci.kids.push(ref);
|
|
552
|
+
link.parent = ref;
|
|
553
|
+
ref.kids.push(link);
|
|
554
|
+
toc.entries.set(e, link);
|
|
555
|
+
}
|
|
556
|
+
return link;
|
|
557
|
+
};
|
|
518
558
|
items.forEach((it, i) => {
|
|
519
559
|
if (it.t === "bookmark") return;
|
|
560
|
+
if (it.tocEntry != null && (it.t === "text" || it.t === "link") && !it.art) {
|
|
561
|
+
const link = tocLink(it.tocEntry);
|
|
562
|
+
out.set(i, it.t === "link" ? { link } : { el: link });
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (it.tocTitle && it.t === "text" && it.lines?.length) {
|
|
566
|
+
out.set(i, { el: add(node("H1")) });
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
520
569
|
if (it.t === "link" || it.t === "field") {
|
|
521
570
|
out.set(i, { near: lastText && overlaps(lastText.it, it) ? lastText.el : null });
|
|
522
571
|
return;
|
|
@@ -748,8 +797,285 @@ function pngProblem(b) {
|
|
|
748
797
|
return null;
|
|
749
798
|
}
|
|
750
799
|
|
|
800
|
+
// src/exporters/pdfstream.js
|
|
801
|
+
import { Zlib } from "fflate";
|
|
802
|
+
|
|
803
|
+
// src/exporters/pdfstreamtags.js
|
|
804
|
+
function createStreamTagger(w, { maxElements = Infinity } = {}) {
|
|
805
|
+
let count = 0;
|
|
806
|
+
const made = () => {
|
|
807
|
+
if (++count > maxElements) throw Object.assign(new Error(`The tagged PDF has more than ${maxElements.toLocaleString("en-US")} structure elements (tagged.maxElements). Filter the data, or export it untagged.`), { status: 413 });
|
|
808
|
+
};
|
|
809
|
+
const rootRef = w.reserve(), docRef = w.reserve();
|
|
810
|
+
const docKids = [];
|
|
811
|
+
let table = (
|
|
812
|
+
/** @type {null | { ref: number, cols: number, rows: Int32Array, n: number }} */
|
|
813
|
+
null
|
|
814
|
+
);
|
|
815
|
+
let headerDone = false;
|
|
816
|
+
let nums = new Int32Array(1024), nn = 0, key = 0;
|
|
817
|
+
const num3 = (k, ref) => {
|
|
818
|
+
if (nn + 2 > nums.length) {
|
|
819
|
+
const b = new Int32Array(nums.length * 2);
|
|
820
|
+
b.set(nums);
|
|
821
|
+
nums = b;
|
|
822
|
+
}
|
|
823
|
+
nums[nn++] = k;
|
|
824
|
+
nums[nn++] = ref;
|
|
825
|
+
};
|
|
826
|
+
const addRow = (ref) => {
|
|
827
|
+
const t = (
|
|
828
|
+
/** @type {any} */
|
|
829
|
+
table
|
|
830
|
+
);
|
|
831
|
+
if (t.n === t.rows.length) {
|
|
832
|
+
const b = new Int32Array(t.n * 2);
|
|
833
|
+
b.set(t.rows);
|
|
834
|
+
t.rows = b;
|
|
835
|
+
}
|
|
836
|
+
t.rows[t.n++] = ref;
|
|
837
|
+
};
|
|
838
|
+
let mcids = (
|
|
839
|
+
/** @type {number[]} */
|
|
840
|
+
[]
|
|
841
|
+
);
|
|
842
|
+
let rows = /* @__PURE__ */ new Map();
|
|
843
|
+
let els = (
|
|
844
|
+
/** @type {any[]} */
|
|
845
|
+
[]
|
|
846
|
+
);
|
|
847
|
+
let last = (
|
|
848
|
+
/** @type {any} */
|
|
849
|
+
null
|
|
850
|
+
);
|
|
851
|
+
let links = false, win = 0;
|
|
852
|
+
const el = (S, parent, attrs2) => {
|
|
853
|
+
made();
|
|
854
|
+
const e = { ref: w.reserve(), S, parent, mcid: (
|
|
855
|
+
/** @type {number[]} */
|
|
856
|
+
[]
|
|
857
|
+
), kids: (
|
|
858
|
+
/** @type {any[]} */
|
|
859
|
+
[]
|
|
860
|
+
), attrs: attrs2 };
|
|
861
|
+
els.push(e);
|
|
862
|
+
return e;
|
|
863
|
+
};
|
|
864
|
+
const mark = (e) => {
|
|
865
|
+
const m = mcids.length;
|
|
866
|
+
mcids.push(e.ref);
|
|
867
|
+
e.mcid.push(m);
|
|
868
|
+
return `/${e.S} <</MCID ${m}>> BDC
|
|
869
|
+
`;
|
|
870
|
+
};
|
|
871
|
+
return {
|
|
872
|
+
/** structure elements so far */
|
|
873
|
+
get count() {
|
|
874
|
+
return count;
|
|
875
|
+
},
|
|
876
|
+
/** a new page (window: the paged window it came from; row ids are its own) @param {number} window */
|
|
877
|
+
page(window) {
|
|
878
|
+
mcids = [];
|
|
879
|
+
rows = /* @__PURE__ */ new Map();
|
|
880
|
+
els = [];
|
|
881
|
+
last = null;
|
|
882
|
+
links = false;
|
|
883
|
+
win = window;
|
|
884
|
+
},
|
|
885
|
+
/**
|
|
886
|
+
* The marked content that opens item it: a structure element's MCID, or an artifact; null for a link.
|
|
887
|
+
* @param {any} it
|
|
888
|
+
*/
|
|
889
|
+
open(it) {
|
|
890
|
+
if (it.t === "link" || it.t === "bookmark") return null;
|
|
891
|
+
if (it.art) return "/Artifact <</Type /Pagination>> BDC\n";
|
|
892
|
+
if (it.t !== "text" || !it.lines?.some((l) => String(l.text).trim())) return "/Artifact BMC\n";
|
|
893
|
+
const c = it.cell;
|
|
894
|
+
if (!c) {
|
|
895
|
+
const h = it.tag?.h ? Math.min(6, Math.max(1, it.tag.h)) : 0;
|
|
896
|
+
const e = el(h ? `H${h}` : "P", docRef);
|
|
897
|
+
docKids.push(e.ref);
|
|
898
|
+
last = { e, it };
|
|
899
|
+
return mark(e);
|
|
900
|
+
}
|
|
901
|
+
if (c.kind === "header" && headerDone) return "/Artifact <</Type /Pagination>> BDC\n";
|
|
902
|
+
if (!table) {
|
|
903
|
+
table = { ref: w.reserve(), cols: c.cols.length, rows: new Int32Array(4096), n: 0 };
|
|
904
|
+
docKids.push(table.ref);
|
|
905
|
+
}
|
|
906
|
+
const rk = `${win}:${c.row}`;
|
|
907
|
+
let r = rows.get(rk);
|
|
908
|
+
if (!r) {
|
|
909
|
+
made();
|
|
910
|
+
r = { ref: w.reserve(), kind: c.kind, cells: /* @__PURE__ */ new Map() };
|
|
911
|
+
rows.set(rk, r);
|
|
912
|
+
addRow(r.ref);
|
|
913
|
+
}
|
|
914
|
+
let cell = r.cells.get(c.col);
|
|
915
|
+
if (!cell) {
|
|
916
|
+
const attrs2 = c.kind === "header" || c.span > 1 ? { O: "/Table", ...c.kind === "header" ? { Scope: "/Column" } : {}, ...c.span > 1 ? { ColSpan: c.span } : {} } : null;
|
|
917
|
+
cell = el(c.kind === "header" ? "TH" : "TD", r.ref, attrs2);
|
|
918
|
+
r.cells.set(c.col, cell);
|
|
919
|
+
}
|
|
920
|
+
last = { e: cell, it };
|
|
921
|
+
return mark(cell);
|
|
922
|
+
},
|
|
923
|
+
/**
|
|
924
|
+
* A link annotation of the page: its Link element (in the element of the text it covers, else the Document).
|
|
925
|
+
* @returns {number} the annotation's StructParent
|
|
926
|
+
* @param {any} it @param {number} annot the annotation's object number
|
|
927
|
+
*/
|
|
928
|
+
link(it, annot) {
|
|
929
|
+
const near = last && overlaps2(last.it, it) ? last.e : null;
|
|
930
|
+
const e = el("Link", near ? near.ref : docRef);
|
|
931
|
+
e.kids.push(`<< /Type /OBJR /Obj ${annot} 0 R >>`);
|
|
932
|
+
(near ? near.kids : docKids).push(near ? `${e.ref} 0 R` : e.ref);
|
|
933
|
+
links = true;
|
|
934
|
+
num3(key, e.ref);
|
|
935
|
+
return key++;
|
|
936
|
+
},
|
|
937
|
+
/**
|
|
938
|
+
* The page is drawn: its elements and parent-tree array are written. @returns {Promise<string>} the page's entries
|
|
939
|
+
* @param {number} pageRef
|
|
940
|
+
*/
|
|
941
|
+
async end(pageRef) {
|
|
942
|
+
for (const r of rows.values()) {
|
|
943
|
+
const kids = [];
|
|
944
|
+
for (let col2 = 0; col2 < /** @type {any} */
|
|
945
|
+
table.cols; ) {
|
|
946
|
+
let cell = r.cells.get(col2);
|
|
947
|
+
if (!cell) {
|
|
948
|
+
cell = el(r.kind === "header" ? "TH" : "TD", r.ref, r.kind === "header" ? { O: "/Table", Scope: "/Column" } : null);
|
|
949
|
+
}
|
|
950
|
+
kids.push(cell.ref);
|
|
951
|
+
col2 += Math.max(1, cell.attrs?.ColSpan || 1);
|
|
952
|
+
}
|
|
953
|
+
for (const [col2, cell] of r.cells) if (!kids.includes(cell.ref)) {
|
|
954
|
+
void col2;
|
|
955
|
+
kids.push(cell.ref);
|
|
956
|
+
}
|
|
957
|
+
await w.objectAt(r.ref, `<< /S /TR /P ${/** @type {any} */
|
|
958
|
+
table.ref} 0 R /K [${kids.map((k) => `${k} 0 R`).join(" ")}] >>`);
|
|
959
|
+
}
|
|
960
|
+
if (rows.size && [...rows.values()].some((r) => r.kind === "header")) headerDone = true;
|
|
961
|
+
for (const e of els) {
|
|
962
|
+
const K = [...e.mcid.map(String), ...e.kids].join(" ");
|
|
963
|
+
const A = e.attrs ? ` /A << ${Object.entries(e.attrs).map(([k, v]) => `/${k} ${v}`).join(" ")} >>` : "";
|
|
964
|
+
const P = e.parent === docRef ? docRef : e.parent;
|
|
965
|
+
await w.objectAt(e.ref, `<< /S /${e.S} /P ${P} 0 R${e.mcid.length || e.S === "Link" ? ` /Pg ${pageRef} 0 R` : ""} /K [${K}]${A} >>`);
|
|
966
|
+
}
|
|
967
|
+
let extra = "";
|
|
968
|
+
if (mcids.length) {
|
|
969
|
+
const arr = await w.object(`[${mcids.map((r) => `${r} 0 R`).join(" ")}]`);
|
|
970
|
+
num3(key, arr);
|
|
971
|
+
extra += ` /StructParents ${key++}`;
|
|
972
|
+
}
|
|
973
|
+
if (links) extra += " /Tabs /S";
|
|
974
|
+
return extra;
|
|
975
|
+
},
|
|
976
|
+
/**
|
|
977
|
+
* The tree's top: Table, Document, the parent tree, the root. @returns {Promise<string>} the catalog's entries
|
|
978
|
+
* @param {{ lang?: string }} o
|
|
979
|
+
*/
|
|
980
|
+
async finish({ lang = "en" } = {}) {
|
|
981
|
+
const t = table;
|
|
982
|
+
if (t) await w.bigObject(t.ref, `<< /Type /StructElem /S /Table /P ${docRef} 0 R /K [`, refs(t.rows, t.n), "] >>");
|
|
983
|
+
await w.objectAt(docRef, `<< /Type /StructElem /S /Document /P ${rootRef} 0 R /K [${docKids.map((k) => typeof k === "string" ? k : `${k} 0 R`).join(" ")}] >>`);
|
|
984
|
+
const pt = w.reserve();
|
|
985
|
+
await w.bigObject(pt, "<< /Nums [", pairs(nums, nn), "] >>");
|
|
986
|
+
await w.objectAt(rootRef, `<< /Type /StructTreeRoot /K ${docRef} 0 R /ParentTree ${pt} 0 R /ParentTreeNextKey ${key} >>`);
|
|
987
|
+
return ` /StructTreeRoot ${rootRef} 0 R /MarkInfo << /Marked true >> /Lang (${String(lang).replace(/[^A-Za-z0-9-]/g, "") || "en"}) /ViewerPreferences << /DisplayDocTitle true >>`;
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
function* refs(a, n) {
|
|
992
|
+
for (let i = 0; i < n; i += 4096) {
|
|
993
|
+
let s = "";
|
|
994
|
+
for (let j = i; j < Math.min(n, i + 4096); j++) s += `${a[j]} 0 R `;
|
|
995
|
+
yield s;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function* pairs(a, n) {
|
|
999
|
+
for (let i = 0; i < n; i += 4096) {
|
|
1000
|
+
let s = "";
|
|
1001
|
+
for (let j = i; j < Math.min(n, i + 4096); j += 2) s += `${a[j]} ${a[j + 1]} 0 R `;
|
|
1002
|
+
yield s;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function overlaps2(t, l) {
|
|
1006
|
+
const c = t.clip || { x: t.lines[0].x, y: t.lines[0].y - t.size, w: t.lines[0].w || 0, h: t.size * 1.3 };
|
|
1007
|
+
return l.x < c.x + c.w && c.x < l.x + l.w && l.y < c.y + c.h && c.y < l.y + l.h;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// src/exporters/pdfstandard.js
|
|
1011
|
+
function standardFontEntries(f) {
|
|
1012
|
+
return {
|
|
1013
|
+
Type: "Font",
|
|
1014
|
+
Subtype: "Type1",
|
|
1015
|
+
BaseFont: f.postscriptName,
|
|
1016
|
+
...f.winAnsi ? { Encoding: "WinAnsiEncoding" } : {},
|
|
1017
|
+
FirstChar: 32,
|
|
1018
|
+
LastChar: 255,
|
|
1019
|
+
Widths: f.widths.slice(32, 256)
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function standardFontDict(f) {
|
|
1023
|
+
const e = standardFontEntries(f);
|
|
1024
|
+
return `<< /Type /Font /Subtype /Type1 /BaseFont /${e.BaseFont}${e.Encoding ? ` /Encoding /${e.Encoding}` : ""} /FirstChar 32 /LastChar 255 /Widths [${e.Widths.join(" ")}] >>`;
|
|
1025
|
+
}
|
|
1026
|
+
var standIns = (store) => [...new Set([...store.fonts.keys()].filter(isStandard).map(embeddedFace))];
|
|
1027
|
+
var esc = (b) => b === 40 || b === 41 || b === 92 ? "\\" + String.fromCharCode(b) : b === 13 ? "\\r" : String.fromCharCode(b);
|
|
1028
|
+
function standardLiteral(f, text) {
|
|
1029
|
+
let out = "";
|
|
1030
|
+
for (const ch of text) out += esc(f.glyphForCodePoint(
|
|
1031
|
+
/** @type {number} */
|
|
1032
|
+
ch.codePointAt(0)
|
|
1033
|
+
).id);
|
|
1034
|
+
return out;
|
|
1035
|
+
}
|
|
1036
|
+
function embeddedPage(pg, fontOf, families) {
|
|
1037
|
+
const line = (l, key, size) => {
|
|
1038
|
+
const runs = l.runs || [{ font: key, x: 0, text: l.text, glyphs: null }];
|
|
1039
|
+
if (!runs.some((r) => isStandard(r.font))) return l;
|
|
1040
|
+
return { ...l, runs: runs.map((r) => {
|
|
1041
|
+
if (!isStandard(r.font)) return r;
|
|
1042
|
+
families.add(fontCss(r.font).family);
|
|
1043
|
+
const std = fontOf(r.font), sub = embeddedFace(r.font), emb = fontOf(sub);
|
|
1044
|
+
const glyphs = [];
|
|
1045
|
+
if (r.glyphs) {
|
|
1046
|
+
for (let i = 0; i < r.glyphs.length; i += 4) glyphs.push(emb.glyphForCodePoint(r.text.codePointAt(r.glyphs[i + 3])).id, r.glyphs[i + 1], r.glyphs[i + 2], r.glyphs[i + 3]);
|
|
1047
|
+
return { ...r, font: sub, glyphs };
|
|
1048
|
+
}
|
|
1049
|
+
let pen = 0;
|
|
1050
|
+
for (let i = 0; i < r.text.length; ) {
|
|
1051
|
+
const cp = (
|
|
1052
|
+
/** @type {number} */
|
|
1053
|
+
r.text.codePointAt(i)
|
|
1054
|
+
);
|
|
1055
|
+
glyphs.push(emb.glyphForCodePoint(cp).id, pen, 0, i);
|
|
1056
|
+
pen += std.glyphForCodePoint(cp).advanceWidth * size / 1e3;
|
|
1057
|
+
i += cp > 65535 ? 2 : 1;
|
|
1058
|
+
}
|
|
1059
|
+
return { ...r, font: sub, w: pen, glyphs };
|
|
1060
|
+
}) };
|
|
1061
|
+
};
|
|
1062
|
+
const item = (it) => {
|
|
1063
|
+
if (it.t === "field") {
|
|
1064
|
+
const draw = it.draw.map(item);
|
|
1065
|
+
return draw.some((d, i) => d !== it.draw[i]) ? { ...it, draw } : it;
|
|
1066
|
+
}
|
|
1067
|
+
if (it.t !== "text") return it;
|
|
1068
|
+
const lines = it.lines.map((l) => line(l, it.font, it.size));
|
|
1069
|
+
return lines.some((l, i) => l !== it.lines[i]) ? { ...it, lines } : it;
|
|
1070
|
+
};
|
|
1071
|
+
const items = pg.items.map(item);
|
|
1072
|
+
return items.some((x, i) => x !== pg.items[i]) ? { ...pg, items } : pg;
|
|
1073
|
+
}
|
|
1074
|
+
function embeddedWarnings(families) {
|
|
1075
|
+
return [...families].map((f) => `PDF/A and PDF/UA need embedded fonts, and "${f}" is a standard font that is not embedded: its text is drawn in ${fontCss(embeddedFace(f)).family} at ${f}'s spacing (no metric-compatible font ships, so the letters' widths differ).`);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
751
1078
|
// src/exporters/pdfpaint.js
|
|
752
|
-
import { PDFHexString as PDFHexString4, rgb as rgb2 } from "pdf-lib";
|
|
753
1079
|
var colors = /* @__PURE__ */ new Map();
|
|
754
1080
|
var col = (c) => {
|
|
755
1081
|
if (colors.has(c)) return colors.get(c);
|
|
@@ -758,6 +1084,17 @@ var col = (c) => {
|
|
|
758
1084
|
return v;
|
|
759
1085
|
};
|
|
760
1086
|
var BLACK = { color: rgb2(0, 0, 0), opacity: 1, rgb: "0 0 0" };
|
|
1087
|
+
function rgb2(red, green, blue) {
|
|
1088
|
+
return { type: (
|
|
1089
|
+
/** @type {any} */
|
|
1090
|
+
"RGB"
|
|
1091
|
+
), red, green, blue };
|
|
1092
|
+
}
|
|
1093
|
+
var hexText = (s) => {
|
|
1094
|
+
let h = "<FEFF";
|
|
1095
|
+
for (let i = 0; i < s.length; i++) h += s.charCodeAt(i).toString(16).toUpperCase().padStart(4, "0");
|
|
1096
|
+
return `${h}>`;
|
|
1097
|
+
};
|
|
761
1098
|
var n2 = (v) => Math.round(v * 100) / 100;
|
|
762
1099
|
var n3 = (v) => Math.round(v * 1e3) / 1e3;
|
|
763
1100
|
var n4 = (v) => Math.round(v * 1e4) / 1e4;
|
|
@@ -771,7 +1108,7 @@ var formatAt = (run, cl) => {
|
|
|
771
1108
|
function drawRun(c, run, x, y, size, pf, color, spans, texts) {
|
|
772
1109
|
const f = pf.embedder.font;
|
|
773
1110
|
const per = 1e3 / size;
|
|
774
|
-
const span = (text) => `/Span <</ActualText ${
|
|
1111
|
+
const span = (text) => `/Span <</ActualText ${hexText(text)}>> BDC
|
|
775
1112
|
`;
|
|
776
1113
|
c.et();
|
|
777
1114
|
c.paint(color, null);
|
|
@@ -822,7 +1159,7 @@ function drawRun(c, run, x, y, size, pf, color, spans, texts) {
|
|
|
822
1159
|
const adj = Math.round((pen - gx) * per * 1e3) / 1e3;
|
|
823
1160
|
if (id === 0 && (c.tagged || formatAt(run, cl))) pen = gx;
|
|
824
1161
|
else {
|
|
825
|
-
arr += (adj ? `${adj}` : "") + `<${hex4(id)}>`;
|
|
1162
|
+
arr += (adj ? `${adj}` : "") + `<${f.standard ? id.toString(16).padStart(2, "0") : hex4(id)}>`;
|
|
826
1163
|
pen = gx + adv(id) * size / f.unitsPerEm;
|
|
827
1164
|
}
|
|
828
1165
|
if (inSpan && (i + 4 >= g.length || (quietAt < 0 || i + 4 < quietAt) && g[i + 7] !== cl || i + 4 === quietAt)) {
|
|
@@ -1081,11 +1418,852 @@ async function deflateNow(bytes) {
|
|
|
1081
1418
|
return new Uint8Array(await new Response(new Blob([bytes]).stream().pipeThrough(new CompressionStream("deflate"))).arrayBuffer());
|
|
1082
1419
|
}
|
|
1083
1420
|
|
|
1421
|
+
// src/exporters/pdfstream.js
|
|
1422
|
+
var CHUNK = 64 * 1024;
|
|
1423
|
+
var LEAF = 64;
|
|
1424
|
+
var OBJSTM = 100;
|
|
1425
|
+
var TAGGED_LARGE = 1e6;
|
|
1426
|
+
var IN_FLIGHT = 8;
|
|
1427
|
+
var hex42 = (id) => id.toString(16).padStart(4, "0");
|
|
1428
|
+
var num2 = (v) => String(Math.round(v * 1e3) / 1e3);
|
|
1429
|
+
var fontRes = (key) => `F_${key.replace(/[^A-Za-z0-9.-]/g, "_")}`;
|
|
1430
|
+
var esc2 = (b) => b === 40 || b === 41 || b === 92 ? "\\" + String.fromCharCode(b) : b === 13 ? "\\r" : String.fromCharCode(b);
|
|
1431
|
+
function written(sink, r) {
|
|
1432
|
+
const s = (
|
|
1433
|
+
/** @type {any} */
|
|
1434
|
+
sink
|
|
1435
|
+
);
|
|
1436
|
+
if (r !== false || !s.once) return Promise.resolve(r);
|
|
1437
|
+
return new Promise((ok, fail) => {
|
|
1438
|
+
const off = () => {
|
|
1439
|
+
s.off?.("drain", onDrain);
|
|
1440
|
+
s.off?.("error", onError);
|
|
1441
|
+
s.off?.("close", onClose);
|
|
1442
|
+
};
|
|
1443
|
+
const onDrain = () => {
|
|
1444
|
+
off();
|
|
1445
|
+
ok(void 0);
|
|
1446
|
+
};
|
|
1447
|
+
const onError = (e) => {
|
|
1448
|
+
off();
|
|
1449
|
+
fail(e);
|
|
1450
|
+
};
|
|
1451
|
+
const onClose = () => {
|
|
1452
|
+
off();
|
|
1453
|
+
fail(Object.assign(new Error("The sink closed before the PDF was written"), { code: "ERR_STREAM_PREMATURE_CLOSE" }));
|
|
1454
|
+
};
|
|
1455
|
+
s.once("drain", onDrain);
|
|
1456
|
+
s.once("error", onError);
|
|
1457
|
+
s.once("close", onClose);
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
function raced(p, signal) {
|
|
1461
|
+
if (!signal) return p;
|
|
1462
|
+
if (signal.aborted) {
|
|
1463
|
+
p.catch(() => {
|
|
1464
|
+
});
|
|
1465
|
+
return Promise.reject(signal.reason);
|
|
1466
|
+
}
|
|
1467
|
+
return new Promise((ok, fail) => {
|
|
1468
|
+
const on = () => fail(signal.reason);
|
|
1469
|
+
signal.addEventListener("abort", on, { once: true });
|
|
1470
|
+
p.then((v) => {
|
|
1471
|
+
signal.removeEventListener("abort", on);
|
|
1472
|
+
ok(v);
|
|
1473
|
+
}, (e) => {
|
|
1474
|
+
signal.removeEventListener("abort", on);
|
|
1475
|
+
fail(e);
|
|
1476
|
+
});
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
function createPdfStream(sink, opt) {
|
|
1480
|
+
const { fontStore } = opt;
|
|
1481
|
+
let pos = 0, nextNum = 1;
|
|
1482
|
+
let kind = new Uint8Array(4096), loc = new Uint32Array(4096), idx = new Uint16Array(4096);
|
|
1483
|
+
const place = (n, k, l, i = 0) => {
|
|
1484
|
+
if (n >= kind.length) {
|
|
1485
|
+
let L = kind.length;
|
|
1486
|
+
while (L <= n) L *= 2;
|
|
1487
|
+
const k2 = new Uint8Array(L), l2 = new Uint32Array(L), i2 = new Uint16Array(L);
|
|
1488
|
+
k2.set(kind);
|
|
1489
|
+
l2.set(loc);
|
|
1490
|
+
i2.set(idx);
|
|
1491
|
+
kind = k2;
|
|
1492
|
+
loc = l2;
|
|
1493
|
+
idx = i2;
|
|
1494
|
+
}
|
|
1495
|
+
kind[n] = k;
|
|
1496
|
+
loc[n] = l;
|
|
1497
|
+
idx[n] = i;
|
|
1498
|
+
};
|
|
1499
|
+
let parts = [];
|
|
1500
|
+
let size = 0;
|
|
1501
|
+
const reserve = () => nextNum++;
|
|
1502
|
+
const flush = async () => {
|
|
1503
|
+
if (!size) return;
|
|
1504
|
+
const all = new Uint8Array(size);
|
|
1505
|
+
let at = 0;
|
|
1506
|
+
for (const p of parts) {
|
|
1507
|
+
all.set(p, at);
|
|
1508
|
+
at += p.length;
|
|
1509
|
+
}
|
|
1510
|
+
parts = [];
|
|
1511
|
+
size = 0;
|
|
1512
|
+
await raced(written(sink, sink.write(all)), opt.signal);
|
|
1513
|
+
};
|
|
1514
|
+
const put = (x) => {
|
|
1515
|
+
const u8 = typeof x === "string" ? latin12(x) : x;
|
|
1516
|
+
parts.push(u8);
|
|
1517
|
+
size += u8.length;
|
|
1518
|
+
pos += u8.length;
|
|
1519
|
+
return size >= CHUNK ? flush() : void 0;
|
|
1520
|
+
};
|
|
1521
|
+
let batch = [];
|
|
1522
|
+
const writeBatch = async () => {
|
|
1523
|
+
if (!batch.length) return;
|
|
1524
|
+
const b = batch;
|
|
1525
|
+
batch = [];
|
|
1526
|
+
const sn = reserve();
|
|
1527
|
+
let head = "", body = "";
|
|
1528
|
+
b.forEach(([n, d], i) => {
|
|
1529
|
+
head += `${n} ${body.length} `;
|
|
1530
|
+
body += `${d}
|
|
1531
|
+
`;
|
|
1532
|
+
place(n, 2, sn, i);
|
|
1533
|
+
});
|
|
1534
|
+
const raw = latin12(head + body);
|
|
1535
|
+
await writeObj(sn, `<< /Type /ObjStm /N ${b.length} /First ${head.length} /Filter /FlateDecode >>`, await deflate(raw));
|
|
1536
|
+
};
|
|
1537
|
+
const writeObj = async (n, dict, stream) => {
|
|
1538
|
+
if (!stream) {
|
|
1539
|
+
batch.push([n, dict]);
|
|
1540
|
+
place(n, 3, 0);
|
|
1541
|
+
return batch.length >= OBJSTM ? writeBatch() : void 0;
|
|
1542
|
+
}
|
|
1543
|
+
place(n, 1, pos);
|
|
1544
|
+
await put(`${n} 0 obj
|
|
1545
|
+
${dict.replace(/>>\s*$/, `/Length ${stream.length} >>`)}
|
|
1546
|
+
stream
|
|
1547
|
+
`);
|
|
1548
|
+
await put(stream);
|
|
1549
|
+
return put("\nendstream\nendobj\n");
|
|
1550
|
+
};
|
|
1551
|
+
put("%PDF-1.7\n%âãÏÓ\n");
|
|
1552
|
+
const fonts = /* @__PURE__ */ new Map();
|
|
1553
|
+
let pages = 0, done = false;
|
|
1554
|
+
const inFlight = [];
|
|
1555
|
+
const fontOf = (key) => {
|
|
1556
|
+
let f = fonts.get(key);
|
|
1557
|
+
if (!f) {
|
|
1558
|
+
if (done) throw new Error("The PDF is finished");
|
|
1559
|
+
fonts.set(key, f = { name: fontRes(key), ref: reserve(), font: fontStore.get(key), cps: /* @__PURE__ */ new Set([32]), glyphs: /* @__PURE__ */ new Map(), memo: /* @__PURE__ */ new Map(), lit: /* @__PURE__ */ new Map() });
|
|
1560
|
+
}
|
|
1561
|
+
return f;
|
|
1562
|
+
};
|
|
1563
|
+
const resRef = reserve();
|
|
1564
|
+
for (const key of opt.fonts || []) fontOf(key);
|
|
1565
|
+
const res = /* @__PURE__ */ new Map();
|
|
1566
|
+
const totals = [];
|
|
1567
|
+
const pageRefs = [];
|
|
1568
|
+
const leaves = [];
|
|
1569
|
+
const w = {
|
|
1570
|
+
/** @param {string} key @returns {string} the font's resource name (F1…) */
|
|
1571
|
+
fontName: (key) => fontOf(key).name,
|
|
1572
|
+
/**
|
|
1573
|
+
* The text's glyphs, one per character (as the engine measured it: no layout features), as hex for <…> Tj, with
|
|
1574
|
+
* the glyphs recorded for the subset, W and ToUnicode.
|
|
1575
|
+
* @param {string} key @param {string} text
|
|
1576
|
+
*/
|
|
1577
|
+
encode(key, text) {
|
|
1578
|
+
const F = fontOf(key);
|
|
1579
|
+
let out = "";
|
|
1580
|
+
for (const ch of text) {
|
|
1581
|
+
const cp = (
|
|
1582
|
+
/** @type {number} */
|
|
1583
|
+
ch.codePointAt(0)
|
|
1584
|
+
);
|
|
1585
|
+
let h = F.memo.get(cp);
|
|
1586
|
+
if (h === void 0) {
|
|
1587
|
+
const id = F.font.glyphForCodePoint(cp).id;
|
|
1588
|
+
F.memo.set(cp, h = F.font.standard ? id.toString(16).padStart(2, "0") : hex42(id));
|
|
1589
|
+
F.cps.add(cp);
|
|
1590
|
+
if (!F.glyphs.has(id)) F.glyphs.set(id, ch);
|
|
1591
|
+
}
|
|
1592
|
+
out += h;
|
|
1593
|
+
}
|
|
1594
|
+
return out;
|
|
1595
|
+
},
|
|
1596
|
+
/**
|
|
1597
|
+
* The same glyphs as a literal string's body, two bytes each, escaped (as pdf.js draws plain text): ( … ) Tj.
|
|
1598
|
+
* @param {string} key @param {string} text
|
|
1599
|
+
*/
|
|
1600
|
+
literal(key, text) {
|
|
1601
|
+
const F = fontOf(key);
|
|
1602
|
+
let out = "";
|
|
1603
|
+
for (const ch of text) {
|
|
1604
|
+
const cp = (
|
|
1605
|
+
/** @type {number} */
|
|
1606
|
+
ch.codePointAt(0)
|
|
1607
|
+
);
|
|
1608
|
+
let b = F.lit.get(cp);
|
|
1609
|
+
if (b === void 0) {
|
|
1610
|
+
const id = parseInt(w.encode(key, ch), 16);
|
|
1611
|
+
F.lit.set(cp, b = F.font.standard ? esc2(id) : esc2(id >> 8) + esc2(id & 255));
|
|
1612
|
+
}
|
|
1613
|
+
out += b;
|
|
1614
|
+
}
|
|
1615
|
+
return out;
|
|
1616
|
+
},
|
|
1617
|
+
/**
|
|
1618
|
+
* Shaped glyphs drawn by ID (conjuncts, joined forms): [glyph ID, the text it stands for ('' for none)].
|
|
1619
|
+
* @param {string} key @param {Iterable<[number, string]>} glyphs
|
|
1620
|
+
*/
|
|
1621
|
+
addGlyphs(key, glyphs) {
|
|
1622
|
+
const F = fontOf(key);
|
|
1623
|
+
for (const [id, text] of glyphs) if (!F.glyphs.has(id)) F.glyphs.set(id, text);
|
|
1624
|
+
},
|
|
1625
|
+
/**
|
|
1626
|
+
* A name in the shared Resources dictionary for a value (an indirect ref "12 0 R" or an inline dictionary).
|
|
1627
|
+
* @param {'ExtGState'|'XObject'|'Pattern'|'Shading'|'ColorSpace'} kind @param {string} value
|
|
1628
|
+
*/
|
|
1629
|
+
resource(kind2, value, name = void 0) {
|
|
1630
|
+
let m = res.get(kind2);
|
|
1631
|
+
if (!m) res.set(kind2, m = /* @__PURE__ */ new Map());
|
|
1632
|
+
let n = m.get(value);
|
|
1633
|
+
if (!n) m.set(value, n = name || `${kind2 === "ExtGState" ? "GS" : kind2[0]}${m.size + 1}`);
|
|
1634
|
+
return n;
|
|
1635
|
+
},
|
|
1636
|
+
/**
|
|
1637
|
+
* The ExtGState name for fill and stroke opacity, named by its values (the same name in every writer: pages
|
|
1638
|
+
* painted elsewhere, parallel.js, use it too). @param {number} ca @param {number} CA
|
|
1639
|
+
*/
|
|
1640
|
+
gs: (ca, CA) => w.resource("ExtGState", `<< /Type /ExtGState /ca ${num2(ca)} /CA ${num2(CA)} >>`, `GS${num2(ca)}_${num2(CA)}`),
|
|
1641
|
+
/** What this writer's pages used, for another writer to take over (pages painted elsewhere). */
|
|
1642
|
+
used: () => ({ fonts: [...fonts].map(([key, F]) => [key, [...F.cps], [...F.glyphs]]), gs: [...res.get("ExtGState")?.keys() || []] }),
|
|
1643
|
+
/** Take over what pages painted elsewhere used (used() of their writer). @param {any} u */
|
|
1644
|
+
take(u) {
|
|
1645
|
+
for (const [key, cps, glyphs] of u.fonts) {
|
|
1646
|
+
const F = fontOf(key);
|
|
1647
|
+
for (const cp of cps) F.cps.add(cp);
|
|
1648
|
+
for (const [id, t] of glyphs) if (!F.glyphs.has(id)) F.glyphs.set(id, t);
|
|
1649
|
+
}
|
|
1650
|
+
for (const v of u.gs) {
|
|
1651
|
+
const m = (
|
|
1652
|
+
/** @type {any} */
|
|
1653
|
+
v.match(/\/ca (\S+) \/CA (\S+)/)
|
|
1654
|
+
);
|
|
1655
|
+
w.gs(Number(m[1]), Number(m[2]));
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
/**
|
|
1659
|
+
* Write an object now (an image: its dictionary and its stream, already filtered). @returns {Promise<number>} its number
|
|
1660
|
+
* @param {string} dict @param {Uint8Array} [stream]
|
|
1661
|
+
*/
|
|
1662
|
+
async object(dict, stream) {
|
|
1663
|
+
const n = reserve();
|
|
1664
|
+
await writeObj(n, dict, stream);
|
|
1665
|
+
return n;
|
|
1666
|
+
},
|
|
1667
|
+
/** An object number to write later (objectAt). */
|
|
1668
|
+
reserve: () => reserve(),
|
|
1669
|
+
/** Write a reserved object. @param {number} n @param {string} dict @param {Uint8Array} [stream] */
|
|
1670
|
+
objectAt: (n, dict, stream) => writeObj(n, dict, stream),
|
|
1671
|
+
/**
|
|
1672
|
+
* Write a reserved object whose text may be long (an array of every row's element): head, the parts as they come,
|
|
1673
|
+
* tail; written out in place, never held whole. @param {number} n @param {string} head @param {Iterable<string>} parts @param {string} tail
|
|
1674
|
+
*/
|
|
1675
|
+
async bigObject(n, head, parts2, tail) {
|
|
1676
|
+
place(n, 1, pos);
|
|
1677
|
+
await put(`${n} 0 obj
|
|
1678
|
+
${head}`);
|
|
1679
|
+
for (const x of parts2) await put(x);
|
|
1680
|
+
await put(`${tail}
|
|
1681
|
+
endobj
|
|
1682
|
+
`);
|
|
1683
|
+
},
|
|
1684
|
+
/** The object number of page i (0-based), written or not: links and outline entries may point ahead. @param {number} i */
|
|
1685
|
+
pageRef(i) {
|
|
1686
|
+
return pageRefs[i] ?? (pageRefs[i] = reserve());
|
|
1687
|
+
},
|
|
1688
|
+
/**
|
|
1689
|
+
* The total page count, drawn at the end: a Form XObject whose origin is the text's baseline at the box's left;
|
|
1690
|
+
* draw it with `q 1 0 0 1 x y cm /<name> Do Q`. align: within width.
|
|
1691
|
+
* @param {{ font: string, size: number, width: number, align?: 'left'|'center'|'right', color?: string }} o
|
|
1692
|
+
*/
|
|
1693
|
+
totalPages(o) {
|
|
1694
|
+
fontOf(o.font);
|
|
1695
|
+
const ref = reserve();
|
|
1696
|
+
totals.push({ ref, font: o.font, size: o.size, width: o.width, align: o.align || "left", color: o.color || "0 0 0" });
|
|
1697
|
+
return w.resource("XObject", `${ref} 0 R`);
|
|
1698
|
+
},
|
|
1699
|
+
/**
|
|
1700
|
+
* Write a page: its content stream (deflated) and its dictionary, now. Nothing of it stays but two offsets.
|
|
1701
|
+
* @param {{ width: number, height: number, content?: string | Uint8Array, deflated?: Uint8Array, annots?: (string | { ref: number, dict: string })[], extra?: string }} p
|
|
1702
|
+
* deflated: the content stream already compressed (zlib), as pages painted elsewhere come.
|
|
1703
|
+
* content: the page's operators (a string holds bytes 0–255, as pdf.js's Content makes). annots: annotation
|
|
1704
|
+
* dictionaries (with a reserved number: { ref, dict }). extra: more entries for the page dictionary (/StructParents 3).
|
|
1705
|
+
*/
|
|
1706
|
+
async addPage(p) {
|
|
1707
|
+
if (done) throw new Error("The PDF is finished");
|
|
1708
|
+
const i = pages++;
|
|
1709
|
+
const ref = w.pageRef(i);
|
|
1710
|
+
if (i % LEAF === 0) leaves.push(reserve());
|
|
1711
|
+
const contents = reserve(), parent = leaves[leaves.length - 1];
|
|
1712
|
+
const z = p.deflated ? Promise.resolve(p.deflated) : deflate(typeof p.content === "string" ? latin12(p.content) : p.content);
|
|
1713
|
+
z.catch(() => {
|
|
1714
|
+
});
|
|
1715
|
+
inFlight.push({ ref, contents, parent, p: { width: p.width, height: p.height, annots: p.annots, extra: p.extra }, z });
|
|
1716
|
+
while (inFlight.length > IN_FLIGHT) await writeNext();
|
|
1717
|
+
},
|
|
1718
|
+
/**
|
|
1719
|
+
* The end of the file: totals, fonts, resources, page tree, outline, catalog, Info, xref, trailer.
|
|
1720
|
+
* @param {{ outline?: OutlineEntry[], info?: { title?: string, author?: string, subject?: string, creationDate?: Date }, catalog?: string }} [o]
|
|
1721
|
+
* catalog: more entries for the catalog (the structure tree, metadata, output intents).
|
|
1722
|
+
* @returns {Promise<{ pages: number, bytes: number }>}
|
|
1723
|
+
*/
|
|
1724
|
+
async finish(o = {}) {
|
|
1725
|
+
if (done) throw new Error("The PDF is finished");
|
|
1726
|
+
if (!pages) await w.addPage({ width: 595.28, height: 841.89, content: "" });
|
|
1727
|
+
while (inFlight.length) await writeNext();
|
|
1728
|
+
done = true;
|
|
1729
|
+
for (const t of totals) {
|
|
1730
|
+
const F = fontOf(t.font), text = String(pages), hex2 = w.encode(t.font, text);
|
|
1731
|
+
let adv = 0;
|
|
1732
|
+
for (const ch of text) adv += F.font.glyphForCodePoint(
|
|
1733
|
+
/** @type {number} */
|
|
1734
|
+
ch.codePointAt(0)
|
|
1735
|
+
).advanceWidth;
|
|
1736
|
+
const tw = adv * t.size / F.font.unitsPerEm;
|
|
1737
|
+
const dx = t.align === "right" ? t.width - tw : t.align === "center" ? (t.width - tw) / 2 : 0;
|
|
1738
|
+
await writeObj(
|
|
1739
|
+
t.ref,
|
|
1740
|
+
`<< /Type /XObject /Subtype /Form /BBox [${num2(Math.min(0, dx))} ${num2(-t.size)} ${num2(Math.max(t.width, dx + tw))} ${num2(2 * t.size)}] /Resources << /Font << /${F.name} ${F.ref} 0 R >> >> /Filter /FlateDecode >>`,
|
|
1741
|
+
await deflate(latin12(`${t.color} rg BT /${F.name} ${num2(t.size)} Tf ${num2(dx)} 0 Td <${hex2}> Tj ET`))
|
|
1742
|
+
);
|
|
1743
|
+
}
|
|
1744
|
+
const fontDict = [];
|
|
1745
|
+
for (const [key, F] of fonts) {
|
|
1746
|
+
if (F.glyphs.size) {
|
|
1747
|
+
await writeFont(key, F);
|
|
1748
|
+
fontDict.push(`/${F.name} ${F.ref} 0 R`);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
let resDict = `<< /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << ${fontDict.join(" ")} >>`;
|
|
1752
|
+
for (const [kind2, m] of res) resDict += ` /${kind2} << ${[...m].map(([v, n]) => `/${n} ${v}`).join(" ")} >>`;
|
|
1753
|
+
await writeObj(resRef, resDict + " >>");
|
|
1754
|
+
let level = leaves.map((ref, k) => ({ ref, kids: pageRefs.slice(k * LEAF, Math.min(pages, (k + 1) * LEAF)), count: Math.min(LEAF, pages - k * LEAF) }));
|
|
1755
|
+
while (level.length > 1) {
|
|
1756
|
+
const up = [];
|
|
1757
|
+
for (let k = 0; k < level.length; k += LEAF) {
|
|
1758
|
+
const kids = level.slice(k, k + LEAF);
|
|
1759
|
+
up.push({ ref: reserve(), kids: kids.map((x) => x.ref), count: kids.reduce((s, x) => s + x.count, 0), below: kids });
|
|
1760
|
+
}
|
|
1761
|
+
for (const node2 of up) for (const kid of node2.below) kid.parent = node2.ref;
|
|
1762
|
+
await writeNodes(level);
|
|
1763
|
+
level = /** @type {any} */
|
|
1764
|
+
up;
|
|
1765
|
+
}
|
|
1766
|
+
await writeNodes(level);
|
|
1767
|
+
const pagesRoot = level[0].ref;
|
|
1768
|
+
const outline = await writeOutline(o.outline || []);
|
|
1769
|
+
const catalog = reserve();
|
|
1770
|
+
await writeObj(catalog, `<< /Type /Catalog /Pages ${pagesRoot} 0 R /PageLabels << /Nums [0 << /S /D /St 1 >>] >>${outline ? ` /Outlines ${outline} 0 R /PageMode /UseOutlines` : ""}${o.catalog || ""} >>`);
|
|
1771
|
+
const info = reserve(), I2 = o.info || {};
|
|
1772
|
+
await writeObj(info, `<< /Producer ${pdfText("ReportWright")} /Creator ${pdfText("ReportWright")} /Title ${pdfText(I2.title || "Report")}${I2.author ? ` /Author ${pdfText(I2.author)}` : ""}${I2.subject ? ` /Subject ${pdfText(I2.subject)}` : ""} /CreationDate ${pdfDate(I2.creationDate || /* @__PURE__ */ new Date())} /ModDate ${pdfDate(I2.creationDate || /* @__PURE__ */ new Date())} >>`);
|
|
1773
|
+
for (let n = 1; n < nextNum; n++) if (n >= kind.length || !kind[n]) await writeObj(n, "null");
|
|
1774
|
+
await writeBatch();
|
|
1775
|
+
const xn = reserve(), size2 = nextNum, xref = pos;
|
|
1776
|
+
place(xn, 1, xref);
|
|
1777
|
+
const out = (
|
|
1778
|
+
/** @type {Uint8Array[]} */
|
|
1779
|
+
[]
|
|
1780
|
+
);
|
|
1781
|
+
const zs = new Zlib({ level: 6 }, (d) => {
|
|
1782
|
+
out.push(d);
|
|
1783
|
+
});
|
|
1784
|
+
const prev = new Uint8Array(7), row = new Uint8Array(7);
|
|
1785
|
+
for (let from = 0; from < size2; from += 65536) {
|
|
1786
|
+
const to = Math.min(size2, from + 65536), rows = new Uint8Array((to - from) * 8);
|
|
1787
|
+
for (let n = from; n < to; n++) {
|
|
1788
|
+
row.fill(0);
|
|
1789
|
+
const l = loc[n];
|
|
1790
|
+
if (n === 0) {
|
|
1791
|
+
row[5] = 255;
|
|
1792
|
+
row[6] = 255;
|
|
1793
|
+
} else {
|
|
1794
|
+
row[0] = kind[n];
|
|
1795
|
+
row[1] = l >>> 24 & 255;
|
|
1796
|
+
row[2] = l >>> 16 & 255;
|
|
1797
|
+
row[3] = l >>> 8 & 255;
|
|
1798
|
+
row[4] = l & 255;
|
|
1799
|
+
if (kind[n] === 2) {
|
|
1800
|
+
row[5] = idx[n] >> 8;
|
|
1801
|
+
row[6] = idx[n] & 255;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
const at = (n - from) * 8;
|
|
1805
|
+
rows[at] = 2;
|
|
1806
|
+
for (let b = 0; b < 7; b++) {
|
|
1807
|
+
rows[at + 1 + b] = row[b] - prev[b] & 255;
|
|
1808
|
+
prev[b] = row[b];
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
zs.push(rows, to === size2);
|
|
1812
|
+
}
|
|
1813
|
+
let zn = 0;
|
|
1814
|
+
for (const c of out) zn += c.length;
|
|
1815
|
+
const z = new Uint8Array(zn);
|
|
1816
|
+
zn = 0;
|
|
1817
|
+
for (const c of out) {
|
|
1818
|
+
z.set(c, zn);
|
|
1819
|
+
zn += c.length;
|
|
1820
|
+
}
|
|
1821
|
+
const id = opt.id || [...globalThis.crypto.getRandomValues(new Uint8Array(16))].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1822
|
+
await put(`${xn} 0 obj
|
|
1823
|
+
<< /Type /XRef /Size ${size2} /W [1 4 2] /DecodeParms << /Columns 7 /Predictor 12 >> /Root ${catalog} 0 R /Info ${info} 0 R /ID [<${id}> <${id}>] /Filter /FlateDecode /Length ${z.length} >>
|
|
1824
|
+
stream
|
|
1825
|
+
`);
|
|
1826
|
+
await put(z);
|
|
1827
|
+
await put(`
|
|
1828
|
+
endstream
|
|
1829
|
+
endobj
|
|
1830
|
+
startxref
|
|
1831
|
+
${xref}
|
|
1832
|
+
%%EOF
|
|
1833
|
+
`);
|
|
1834
|
+
await flush();
|
|
1835
|
+
return { pages, bytes: pos };
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
async function writeNext() {
|
|
1839
|
+
const { ref, contents, parent, p, z } = (
|
|
1840
|
+
/** @type {any} */
|
|
1841
|
+
inFlight.shift()
|
|
1842
|
+
);
|
|
1843
|
+
await writeObj(contents, "<< /Filter /FlateDecode >>", await z);
|
|
1844
|
+
const annots = [];
|
|
1845
|
+
for (const a of p.annots || []) annots.push(typeof a === "string" ? await w.object(a) : (await writeObj(a.ref, a.dict), a.ref));
|
|
1846
|
+
await writeObj(ref, `<< /Type /Page /Parent ${parent} 0 R /MediaBox [0 0 ${num2(p.width)} ${num2(p.height)}] /Resources ${resRef} 0 R /Contents ${contents} 0 R${annots.length ? ` /Annots [${annots.map((a) => `${a} 0 R`).join(" ")}]` : ""}${p.extra || ""} >>`);
|
|
1847
|
+
}
|
|
1848
|
+
async function writeNodes(nodes) {
|
|
1849
|
+
for (const n of nodes) await writeObj(n.ref, `<< /Type /Pages${n.parent ? ` /Parent ${n.parent} 0 R` : ""} /Kids [${n.kids.map((k) => `${k} 0 R`).join(" ")}] /Count ${n.count} >>`);
|
|
1850
|
+
}
|
|
1851
|
+
async function writeFont(key, F) {
|
|
1852
|
+
if (F.font.standard) {
|
|
1853
|
+
await writeObj(F.ref, standardFontDict(F.font));
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
await loadFontkit();
|
|
1857
|
+
const f = F.font, full = (
|
|
1858
|
+
/** @type {Uint8Array} */
|
|
1859
|
+
fontStore.bytes.get(key)
|
|
1860
|
+
);
|
|
1861
|
+
let bytes = full;
|
|
1862
|
+
if (opt.subset && !f["OS/2"]?.fsType?.noSubsetting) {
|
|
1863
|
+
try {
|
|
1864
|
+
const sub = await opt.subset(full, F.cps, { glyphs: F.glyphs.keys() });
|
|
1865
|
+
const padded = new Uint8Array(sub.length + 16);
|
|
1866
|
+
padded.set(sub);
|
|
1867
|
+
const check = fontkit.create(padded);
|
|
1868
|
+
for (const id of F.glyphs.keys()) void check.getGlyph(id).advanceWidth;
|
|
1869
|
+
bytes = sub;
|
|
1870
|
+
} catch {
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
const cff = "CFF " in f.directory.tables || "CFF2" in f.directory.tables;
|
|
1874
|
+
const base = `${bytes === full ? "" : `${subsetTag(bytes)}+`}${String(f.postscriptName || "Font").replace(/[^A-Za-z0-9_.-]/g, "")}`;
|
|
1875
|
+
const k = 1e3 / f.unitsPerEm, s = (v) => String(v * k);
|
|
1876
|
+
const desc = reserve(), file = reserve(), cid = reserve(), cmap = reserve();
|
|
1877
|
+
const fileDict = cff ? "<< /Subtype /OpenType /Filter /FlateDecode >>" : `<< /Length1 ${bytes.length} /Filter /FlateDecode >>`;
|
|
1878
|
+
await writeObj(file, fileDict, await deflate(bytes));
|
|
1879
|
+
const bb = f.bbox, italic = f.italicAngle || 0;
|
|
1880
|
+
const flags = (f.post?.isFixedPitch ? 1 : 0) | 4 | (italic ? 64 : 0);
|
|
1881
|
+
await writeObj(desc, `<< /Type /FontDescriptor /FontName /${base} /Flags ${flags} /FontBBox [${s(bb.minX)} ${s(bb.minY)} ${s(bb.maxX)} ${s(bb.maxY)}] /ItalicAngle ${num2(italic)} /Ascent ${s(f.ascent)} /Descent ${s(f.descent)} /CapHeight ${s(f.capHeight || f.ascent)} /XHeight ${s(f.xHeight || 0)} /StemV 0 /${cff ? "FontFile3" : "FontFile2"} ${file} 0 R >>`);
|
|
1882
|
+
const ids = [...F.glyphs.keys()].sort((a, b) => a - b);
|
|
1883
|
+
let W = "";
|
|
1884
|
+
for (let i = 0; i < ids.length; ) {
|
|
1885
|
+
let j = i;
|
|
1886
|
+
while (j + 1 < ids.length && ids[j + 1] === ids[j] + 1) j++;
|
|
1887
|
+
W += `${ids[i]} [${ids.slice(i, j + 1).map((id) => s(f.getGlyph(id).advanceWidth)).join(" ")}] `;
|
|
1888
|
+
i = j + 1;
|
|
1889
|
+
}
|
|
1890
|
+
await writeObj(cid, `<< /Type /Font /Subtype /${cff ? "CIDFontType0" : "CIDFontType2"} /BaseFont /${base} /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor ${desc} 0 R /W [${W}]${cff ? "" : " /CIDToGIDMap /Identity"} >>`);
|
|
1891
|
+
await writeObj(cmap, "<< /Filter /FlateDecode >>", await deflate(latin12(toUnicode(F.glyphs))));
|
|
1892
|
+
await writeObj(F.ref, `<< /Type /Font /Subtype /Type0 /BaseFont /${base} /Encoding /Identity-H /DescendantFonts [${cid} 0 R] /ToUnicode ${cmap} 0 R >>`);
|
|
1893
|
+
}
|
|
1894
|
+
async function writeOutline(entries) {
|
|
1895
|
+
const root = { ref: 0, level: -1, kids: [] };
|
|
1896
|
+
const stack = [root];
|
|
1897
|
+
for (const e of entries) {
|
|
1898
|
+
if (!(e.page >= 1 && e.page <= pages)) continue;
|
|
1899
|
+
const level = Math.max(0, Math.min(9, Number(e.level) || 0));
|
|
1900
|
+
while (stack[stack.length - 1].level >= level) stack.pop();
|
|
1901
|
+
const node2 = { ref: reserve(), level, kids: [], title: e.title, dest: `[${pageRefs[e.page - 1]} 0 R ${e.top == null ? "/Fit" : `/XYZ null ${num2(e.top)} null`}]` };
|
|
1902
|
+
stack[stack.length - 1].kids.push(node2);
|
|
1903
|
+
stack.push(node2);
|
|
1904
|
+
}
|
|
1905
|
+
if (!root.kids.length) return 0;
|
|
1906
|
+
root.ref = reserve();
|
|
1907
|
+
const count = (n) => n.kids.reduce((t, c) => t + 1 + count(c), 0);
|
|
1908
|
+
const children = (n) => n.kids.length ? ` /First ${n.kids[0].ref} 0 R /Last ${n.kids[n.kids.length - 1].ref} 0 R /Count ${count(n)}` : "";
|
|
1909
|
+
const write = async (n) => {
|
|
1910
|
+
for (let i = 0; i < n.kids.length; i++) {
|
|
1911
|
+
const c = n.kids[i];
|
|
1912
|
+
await writeObj(c.ref, `<< /Title ${pdfText(c.title)} /Parent ${n.ref} 0 R /Dest ${c.dest}${i ? ` /Prev ${n.kids[i - 1].ref} 0 R` : ""}${i < n.kids.length - 1 ? ` /Next ${n.kids[i + 1].ref} 0 R` : ""}${children(c)} >>`);
|
|
1913
|
+
await write(c);
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
await write(root);
|
|
1917
|
+
await writeObj(root.ref, `<< /Type /Outlines${children(root)} >>`);
|
|
1918
|
+
return root.ref;
|
|
1919
|
+
}
|
|
1920
|
+
return w;
|
|
1921
|
+
}
|
|
1922
|
+
function toUnicode(glyphs) {
|
|
1923
|
+
const entries = [...glyphs].filter(([, t]) => t).sort((a, b) => a[0] - b[0]);
|
|
1924
|
+
let body = "";
|
|
1925
|
+
for (let i = 0; i < entries.length; i += 100) {
|
|
1926
|
+
const chunk = entries.slice(i, i + 100);
|
|
1927
|
+
body += `${chunk.length} beginbfchar
|
|
1928
|
+
${chunk.map(([id, t]) => `<${hex42(id)}> <${utf16(t)}>`).join("\n")}
|
|
1929
|
+
endbfchar
|
|
1930
|
+
`;
|
|
1931
|
+
}
|
|
1932
|
+
return `/CIDInit /ProcSet findresource begin
|
|
1933
|
+
12 dict begin
|
|
1934
|
+
begincmap
|
|
1935
|
+
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
|
|
1936
|
+
/CMapName /Adobe-Identity-UCS def
|
|
1937
|
+
/CMapType 2 def
|
|
1938
|
+
1 begincodespacerange
|
|
1939
|
+
<0000> <ffff>
|
|
1940
|
+
endcodespacerange
|
|
1941
|
+
${body}endcmap
|
|
1942
|
+
CMapName currentdict /CMap defineresource pop
|
|
1943
|
+
end
|
|
1944
|
+
end
|
|
1945
|
+
`;
|
|
1946
|
+
}
|
|
1947
|
+
var utf16 = (t) => {
|
|
1948
|
+
let h = "";
|
|
1949
|
+
for (let i = 0; i < t.length; i++) h += hex42(t.charCodeAt(i));
|
|
1950
|
+
return h;
|
|
1951
|
+
};
|
|
1952
|
+
var pdfText = (t) => `<feff${utf16(String(t ?? ""))}>`;
|
|
1953
|
+
var pdfDate = (d) => `(D:${d.toISOString().replace(/\D/g, "").slice(0, 14)}+00'00')`;
|
|
1954
|
+
function subsetTag(bytes) {
|
|
1955
|
+
let h = 2166136261;
|
|
1956
|
+
for (let i = 0; i < bytes.length; i++) h = Math.imul(h ^ bytes[i], 16777619);
|
|
1957
|
+
let tag = "";
|
|
1958
|
+
for (let i = 0; i < 6; i++) {
|
|
1959
|
+
tag += String.fromCharCode(65 + (h >>> 0) % 26);
|
|
1960
|
+
h = Math.imul(h ^ i, 16777619) >>> 0;
|
|
1961
|
+
}
|
|
1962
|
+
return tag;
|
|
1963
|
+
}
|
|
1964
|
+
function latin12(s) {
|
|
1965
|
+
const B = (
|
|
1966
|
+
/** @type {any} */
|
|
1967
|
+
globalThis.Buffer
|
|
1968
|
+
);
|
|
1969
|
+
if (B) return B.from(s, "latin1");
|
|
1970
|
+
const out = new Uint8Array(s.length);
|
|
1971
|
+
for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);
|
|
1972
|
+
return out;
|
|
1973
|
+
}
|
|
1974
|
+
async function writePagedPdf(plan2, opts, sink) {
|
|
1975
|
+
const { fontStore } = opts;
|
|
1976
|
+
if (opts.pdfa || opts.tagged) await fontStore.load(standIns(fontStore));
|
|
1977
|
+
const w = createPdfStream(sink, { fontStore, subset: opts.subset, id: opts.id, signal: opts.signal });
|
|
1978
|
+
const { info, pages } = (
|
|
1979
|
+
/** @type {any} */
|
|
1980
|
+
plan2
|
|
1981
|
+
);
|
|
1982
|
+
const tags = opts.tagged ? createStreamTagger(w, { maxElements: Number(opts.tagged.maxElements) || Infinity }) : null;
|
|
1983
|
+
const env = paintEnv(w, fontStore, { drillBase: opts.drillBase, tags, embedAll: !!(opts.pdfa || tags) });
|
|
1984
|
+
const { shaped } = env;
|
|
1985
|
+
const pool = !tags && Number(opts.parallel) > 1 ? paintPool(Number(opts.parallel), fontStore, opts, info) : null;
|
|
1986
|
+
let pi = -1;
|
|
1987
|
+
const it = pages(pool ? { run: pool.run, parallel: pool.size } : {})[Symbol.asyncIterator]();
|
|
1988
|
+
let pending = false;
|
|
1989
|
+
try {
|
|
1990
|
+
for (; ; ) {
|
|
1991
|
+
opts.signal?.throwIfAborted();
|
|
1992
|
+
pending = true;
|
|
1993
|
+
const x = await raced(it.next(), opts.signal);
|
|
1994
|
+
pending = false;
|
|
1995
|
+
if (x.done) break;
|
|
1996
|
+
const pg = x.value;
|
|
1997
|
+
pi++;
|
|
1998
|
+
const H = pg.height ?? info.height;
|
|
1999
|
+
if (pg.deflated) {
|
|
2000
|
+
for (const f of pg.embedded || []) env.embedded?.add(f);
|
|
2001
|
+
if (pg.used) {
|
|
2002
|
+
w.take(pg.used);
|
|
2003
|
+
for (const [k, g] of pg.shaped) {
|
|
2004
|
+
const m = env.shapedOf(k);
|
|
2005
|
+
for (const [id, t] of g) if (!m.has(id)) m.set(id, t);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
const annots2 = pg.annots.map((a) => a.replace(/@@P(\d+)@@/g, (_, i) => String(w.pageRef(Number(i)))));
|
|
2009
|
+
await w.addPage({ width: pg.width ?? info.width, height: H, deflated: pg.deflated, annots: annots2 });
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const { content, annots } = paintPage(pg, H, env);
|
|
2013
|
+
await w.addPage({ width: pg.width ?? info.width, height: H, content, annots, extra: tags ? await tags.end(w.pageRef(pi)) : void 0 });
|
|
2014
|
+
}
|
|
2015
|
+
} finally {
|
|
2016
|
+
if (pending) it.return?.(void 0)?.catch(() => {
|
|
2017
|
+
});
|
|
2018
|
+
else await it.return?.(void 0);
|
|
2019
|
+
await pool?.close();
|
|
2020
|
+
}
|
|
2021
|
+
for (const [key, g] of shaped) w.addGlyphs(key, g);
|
|
2022
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2023
|
+
const outline = [...info.bookmarks, ...info.headings].map((b, i) => ({ b, i })).sort((p, q) => p.b.page - q.b.page || (p.b.y ?? 0) - (q.b.y ?? 0) || p.i - q.i).map(({ b }) => b).filter((b) => {
|
|
2024
|
+
const k = `${b.page}|${Math.round(b.y ?? 0)}|${b.label}`;
|
|
2025
|
+
if (seen.has(k)) return false;
|
|
2026
|
+
seen.add(k);
|
|
2027
|
+
return true;
|
|
2028
|
+
}).map((b) => ({ title: b.label, page: b.page, top: info.height - b.y + 4, level: b.level }));
|
|
2029
|
+
const title = opts.title || "Report", when = new Date(Math.floor((opts.creationDate || /* @__PURE__ */ new Date()).getTime() / 1e3) * 1e3);
|
|
2030
|
+
let catalog = tags ? await tags.finish({ lang: opts.tagged.lang }) : "";
|
|
2031
|
+
if (opts.pdfa || tags) {
|
|
2032
|
+
const xmp = new TextEncoder().encode(xmpPacket({ title, author: opts.author, stamp: when.toISOString().replace(".000Z", "Z"), pdfa: opts.pdfa ? tags ? "A" : "B" : null, ua: !!tags }));
|
|
2033
|
+
catalog += ` /Metadata ${await w.object("<< /Type /Metadata /Subtype /XML >>", xmp)} 0 R`;
|
|
2034
|
+
}
|
|
2035
|
+
if (opts.pdfa) {
|
|
2036
|
+
const icc = await w.object("<< /N 3 /Filter /FlateDecode >>", await deflate(opts.pdfa.icc));
|
|
2037
|
+
catalog += ` /OutputIntents [${await w.object(`<< /Type /OutputIntent /S /GTS_PDFA1 /OutputConditionIdentifier (sRGB) /Info (sRGB IEC61966-2.1) /DestOutputProfile ${icc} 0 R >>`)} 0 R]`;
|
|
2038
|
+
}
|
|
2039
|
+
const res = await w.finish({ outline, catalog, info: { title, author: opts.author, creationDate: when } });
|
|
2040
|
+
for (const x of env.embedded ? embeddedWarnings(env.embedded) : []) info.warnings.push(x);
|
|
2041
|
+
if (tags && tags.count > TAGGED_LARGE) info.warnings.push(`The tagged PDF has ${tags.count.toLocaleString("en-US")} structure elements (${res.pages.toLocaleString("en-US")} pages): readers open it, but tools that load every object of a file (qpdf, pikepdf) may run out of memory on it. tagged.maxElements caps it.`);
|
|
2042
|
+
return { pages: res.pages, warnings: info.warnings };
|
|
2043
|
+
}
|
|
2044
|
+
var lit = (v) => `(${String(v).replace(/[\\()]/g, "\\$&")})`;
|
|
2045
|
+
function coveredText(items, box) {
|
|
2046
|
+
const lines = [];
|
|
2047
|
+
for (const t of items) if (t.t === "text" && t.lines) {
|
|
2048
|
+
for (const l of t.lines) if (l.text?.trim() && l.x >= box.x && l.x <= box.x + box.w && l.y >= box.y && l.y <= box.y + box.h) lines.push(l);
|
|
2049
|
+
}
|
|
2050
|
+
return lines.sort((a, b) => a.y - b.y || a.x - b.x).map((l) => l.text.trim()).join(" ");
|
|
2051
|
+
}
|
|
2052
|
+
function paintPage(pg, H, env) {
|
|
2053
|
+
if (env.embedded) pg = embeddedPage(pg, env.font, env.embedded);
|
|
2054
|
+
const annots = [];
|
|
2055
|
+
const c = new Content(env.shared);
|
|
2056
|
+
const { tags } = env;
|
|
2057
|
+
if (tags) {
|
|
2058
|
+
c.tagged = true;
|
|
2059
|
+
c.artLines = true;
|
|
2060
|
+
tags.page(pg.win ?? 0);
|
|
2061
|
+
}
|
|
2062
|
+
for (const it of pg.items) {
|
|
2063
|
+
const mark = tags && it.t !== "line" && tags.open(it);
|
|
2064
|
+
const inText = mark && it.t === "text" && !it.rotate && it.lines.every((l) => !l.runs) && !(it.clip && !insideClip(it, env.vmetrics(it.font)));
|
|
2065
|
+
if (inText) {
|
|
2066
|
+
if (!c.bt) {
|
|
2067
|
+
c._s += "BT\n";
|
|
2068
|
+
c.bt = true;
|
|
2069
|
+
c.tx = 0;
|
|
2070
|
+
c.ty = 0;
|
|
2071
|
+
}
|
|
2072
|
+
c._s += mark;
|
|
2073
|
+
} else if (mark) {
|
|
2074
|
+
c.et();
|
|
2075
|
+
c.s += mark;
|
|
2076
|
+
}
|
|
2077
|
+
if (it.t !== "text" && it.t !== "line" || it.rotate) c.et();
|
|
2078
|
+
if (it.rotate) {
|
|
2079
|
+
const t = -it.rotate.a * Math.PI / 180, cs = Math.cos(t), sn = Math.sin(t);
|
|
2080
|
+
const px = it.rotate.cx, py = H - it.rotate.cy;
|
|
2081
|
+
c.q();
|
|
2082
|
+
c.s += `${n4(cs)} ${n4(sn)} ${n4(-sn)} ${n4(cs)} ${n2(px - px * cs + py * sn)} ${n2(py - px * sn - py * cs)} cm
|
|
2083
|
+
`;
|
|
2084
|
+
}
|
|
2085
|
+
switch (it.t) {
|
|
2086
|
+
case "rect": {
|
|
2087
|
+
const fill = col(it.fill), stroke = col(it.stroke);
|
|
2088
|
+
if (!fill && !stroke) break;
|
|
2089
|
+
if (it.radius) throw new Error("rounded boxes do not stream yet");
|
|
2090
|
+
c.paint(fill, stroke, it.strokeWidth || 1, it.dash);
|
|
2091
|
+
const x = n2(it.x), y = n2(H - it.y - it.h), rw = n2(it.w), rh = n2(it.h);
|
|
2092
|
+
c.s += (stroke && it.dash?.length ? `${x} ${y} m ${x} ${n2(y + rh)} l ${n2(x + rw)} ${n2(y + rh)} l ${n2(x + rw)} ${y} l h` : `${x} ${y} ${rw} ${rh} re`) + (fill && stroke ? " B\n" : fill ? " f\n" : " S\n");
|
|
2093
|
+
break;
|
|
2094
|
+
}
|
|
2095
|
+
case "ellipse": {
|
|
2096
|
+
const fill = col(it.fill), stroke = col(it.stroke);
|
|
2097
|
+
if (!fill && !stroke) break;
|
|
2098
|
+
c.paint(fill, stroke, it.strokeWidth || 1, it.dash);
|
|
2099
|
+
const cx = it.cx, cy = H - it.cy, rx = it.rx, ry = it.ry, ox = rx * KAPPA, oy = ry * KAPPA;
|
|
2100
|
+
c.s += `${n2(cx - rx)} ${n2(cy)} m ${n2(cx - rx)} ${n2(cy - oy)} ${n2(cx - ox)} ${n2(cy - ry)} ${n2(cx)} ${n2(cy - ry)} c ${n2(cx + ox)} ${n2(cy - ry)} ${n2(cx + rx)} ${n2(cy - oy)} ${n2(cx + rx)} ${n2(cy)} c ${n2(cx + rx)} ${n2(cy + oy)} ${n2(cx + ox)} ${n2(cy + ry)} ${n2(cx)} ${n2(cy + ry)} c ${n2(cx - ox)} ${n2(cy + ry)} ${n2(cx - rx)} ${n2(cy + oy)} ${n2(cx - rx)} ${n2(cy)} c h ${fill &&
|
|
2101
|
+
stroke ? "B" : fill ? "f" : "S"}
|
|
2102
|
+
`;
|
|
2103
|
+
break;
|
|
2104
|
+
}
|
|
2105
|
+
case "line": {
|
|
2106
|
+
const st = col(it.stroke);
|
|
2107
|
+
if (st) c.line(st, it.strokeWidth || 1, it.dash, it.x1, H - it.y1, it.x2, H - it.y2);
|
|
2108
|
+
break;
|
|
2109
|
+
}
|
|
2110
|
+
case "text": {
|
|
2111
|
+
const color = col(it.color) || BLACK;
|
|
2112
|
+
const clipped = it.clip && !insideClip(it, env.vmetrics(it.font));
|
|
2113
|
+
if (clipped) {
|
|
2114
|
+
c.q();
|
|
2115
|
+
c.s += `${n2(it.clip.x)} ${n2(H - it.clip.y - it.clip.h)} ${n2(it.clip.w)} ${n2(it.clip.h)} re W n
|
|
2116
|
+
`;
|
|
2117
|
+
}
|
|
2118
|
+
for (const l of it.lines) {
|
|
2119
|
+
if (!l.runs) {
|
|
2120
|
+
c.text(env.pf(it.font), it.size, color, l.x, H - l.y, env.literal(it.font, cleanText(l.text)));
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
for (const r of l.runs) {
|
|
2124
|
+
const g = env.shapedOf(r.font), spans = /* @__PURE__ */ new WeakMap();
|
|
2125
|
+
glyphText(r, env.font(r.font), g, spans);
|
|
2126
|
+
if (r.text.trim()) drawRun(c, r, l.x + r.x, H - l.y, it.size, env.pf(r.font), color, spans.get(r), g);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
if (clipped) c.Q();
|
|
2130
|
+
break;
|
|
2131
|
+
}
|
|
2132
|
+
case "link": {
|
|
2133
|
+
const rect = `[${[it.x, H - it.y - it.h, it.x + it.w, H - it.y].map(n2).join(" ")}]`;
|
|
2134
|
+
const a = it.action;
|
|
2135
|
+
const href = a?.type === "url" && safeUrl(a.href) ? a.href : a?.type === "drill" ? drillUrl(env.drillBase, a) : null;
|
|
2136
|
+
const to = href ? `/A << /Type /Action /S /URI /URI ${lit(asciiUrl(href))} >>` : a?.type === "bookmark" && a.page ? `/Dest [${env.pageRef(a.page - 1)} 0 R /XYZ null ${n2(H - a.y + 4)} null]` : null;
|
|
2137
|
+
if (!to) break;
|
|
2138
|
+
if (!tags) {
|
|
2139
|
+
annots.push(`<< /Type /Annot /Subtype /Link /F 4 /Rect ${rect} /Border [0 0 0] ${to} >>`);
|
|
2140
|
+
break;
|
|
2141
|
+
}
|
|
2142
|
+
const ref = env.reserve(), key = tags.link(it, ref);
|
|
2143
|
+
const say = coveredText(pg.items, it) || it.tip || href || (a.target ? `Go to ${a.target}` : `Go to page ${a.page}`);
|
|
2144
|
+
annots.push({ ref, dict: `<< /Type /Annot /Subtype /Link /F 4 /Rect ${rect} /Border [0 0 0] ${to} /Contents ${pdfText(say)} /StructParent ${key} >>` });
|
|
2145
|
+
break;
|
|
2146
|
+
}
|
|
2147
|
+
default:
|
|
2148
|
+
throw new Error(`A ${it.t} item does not stream yet`);
|
|
2149
|
+
}
|
|
2150
|
+
if (it.rotate) c.Q();
|
|
2151
|
+
if (inText) c._s += "EMC\n";
|
|
2152
|
+
else if (mark) {
|
|
2153
|
+
c.et();
|
|
2154
|
+
c.s += "EMC\n";
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
c.et();
|
|
2158
|
+
return { content: c.s, annots };
|
|
2159
|
+
}
|
|
2160
|
+
function paintEnv(w, fontStore, o = {}) {
|
|
2161
|
+
const pfs = /* @__PURE__ */ new Map();
|
|
2162
|
+
const shaped = /* @__PURE__ */ new Map();
|
|
2163
|
+
const vm = /* @__PURE__ */ new Map();
|
|
2164
|
+
return {
|
|
2165
|
+
shared: { font: (f) => w.fontName(f.key), gs: (ca, CA) => w.gs(ca, CA), image: () => {
|
|
2166
|
+
throw new Error("images do not stream yet");
|
|
2167
|
+
} },
|
|
2168
|
+
pf: (key) => {
|
|
2169
|
+
let f = pfs.get(key);
|
|
2170
|
+
if (!f) pfs.set(key, f = { key, embedder: { font: fontStore.get(key) } });
|
|
2171
|
+
return f;
|
|
2172
|
+
},
|
|
2173
|
+
font: (key) => fontStore.get(key),
|
|
2174
|
+
shaped,
|
|
2175
|
+
shapedOf: (key) => {
|
|
2176
|
+
let g = shaped.get(key);
|
|
2177
|
+
if (!g) shaped.set(key, g = /* @__PURE__ */ new Map());
|
|
2178
|
+
return g;
|
|
2179
|
+
},
|
|
2180
|
+
vmetrics: (key) => {
|
|
2181
|
+
let m = vm.get(key);
|
|
2182
|
+
if (!m) {
|
|
2183
|
+
const f = fontStore.get(key), u = f?.unitsPerEm || 1e3;
|
|
2184
|
+
vm.set(key, m = { asc: (f?.ascent ?? u) / u, desc: -(f?.descent ?? 0) / u });
|
|
2185
|
+
}
|
|
2186
|
+
return m;
|
|
2187
|
+
},
|
|
2188
|
+
literal: (key, text) => w.literal(key, text),
|
|
2189
|
+
pageRef: o.pageRef || ((i) => w.pageRef(i)),
|
|
2190
|
+
reserve: () => w.reserve(),
|
|
2191
|
+
drillBase: o.drillBase,
|
|
2192
|
+
tags: o.tags || null,
|
|
2193
|
+
/** PDF/A, PDF/UA: standard fonts drawn in embedded stand-ins; the families that were @type {Set<string>|null} */
|
|
2194
|
+
embedded: o.embedAll ? /* @__PURE__ */ new Set() : null
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
function paintPool(size, fontStore, opts, info) {
|
|
2198
|
+
const wt = (
|
|
2199
|
+
/** @type {any} */
|
|
2200
|
+
globalThis.process?.getBuiltinModule?.("node:worker_threads")
|
|
2201
|
+
);
|
|
2202
|
+
if (!wt) return null;
|
|
2203
|
+
let workers = [];
|
|
2204
|
+
let seq = 0, turn = 0;
|
|
2205
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
2206
|
+
const clean = (r) => {
|
|
2207
|
+
if (!r) return r;
|
|
2208
|
+
const { __i, ...o } = r;
|
|
2209
|
+
return o;
|
|
2210
|
+
};
|
|
2211
|
+
const start = async () => {
|
|
2212
|
+
const fonts = [...fontStore.bytes];
|
|
2213
|
+
if (fontStore.shaper) fonts.push(["harfbuzz", await fontStore.loader("harfbuzz")]);
|
|
2214
|
+
workers = Array.from({ length: size }, () => {
|
|
2215
|
+
const w = new wt.Worker(new URL("./pdfstreamworker.js", import.meta.url), { workerData: { fonts } });
|
|
2216
|
+
w.on("message", (m) => {
|
|
2217
|
+
const p = waiting.get(m.id);
|
|
2218
|
+
waiting.delete(m.id);
|
|
2219
|
+
if (m.error) p.fail(Object.assign(new Error(m.error.message), { status: m.error.status, timeout: m.error.timeout }));
|
|
2220
|
+
else p.ok(m);
|
|
2221
|
+
});
|
|
2222
|
+
w.on("error", (e) => {
|
|
2223
|
+
for (const p of waiting.values()) p.fail(e);
|
|
2224
|
+
waiting.clear();
|
|
2225
|
+
});
|
|
2226
|
+
return w;
|
|
2227
|
+
});
|
|
2228
|
+
};
|
|
2229
|
+
let started = null;
|
|
2230
|
+
const pick = ["parameters", "now", "timeZone", "state", "target", "deadline", "timeoutMs"];
|
|
2231
|
+
return {
|
|
2232
|
+
size,
|
|
2233
|
+
/** @param {any} job */
|
|
2234
|
+
async run(job) {
|
|
2235
|
+
await (started || (started = start()));
|
|
2236
|
+
const id = ++seq;
|
|
2237
|
+
const pw = job.pageWindow;
|
|
2238
|
+
const msg = {
|
|
2239
|
+
id,
|
|
2240
|
+
def: job.def,
|
|
2241
|
+
rows: job.rows.map(clean),
|
|
2242
|
+
keep: job.keep,
|
|
2243
|
+
drillBase: opts.drillBase,
|
|
2244
|
+
embedAll: !!opts.pdfa,
|
|
2245
|
+
height: info.height,
|
|
2246
|
+
opts: Object.fromEntries(pick.filter((k) => opts[k] !== void 0).map((k) => [k, opts[k]])),
|
|
2247
|
+
pageWindow: { ...pw, first: clean(pw.first), cont: pw.cont.map((c) => c && { first: clean(c.first), before: c.before }) }
|
|
2248
|
+
};
|
|
2249
|
+
const r = await new Promise((ok, fail) => {
|
|
2250
|
+
waiting.set(id, { ok, fail });
|
|
2251
|
+
workers[turn++ % workers.length].postMessage(msg);
|
|
2252
|
+
});
|
|
2253
|
+
if (r.pages.length) {
|
|
2254
|
+
r.pages[0].used = r.used;
|
|
2255
|
+
r.pages[0].shaped = r.shaped;
|
|
2256
|
+
r.pages[0].embedded = r.embedded;
|
|
2257
|
+
}
|
|
2258
|
+
return r;
|
|
2259
|
+
},
|
|
2260
|
+
async close() {
|
|
2261
|
+
await Promise.all(workers.map((w) => w.terminate()));
|
|
2262
|
+
}
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
|
|
1084
2266
|
// src/exporters/pdf.js
|
|
1085
|
-
var fontkit = (
|
|
1086
|
-
/** @type {any} */
|
|
1087
|
-
fontkitModule.default || fontkitModule
|
|
1088
|
-
);
|
|
1089
2267
|
function exportPdf(model, fontStore, opt = {}) {
|
|
1090
2268
|
return withDeadline(
|
|
1091
2269
|
pdfOf(model, fontStore, opt),
|
|
@@ -1094,6 +2272,8 @@ function exportPdf(model, fontStore, opt = {}) {
|
|
|
1094
2272
|
);
|
|
1095
2273
|
}
|
|
1096
2274
|
async function pdfOf(model, fontStore, opt) {
|
|
2275
|
+
if (ownWriterFits(model, opt)) return ownWriter(model, fontStore, opt);
|
|
2276
|
+
await loadPdfLib();
|
|
1097
2277
|
const fixed = fixedDate(opt);
|
|
1098
2278
|
const when = fixed ?? /* @__PURE__ */ new Date();
|
|
1099
2279
|
const fileId = fixed ? await contentId(model, opt, when) : void 0;
|
|
@@ -1104,7 +2284,13 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1104
2284
|
doc.setCreator("ReportWright");
|
|
1105
2285
|
if (opt.author) doc.setAuthor(opt.author);
|
|
1106
2286
|
setInfoDates(doc, when);
|
|
1107
|
-
if (fileId) doc.context.trailerInfo.ID = doc.context.obj([
|
|
2287
|
+
if (fileId) doc.context.trailerInfo.ID = doc.context.obj([PDFHexString.of(fileId), PDFHexString.of(fileId)]);
|
|
2288
|
+
if (opt.pdfa || opt.tagged || model.pages.some((pg) => pg.items.some((i) => i.t === "field"))) await fontStore.load(standIns(fontStore));
|
|
2289
|
+
if (opt.pdfa || opt.tagged) {
|
|
2290
|
+
const families = /* @__PURE__ */ new Set();
|
|
2291
|
+
model = { ...model, pages: model.pages.map((pg) => embeddedPage(pg, (k) => fontStore.get(k), families)) };
|
|
2292
|
+
for (const w of embeddedWarnings(families)) opt.onWarning?.(w);
|
|
2293
|
+
}
|
|
1108
2294
|
const used = /* @__PURE__ */ new Map();
|
|
1109
2295
|
const shaped = /* @__PURE__ */ new Map();
|
|
1110
2296
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
@@ -1145,6 +2331,13 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1145
2331
|
for (const pg of model.pages) for (const it of pg.items) if (it.t === "field") fieldFonts.add(fieldFont(it));
|
|
1146
2332
|
const fonts = /* @__PURE__ */ new Map();
|
|
1147
2333
|
const font = async (key) => {
|
|
2334
|
+
if (!fonts.has(key) && isStandard(key)) {
|
|
2335
|
+
const f = fontStore.get(key);
|
|
2336
|
+
fonts.set(key, { ref: doc.context.register(doc.context.obj(
|
|
2337
|
+
/** @type {any} */
|
|
2338
|
+
standardFontEntries(f)
|
|
2339
|
+
)), embedder: { font: f, literalOf: (t) => standardLiteral(f, t), tjOf: () => null } });
|
|
2340
|
+
}
|
|
1148
2341
|
if (!fonts.has(key)) {
|
|
1149
2342
|
const full = fontStore.bytes.get(key);
|
|
1150
2343
|
let bytes = full;
|
|
@@ -1161,14 +2354,14 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1161
2354
|
} catch {
|
|
1162
2355
|
}
|
|
1163
2356
|
}
|
|
1164
|
-
const pf = await doc.embedFont(bytes, { subset: false, customName: bytes === full ? void 0 : `${
|
|
2357
|
+
const pf = await doc.embedFont(bytes, { subset: false, customName: bytes === full ? void 0 : `${subsetTag2(bytes)}+${fontStore.get(key).postscriptName || "Font"}` });
|
|
1165
2358
|
plainEncoding(pf);
|
|
1166
2359
|
if (glyphs) addGlyphs(pf, glyphs, !!opt.tagged);
|
|
1167
2360
|
const file = bytes, e = (
|
|
1168
2361
|
/** @type {any} */
|
|
1169
2362
|
pf.embedder
|
|
1170
2363
|
);
|
|
1171
|
-
if (!e.isCFF()) e.embedFontStream = async (c) => c.register(
|
|
2364
|
+
if (!e.isCFF()) e.embedFontStream = async (c) => c.register(PDFRawStream.of(c.obj({ Filter: "FlateDecode", Length1: file.length }), await deflate(file)));
|
|
1172
2365
|
fonts.set(key, pf);
|
|
1173
2366
|
}
|
|
1174
2367
|
return fonts.get(key);
|
|
@@ -1209,7 +2402,7 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1209
2402
|
if (!n) {
|
|
1210
2403
|
n = `${kind[0]}${names.size + 1}`;
|
|
1211
2404
|
names.set(key, n);
|
|
1212
|
-
res.get(
|
|
2405
|
+
res.get(PDFName.of(kind)).set(PDFName.of(n), value());
|
|
1213
2406
|
}
|
|
1214
2407
|
return n;
|
|
1215
2408
|
};
|
|
@@ -1244,7 +2437,7 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1244
2437
|
const H = pg.height ?? model.height;
|
|
1245
2438
|
const p = doc.addPage([pg.width ?? model.width, H]);
|
|
1246
2439
|
p.node.normalize();
|
|
1247
|
-
p.node.set(
|
|
2440
|
+
p.node.set(PDFName.of("Resources"), resRef);
|
|
1248
2441
|
const c = new Content(shared);
|
|
1249
2442
|
if (tags) c.tagged = true;
|
|
1250
2443
|
p.maybeEmbedGraphicsState = (o) => c.gsFor(o.opacity ?? 1, o.borderOpacity ?? 1);
|
|
@@ -1351,7 +2544,7 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1351
2544
|
const form = doc.getForm();
|
|
1352
2545
|
const f = await font(fieldFont(it));
|
|
1353
2546
|
const name = uniqueName(it.name);
|
|
1354
|
-
const box = { x: it.x, y: H - it.y - it.h, width: it.w, height: it.h, borderColor:
|
|
2547
|
+
const box = { x: it.x, y: H - it.y - it.h, width: it.w, height: it.h, borderColor: rgb(0.61, 0.64, 0.69), borderWidth: 0.75, backgroundColor: rgb(1, 1, 1) };
|
|
1355
2548
|
let field;
|
|
1356
2549
|
if (it.kind === "checkbox") {
|
|
1357
2550
|
field = form.createCheckBox(name);
|
|
@@ -1408,7 +2601,8 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1408
2601
|
if (it.required) field.enableRequired();
|
|
1409
2602
|
if (it.readOnly) field.enableReadOnly();
|
|
1410
2603
|
if (tags) {
|
|
1411
|
-
|
|
2604
|
+
if (!it.label) opt.onWarning?.(`Form field "${name}" has no label, so a screen reader announces its name; give it a label`);
|
|
2605
|
+
field.acroField.dict.set(PDFName.of("TU"), PDFHexString.fromText(it.label || it.name || name));
|
|
1412
2606
|
const w = field.acroField.getWidgets()[0];
|
|
1413
2607
|
const ref2 = w && doc.context.getObjectRef(w.dict);
|
|
1414
2608
|
if (ref2) tags.annot(pi, ii, ref2, "field");
|
|
@@ -1417,7 +2611,7 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1417
2611
|
}
|
|
1418
2612
|
case "link": {
|
|
1419
2613
|
const rect = [it.x, H - it.y - it.h, it.x + it.w, H - it.y];
|
|
1420
|
-
const text = tags ?
|
|
2614
|
+
const text = tags ? coveredText2(pg.items, it) : "";
|
|
1421
2615
|
if (it.action?.type === "url" && safeUrl(it.action.href)) links.push({ page: p, rect, href: it.action.href, pi, ii, tip: it.tip, text });
|
|
1422
2616
|
else if (it.action?.type === "drill") {
|
|
1423
2617
|
const href = drillUrl(opt.drillBase, it.action);
|
|
@@ -1470,24 +2664,24 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1470
2664
|
);
|
|
1471
2665
|
if (own) ctx.delete(own);
|
|
1472
2666
|
const ref = ctx.nextRef();
|
|
1473
|
-
p.node.set(
|
|
1474
|
-
contents.push(deflate(latin1(c.s)).then((z) => ctx.assign(ref,
|
|
2667
|
+
p.node.set(PDFName.of("Contents"), ref);
|
|
2668
|
+
contents.push(deflate(latin1(c.s)).then((z) => ctx.assign(ref, PDFRawStream.of(ctx.obj({ Filter: "FlateDecode" }), z))));
|
|
1475
2669
|
if (NODE_ZLIB && contents.length > 8) await contents[contents.length - 9];
|
|
1476
2670
|
}
|
|
1477
2671
|
await Promise.all(contents);
|
|
1478
2672
|
const pageH = (n) => model.pages[n - 1]?.height ?? model.height;
|
|
1479
2673
|
const pages = doc.getPages();
|
|
1480
|
-
const dest = (b) => pages[b.page - 1] && [pages[b.page - 1].ref,
|
|
2674
|
+
const dest = (b) => pages[b.page - 1] && [pages[b.page - 1].ref, PDFName.of("XYZ"), null, pageH(b.page) - b.y + 4, null];
|
|
1481
2675
|
for (const l of links) {
|
|
1482
2676
|
const to = l.href ? { A: { Type: "Action", S: "URI", URI: pdfLiteral(asciiUrl(l.href)) } } : { Dest: dest(l.to) };
|
|
1483
2677
|
if (!l.href && !to.Dest) continue;
|
|
1484
2678
|
const annot = doc.context.obj({ Type: "Annot", Subtype: "Link", F: 4, Rect: l.rect, Border: [0, 0, 0], ...to });
|
|
1485
|
-
if (tags) annot.set(
|
|
2679
|
+
if (tags) annot.set(PDFName.of("Contents"), PDFHexString.fromText(String(l.text || l.tip || l.href || "Link")));
|
|
1486
2680
|
const ref = doc.context.register(annot);
|
|
1487
2681
|
if (tags) tags.annot(l.pi, l.ii, ref, "link");
|
|
1488
|
-
const annots = l.page.node.lookup(
|
|
2682
|
+
const annots = l.page.node.lookup(PDFName.of("Annots"));
|
|
1489
2683
|
if (annots) annots.push(ref);
|
|
1490
|
-
else l.page.node.set(
|
|
2684
|
+
else l.page.node.set(PDFName.of("Annots"), doc.context.obj([ref]));
|
|
1491
2685
|
}
|
|
1492
2686
|
const marks = outlineEntries(model);
|
|
1493
2687
|
if (marks.length) addOutline(doc, marks, dest);
|
|
@@ -1504,7 +2698,44 @@ async function pdfOf(model, fontStore, opt) {
|
|
|
1504
2698
|
}
|
|
1505
2699
|
return doc.save({ updateFieldAppearances: false, ...opt.save || {} });
|
|
1506
2700
|
}
|
|
1507
|
-
function
|
|
2701
|
+
function ownWriterFits(model, opt) {
|
|
2702
|
+
if (opt.pdfa || opt.tagged || opt.encrypt || opt.prepare || opt.save || !model.pages.length) return false;
|
|
2703
|
+
if ((model.pageStarts || []).some((i) => i > 0)) return false;
|
|
2704
|
+
for (const pg of model.pages) {
|
|
2705
|
+
if ((pg.height ?? model.height) !== model.height) return false;
|
|
2706
|
+
for (const it of pg.items) {
|
|
2707
|
+
if (it.t === "text") {
|
|
2708
|
+
if (!isStandard(it.font) || it.lines.some((l) => l.runs)) return false;
|
|
2709
|
+
} else if (it.t === "link") {
|
|
2710
|
+
const a = it.action;
|
|
2711
|
+
if (a?.type === "bookmark" && !(a.page >= 1 && a.page <= model.pages.length)) return false;
|
|
2712
|
+
} else if (!(it.t === "line" || it.t === "ellipse" || it.t === "rect" && !it.radius)) return false;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
return true;
|
|
2716
|
+
}
|
|
2717
|
+
async function ownWriter(model, fontStore, opt) {
|
|
2718
|
+
const fixed = fixedDate(opt), when = fixed ?? /* @__PURE__ */ new Date();
|
|
2719
|
+
const parts = [];
|
|
2720
|
+
const info = { width: model.width, height: model.height, bookmarks: model.bookmarks || [], headings: model.headings || [], warnings: [] };
|
|
2721
|
+
await writePagedPdf(
|
|
2722
|
+
{ info, pages: async function* () {
|
|
2723
|
+
yield* model.pages;
|
|
2724
|
+
} },
|
|
2725
|
+
{ fontStore, subset: opt.subset, id: fixed ? await contentId(model, opt, when) : void 0, title: opt.title, author: opt.author, creationDate: when, drillBase: opt.drillBase },
|
|
2726
|
+
{ write: (u8) => {
|
|
2727
|
+
parts.push(u8);
|
|
2728
|
+
} }
|
|
2729
|
+
);
|
|
2730
|
+
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
2731
|
+
let at = 0;
|
|
2732
|
+
for (const p of parts) {
|
|
2733
|
+
out.set(p, at);
|
|
2734
|
+
at += p.length;
|
|
2735
|
+
}
|
|
2736
|
+
return out;
|
|
2737
|
+
}
|
|
2738
|
+
function coveredText2(items, box) {
|
|
1508
2739
|
const lines = [];
|
|
1509
2740
|
for (const t of items) if (t.t === "text" && t.lines) {
|
|
1510
2741
|
for (const l of t.lines) if (l.text?.trim() && l.x >= box.x && l.x <= box.x + box.w && l.y >= box.y && l.y <= box.y + box.h) lines.push(l);
|
|
@@ -1526,11 +2757,11 @@ async function contentId(model, opt, when) {
|
|
|
1526
2757
|
}
|
|
1527
2758
|
function fieldFont(it) {
|
|
1528
2759
|
for (const d of it.draw) if (d.t === "text") {
|
|
1529
|
-
for (const l of d.lines) for (const r of l.runs || []) if (r.font !== it.font && r.text.trim()) return r.font;
|
|
2760
|
+
for (const l of d.lines) for (const r of l.runs || []) if (r.font !== it.font && r.text.trim()) return embeddedFace(r.font);
|
|
1530
2761
|
}
|
|
1531
|
-
return it.font;
|
|
2762
|
+
return embeddedFace(it.font);
|
|
1532
2763
|
}
|
|
1533
|
-
var pdfLiteral = (s) =>
|
|
2764
|
+
var pdfLiteral = (s) => PDFString.of(String(s).replace(/[\\()]/g, "\\$&"));
|
|
1534
2765
|
function plainEncoding(pf) {
|
|
1535
2766
|
const e = pf.embedder, f = e.font, memo = /* @__PURE__ */ new Map();
|
|
1536
2767
|
e.hexOf = (text) => {
|
|
@@ -1546,7 +2777,7 @@ function plainEncoding(pf) {
|
|
|
1546
2777
|
}
|
|
1547
2778
|
return hex2;
|
|
1548
2779
|
};
|
|
1549
|
-
e.encodeText = (text) =>
|
|
2780
|
+
e.encodeText = (text) => PDFHexString.of(e.hexOf(text));
|
|
1550
2781
|
e.widthOfTextAtSize = (text, size) => {
|
|
1551
2782
|
let w = 0;
|
|
1552
2783
|
for (const ch of text) w += f.glyphForCodePoint(
|
|
@@ -1555,8 +2786,8 @@ function plainEncoding(pf) {
|
|
|
1555
2786
|
).advanceWidth || 0;
|
|
1556
2787
|
return w * size / f.unitsPerEm;
|
|
1557
2788
|
};
|
|
1558
|
-
const
|
|
1559
|
-
const
|
|
2789
|
+
const lit2 = /* @__PURE__ */ new Map();
|
|
2790
|
+
const esc3 = (b) => b === 40 || b === 41 || b === 92 ? "\\" + String.fromCharCode(b) : b === 13 ? "\\r" : String.fromCharCode(b);
|
|
1560
2791
|
e.tjOf = (text) => {
|
|
1561
2792
|
let out = "", cur = "", any = false;
|
|
1562
2793
|
for (const ch of text) {
|
|
@@ -1582,10 +2813,10 @@ function plainEncoding(pf) {
|
|
|
1582
2813
|
/** @type {number} */
|
|
1583
2814
|
ch.codePointAt(0)
|
|
1584
2815
|
);
|
|
1585
|
-
let b =
|
|
2816
|
+
let b = lit2.get(cp);
|
|
1586
2817
|
if (b === void 0) {
|
|
1587
2818
|
const id = f.glyphForCodePoint(cp).id;
|
|
1588
|
-
|
|
2819
|
+
lit2.set(cp, b = esc3(id >> 8) + esc3(id & 255));
|
|
1589
2820
|
}
|
|
1590
2821
|
out += b;
|
|
1591
2822
|
}
|
|
@@ -1623,7 +2854,7 @@ function pageLabels(doc, model) {
|
|
|
1623
2854
|
const starts = [.../* @__PURE__ */ new Set([0, ...model.pageStarts || []])].filter((i) => i >= 0 && i < n).sort((a, b) => a - b);
|
|
1624
2855
|
const ctx = doc.context;
|
|
1625
2856
|
const nums = starts.flatMap((i) => [i, ctx.obj({ S: "D", St: 1 })]);
|
|
1626
|
-
doc.catalog.set(
|
|
2857
|
+
doc.catalog.set(PDFName.of("PageLabels"), ctx.obj({ Nums: nums }));
|
|
1627
2858
|
}
|
|
1628
2859
|
function addOutline(doc, bookmarks, dest) {
|
|
1629
2860
|
const ctx = doc.context;
|
|
@@ -1637,7 +2868,7 @@ function addOutline(doc, bookmarks, dest) {
|
|
|
1637
2868
|
if (!Dest) continue;
|
|
1638
2869
|
const level = Math.max(0, Math.min(9, Number(b.level) || 0));
|
|
1639
2870
|
while (stack[stack.length - 1].level >= level) stack.pop();
|
|
1640
|
-
const node2 = { ref: ctx.nextRef(), level, kids: [], Title:
|
|
2871
|
+
const node2 = { ref: ctx.nextRef(), level, kids: [], Title: PDFHexString.fromText(b.label), Dest };
|
|
1641
2872
|
stack[stack.length - 1].kids.push(node2);
|
|
1642
2873
|
stack.push(node2);
|
|
1643
2874
|
}
|
|
@@ -1650,15 +2881,15 @@ function addOutline(doc, bookmarks, dest) {
|
|
|
1650
2881
|
});
|
|
1651
2882
|
write(root);
|
|
1652
2883
|
ctx.assign(root.ref, ctx.obj({ Type: "Outlines", ...children(root) }));
|
|
1653
|
-
doc.catalog.set(
|
|
1654
|
-
doc.catalog.set(
|
|
2884
|
+
doc.catalog.set(PDFName.of("Outlines"), root.ref);
|
|
2885
|
+
doc.catalog.set(PDFName.of("PageMode"), PDFName.of("UseOutlines"));
|
|
1655
2886
|
}
|
|
1656
2887
|
function withPadding(font) {
|
|
1657
2888
|
const out = new Uint8Array(font.length + 16);
|
|
1658
2889
|
out.set(font);
|
|
1659
2890
|
return out;
|
|
1660
2891
|
}
|
|
1661
|
-
function
|
|
2892
|
+
function subsetTag2(bytes) {
|
|
1662
2893
|
let h = 2166136261;
|
|
1663
2894
|
for (let i = 0; i < bytes.length; i++) h = Math.imul(h ^ bytes[i], 16777619);
|
|
1664
2895
|
let tag = "";
|
|
@@ -1675,4 +2906,4 @@ function roundRect(x, y, w, h, r) {
|
|
|
1675
2906
|
export {
|
|
1676
2907
|
exportPdf
|
|
1677
2908
|
};
|
|
1678
|
-
//# sourceMappingURL=chunk-
|
|
2909
|
+
//# sourceMappingURL=chunk-VZHHNQYB.js.map
|