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