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