pdf-codec 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/content-write.cjs +29 -7
- package/dist/content-write.d.cts +9 -2
- package/dist/content-write.d.ts +9 -2
- package/dist/content-write.js +29 -7
- package/dist/{embedded-font-fREdbxnr.d.ts → embedded-font-B4p9a3O3.d.ts} +3 -1
- package/dist/{embedded-font-BU6Jgcof.d.cts → embedded-font-oc65VGlr.d.cts} +3 -1
- package/dist/embedded-font-write.d.cts +2 -2
- package/dist/embedded-font-write.d.ts +2 -2
- package/dist/embedded-font.cjs +46 -15
- package/dist/embedded-font.d.cts +1 -1
- package/dist/embedded-font.d.ts +1 -1
- package/dist/embedded-font.js +46 -15
- package/dist/font-registry.d.cts +1 -1
- package/dist/font-registry.d.ts +1 -1
- package/dist/gsub-table-BRTQ8EUW.d.ts +10 -0
- package/dist/gsub-table-URczLd85.d.cts +10 -0
- package/dist/gsub-table.cjs +225 -0
- package/dist/gsub-table.d.cts +2 -0
- package/dist/gsub-table.d.ts +2 -0
- package/dist/gsub-table.js +224 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/math-font-write.cjs +1 -1
- package/dist/math-font-write.js +1 -1
- package/dist/sfnt-subset.cjs +10 -3
- package/dist/sfnt-subset.d.cts +1 -1
- package/dist/sfnt-subset.d.ts +1 -1
- package/dist/sfnt-subset.js +10 -3
- package/dist/tounicode.cjs +8 -3
- package/dist/tounicode.d.cts +1 -1
- package/dist/tounicode.d.ts +1 -1
- package/dist/tounicode.js +8 -3
- package/dist/write.cjs +245 -4
- package/dist/write.d.cts +1 -1
- package/dist/write.d.ts +1 -1
- package/dist/write.js +245 -4
- package/package.json +1 -1
package/dist/write.cjs
CHANGED
|
@@ -4,8 +4,10 @@ const require_notes_annotation_author = require("./notes-annotation-author.cjs")
|
|
|
4
4
|
const require_objects = require("./objects.cjs");
|
|
5
5
|
const require_bytes_writer = require("./bytes/writer.cjs");
|
|
6
6
|
const require_serialize = require("./serialize.cjs");
|
|
7
|
+
const require_bytes_reader = require("./bytes/reader.cjs");
|
|
7
8
|
const require_bytes_flate = require("./bytes/flate.cjs");
|
|
8
9
|
const require_util_base64 = require("./util/base64.cjs");
|
|
10
|
+
const require_parse = require("./parse.cjs");
|
|
9
11
|
const require_util_abort = require("./util/abort.cjs");
|
|
10
12
|
const require_crypto_random = require("./crypto/random.cjs");
|
|
11
13
|
const require_encrypt_write = require("./encrypt-write.cjs");
|
|
@@ -252,6 +254,24 @@ function buildNotesAnnotDict(notes) {
|
|
|
252
254
|
function xrefEntry(offset, generation, inUse) {
|
|
253
255
|
return `${offset.toString().padStart(10, "0")} ${generation.toString().padStart(5, "0")} ${inUse ? "n" : "f"} \n`;
|
|
254
256
|
}
|
|
257
|
+
function parseResidueRow(residue) {
|
|
258
|
+
const reader = new require_bytes_reader.ByteReader(new TextEncoder().encode(residue.xml));
|
|
259
|
+
return require_parse.parseValue(reader, () => {});
|
|
260
|
+
}
|
|
261
|
+
function objectContainsReference(obj) {
|
|
262
|
+
if (obj.kind === "ref") return true;
|
|
263
|
+
if (obj.kind === "array") return obj.items.some(objectContainsReference);
|
|
264
|
+
if (obj.kind === "dict") return [...obj.entries.values()].some(objectContainsReference);
|
|
265
|
+
if (obj.kind === "stream") return [...obj.dict.entries.values()].some(objectContainsReference);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
function restoreResidueRow(source, key) {
|
|
269
|
+
const row = source?.[key];
|
|
270
|
+
if (row === void 0) return;
|
|
271
|
+
const parsed = parseResidueRow(row);
|
|
272
|
+
if (parsed === void 0 || objectContainsReference(parsed)) return;
|
|
273
|
+
return parsed;
|
|
274
|
+
}
|
|
255
275
|
function writePdf(doc, options = {}) {
|
|
256
276
|
const compress = options.compress ?? true;
|
|
257
277
|
const registry = options.fonts;
|
|
@@ -340,10 +360,80 @@ function writePdf(doc, options = {}) {
|
|
|
340
360
|
};
|
|
341
361
|
for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
|
|
342
362
|
}
|
|
363
|
+
const layerNumByName = /* @__PURE__ */ new Map();
|
|
364
|
+
for (const layer of doc.layers ?? []) layerNumByName.set(layer.name, nextObjNum++);
|
|
365
|
+
const formObjectNums = [];
|
|
366
|
+
const countFieldObjects = (fields) => {
|
|
367
|
+
let n = 0;
|
|
368
|
+
for (const field of fields) n += 1 + (field.fieldType !== "group" && field.widgets.length > 1 ? field.widgets.length - 1 : 0) + countFieldObjects(field.children);
|
|
369
|
+
return n;
|
|
370
|
+
};
|
|
371
|
+
for (let i = 0; i < countFieldObjects(doc.form ?? []); i += 1) formObjectNums.push(nextObjNum++);
|
|
372
|
+
const formNumByField = /* @__PURE__ */ new Map();
|
|
373
|
+
const formExtraWidgetNums = /* @__PURE__ */ new Map();
|
|
374
|
+
let formNumCursor = 0;
|
|
375
|
+
const claimFormNums = (fields) => {
|
|
376
|
+
for (const field of fields) {
|
|
377
|
+
formNumByField.set(field, formObjectNums[formNumCursor++]);
|
|
378
|
+
if (field.fieldType !== "group" && field.widgets.length > 1) formExtraWidgetNums.set(field, field.widgets.slice(1).map(() => formObjectNums[formNumCursor++]));
|
|
379
|
+
claimFormNums(field.children);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
claimFormNums(doc.form ?? []);
|
|
383
|
+
const formNumOf = (field) => {
|
|
384
|
+
const num = formNumByField.get(field);
|
|
385
|
+
if (num === void 0) throw new Error("AcroForm field object number was not claimed -- this is a writePdf internal invariant violation");
|
|
386
|
+
return num;
|
|
387
|
+
};
|
|
388
|
+
const structElementNumById = /* @__PURE__ */ new Map();
|
|
389
|
+
const countElements = (elements) => {
|
|
390
|
+
let n = 0;
|
|
391
|
+
for (const element of elements) {
|
|
392
|
+
structElementNumById.set(element.id, nextObjNum++);
|
|
393
|
+
n += 1 + countElements(element.children);
|
|
394
|
+
}
|
|
395
|
+
return n;
|
|
396
|
+
};
|
|
397
|
+
const structElementCount = countElements(doc.structure ?? []);
|
|
398
|
+
const structRootNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
399
|
+
const structParentTreeNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
400
|
+
const residueXmpNum = doc.source?.xmp !== void 0 ? nextObjNum++ : void 0;
|
|
343
401
|
const objects = [];
|
|
344
402
|
const catalogEntries = [["Type", require_objects.pdfName("Catalog")], ["Pages", require_objects.pdfRef(pagesNum, 0)]];
|
|
345
403
|
if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", require_objects.pdfRef(attachmentsNamesNum, 0)]);
|
|
346
404
|
if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", require_objects.pdfRef(outlineRootNum, 0)]);
|
|
405
|
+
if (layerNumByName.size > 0) {
|
|
406
|
+
const ocgRefs = [...layerNumByName.values()].map((num) => require_objects.pdfRef(num, 0));
|
|
407
|
+
const visible = [];
|
|
408
|
+
const hidden = [];
|
|
409
|
+
for (const layer of doc.layers ?? []) {
|
|
410
|
+
const num = layerNumByName.get(layer.name);
|
|
411
|
+
(layer.visible ? visible : hidden).push(require_objects.pdfRef(num, 0));
|
|
412
|
+
}
|
|
413
|
+
const defaultConfigEntries = [];
|
|
414
|
+
if (visible.length > 0) defaultConfigEntries.push(["ON", require_objects.pdfArray(visible)]);
|
|
415
|
+
if (hidden.length > 0) defaultConfigEntries.push(["OFF", require_objects.pdfArray(hidden)]);
|
|
416
|
+
catalogEntries.push(["OCProperties", require_objects.pdfDict({
|
|
417
|
+
OCGs: require_objects.pdfArray(ocgRefs),
|
|
418
|
+
D: require_objects.pdfDict(Object.fromEntries(defaultConfigEntries))
|
|
419
|
+
})]);
|
|
420
|
+
}
|
|
421
|
+
if (doc.form !== void 0 && doc.form.length > 0) catalogEntries.push(["AcroForm", require_objects.pdfDict({ Fields: require_objects.pdfArray(doc.form.map((field) => require_objects.pdfRef(formNumOf(field), 0))) })]);
|
|
422
|
+
if (structRootNum !== void 0) catalogEntries.push(["StructTreeRoot", require_objects.pdfRef(structRootNum, 0)]);
|
|
423
|
+
if (residueXmpNum !== void 0) catalogEntries.push(["Metadata", require_objects.pdfRef(residueXmpNum, 0)]);
|
|
424
|
+
const trailerIdRestore = restoreResidueRow(doc.source, "trailer-id");
|
|
425
|
+
for (const [rowKey, catalogKey] of [
|
|
426
|
+
["viewer-preferences", "ViewerPreferences"],
|
|
427
|
+
["page-mode", "PageMode"],
|
|
428
|
+
["page-layout", "PageLayout"],
|
|
429
|
+
["output-intents", "OutputIntents"],
|
|
430
|
+
["piece-info", "PieceInfo"],
|
|
431
|
+
["legal", "Legal"],
|
|
432
|
+
["collection", "Collection"]
|
|
433
|
+
]) {
|
|
434
|
+
const restored = restoreResidueRow(doc.source, rowKey);
|
|
435
|
+
if (restored !== void 0) catalogEntries.push([catalogKey, restored]);
|
|
436
|
+
}
|
|
347
437
|
objects.push({
|
|
348
438
|
num: catalogNum,
|
|
349
439
|
value: require_objects.pdfDict(Object.fromEntries(catalogEntries))
|
|
@@ -427,6 +517,118 @@ function writePdf(doc, options = {}) {
|
|
|
427
517
|
})
|
|
428
518
|
});
|
|
429
519
|
}
|
|
520
|
+
for (const layer of doc.layers ?? []) {
|
|
521
|
+
const num = layerNumByName.get(layer.name);
|
|
522
|
+
objects.push({
|
|
523
|
+
num,
|
|
524
|
+
value: require_objects.pdfDict({
|
|
525
|
+
Type: require_objects.pdfName("OCG"),
|
|
526
|
+
Name: require_objects.pdfLiteralString(new TextEncoder().encode(layer.name))
|
|
527
|
+
})
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
const widgetRectArray = (widget) => require_objects.pdfArray([
|
|
531
|
+
widget.xPt,
|
|
532
|
+
widget.yPt,
|
|
533
|
+
widget.xPt + widget.widthPt,
|
|
534
|
+
widget.yPt + widget.heightPt
|
|
535
|
+
].map((n) => require_objects.pdfNum(n)));
|
|
536
|
+
const widgetDict = (widget) => require_objects.pdfDict({
|
|
537
|
+
Subtype: require_objects.pdfName("Widget"),
|
|
538
|
+
Rect: widgetRectArray(widget),
|
|
539
|
+
P: require_objects.pdfRef(pageAllocs[widget.pageIndex].pageNum, 0)
|
|
540
|
+
});
|
|
541
|
+
const FIELD_TYPE_PDF_NAME = {
|
|
542
|
+
text: "Tx",
|
|
543
|
+
checkbox: "Btn",
|
|
544
|
+
radio: "Btn",
|
|
545
|
+
button: "Btn",
|
|
546
|
+
listbox: "Ch",
|
|
547
|
+
combobox: "Ch",
|
|
548
|
+
signature: "Sig"
|
|
549
|
+
};
|
|
550
|
+
const emitFormFieldObjects = (fields, parentName) => {
|
|
551
|
+
for (const field of fields) {
|
|
552
|
+
const ownName = parentName.length > 0 && field.name.startsWith(`${parentName}.`) ? field.name.slice(parentName.length + 1) : field.name;
|
|
553
|
+
const entries = [];
|
|
554
|
+
if (ownName.length > 0) entries.push(["T", require_objects.pdfLiteralString(new TextEncoder().encode(ownName))]);
|
|
555
|
+
if (field.alias !== void 0) entries.push(["TU", require_objects.pdfLiteralString(new TextEncoder().encode(field.alias))]);
|
|
556
|
+
if (field.fieldType === "group") entries.push(["Kids", require_objects.pdfArray(field.children.map((child) => require_objects.pdfRef(formNumOf(child), 0)))]);
|
|
557
|
+
else {
|
|
558
|
+
entries.push(["FT", require_objects.pdfName(FIELD_TYPE_PDF_NAME[field.fieldType])]);
|
|
559
|
+
const FLAG_READ_ONLY = 1;
|
|
560
|
+
const FLAG_PUSHBUTTON = 4;
|
|
561
|
+
const FLAG_RADIO = 32768;
|
|
562
|
+
const FLAG_COMBO = 131072;
|
|
563
|
+
let flags = 0;
|
|
564
|
+
if (field.readOnly === true) flags |= FLAG_READ_ONLY;
|
|
565
|
+
if (field.fieldType === "button") flags |= FLAG_PUSHBUTTON;
|
|
566
|
+
if (field.fieldType === "radio") flags |= FLAG_RADIO;
|
|
567
|
+
if (field.fieldType === "combobox") flags |= FLAG_COMBO;
|
|
568
|
+
if (flags !== 0) entries.push(["Ff", require_objects.pdfNum(flags)]);
|
|
569
|
+
if (field.fieldType === "text" || field.fieldType === "listbox" || field.fieldType === "combobox") {
|
|
570
|
+
if (field.value !== void 0) entries.push(["V", require_objects.pdfLiteralString(new TextEncoder().encode(field.value))]);
|
|
571
|
+
} else if (field.fieldType === "checkbox" || field.fieldType === "radio") entries.push(["V", require_objects.pdfName(field.checked === false || field.value === void 0 ? field.value ?? (field.checked === true ? "Yes" : "Off") : field.value)]);
|
|
572
|
+
if (field.options !== void 0) entries.push(["Opt", require_objects.pdfArray(field.options.map((option) => require_objects.pdfLiteralString(new TextEncoder().encode(option))))]);
|
|
573
|
+
const firstWidget = field.widgets[0];
|
|
574
|
+
if (field.widgets.length === 1 && firstWidget !== void 0) {
|
|
575
|
+
entries.push(["Subtype", require_objects.pdfName("Widget")]);
|
|
576
|
+
entries.push(["Rect", widgetRectArray(firstWidget)]);
|
|
577
|
+
entries.push(["P", require_objects.pdfRef(pageAllocs[firstWidget.pageIndex].pageNum, 0)]);
|
|
578
|
+
} else if (field.widgets.length > 1 && firstWidget !== void 0) {
|
|
579
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
580
|
+
entries.push(["Kids", require_objects.pdfArray([widgetDict(firstWidget), ...extraNums.map((num) => require_objects.pdfRef(num, 0))])]);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
objects.push({
|
|
584
|
+
num: formNumOf(field),
|
|
585
|
+
value: require_objects.pdfDict(Object.fromEntries(entries))
|
|
586
|
+
});
|
|
587
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
588
|
+
for (const [index, num] of extraNums.entries()) {
|
|
589
|
+
const widget = field.widgets[index + 1];
|
|
590
|
+
objects.push({
|
|
591
|
+
num,
|
|
592
|
+
value: widgetDict(widget)
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
emitFormFieldObjects(field.children, field.name);
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
emitFormFieldObjects(doc.form ?? [], "");
|
|
599
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
600
|
+
const emitStructureElement = (element, parentNum) => {
|
|
601
|
+
const entries = [
|
|
602
|
+
["Type", require_objects.pdfName("StructElem")],
|
|
603
|
+
["S", require_objects.pdfName(element.type)],
|
|
604
|
+
["P", require_objects.pdfRef(parentNum, 0)]
|
|
605
|
+
];
|
|
606
|
+
if (element.title !== void 0) entries.push(["T", require_objects.pdfLiteralString(new TextEncoder().encode(element.title))]);
|
|
607
|
+
if (element.language !== void 0) entries.push(["Lang", require_objects.pdfLiteralString(new TextEncoder().encode(element.language))]);
|
|
608
|
+
if (element.alt !== void 0) entries.push(["Alt", require_objects.pdfLiteralString(new TextEncoder().encode(element.alt))]);
|
|
609
|
+
if (element.actualText !== void 0) entries.push(["ActualText", require_objects.pdfLiteralString(new TextEncoder().encode(element.actualText))]);
|
|
610
|
+
if (element.children.length > 0) entries.push(["K", require_objects.pdfArray(element.children.map((child) => {
|
|
611
|
+
const num = structElementNumById.get(child.id);
|
|
612
|
+
if (num === void 0) throw new Error(`structure element "${child.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
613
|
+
return require_objects.pdfRef(num, 0);
|
|
614
|
+
}))]);
|
|
615
|
+
const ownNum = structElementNumById.get(element.id);
|
|
616
|
+
if (ownNum === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
617
|
+
objects.push({
|
|
618
|
+
num: ownNum,
|
|
619
|
+
value: require_objects.pdfDict(Object.fromEntries(entries))
|
|
620
|
+
});
|
|
621
|
+
for (const child of element.children) emitStructureElement(child, ownNum);
|
|
622
|
+
};
|
|
623
|
+
for (const element of doc.structure ?? []) emitStructureElement(element, structRootNum);
|
|
624
|
+
}
|
|
625
|
+
if (residueXmpNum !== void 0 && doc.source?.xmp !== void 0) objects.push({
|
|
626
|
+
num: residueXmpNum,
|
|
627
|
+
value: require_objects.pdfStream(require_objects.pdfDict({
|
|
628
|
+
Type: require_objects.pdfName("Metadata"),
|
|
629
|
+
Subtype: require_objects.pdfName("XML")
|
|
630
|
+
}), new TextEncoder().encode(doc.source.xmp.xml))
|
|
631
|
+
});
|
|
430
632
|
for (const [standardName, alloc] of fontAllocs) {
|
|
431
633
|
const { font, descriptor } = buildFontObjects(standardName, require_objects.pdfRef(alloc.descNum, 0));
|
|
432
634
|
objects.push({
|
|
@@ -482,9 +684,10 @@ function writePdf(doc, options = {}) {
|
|
|
482
684
|
});
|
|
483
685
|
}
|
|
484
686
|
for (const [face, alloc] of embeddedAllocs) {
|
|
485
|
-
const
|
|
687
|
+
const usedGlyphs = require_embedded_font.collectEmbeddedGlyphs(alloc.texts, face);
|
|
688
|
+
const subset = require_sfnt_subset.subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b), [...usedGlyphs.keys()].sort((a, b) => a - b));
|
|
486
689
|
if (subset === void 0) throw new Error(`font "${face.postScriptName}" resolved to an embeddable face, but its glyph outlines could not be subsetted -- only TrueType-outline ('glyf') fonts can be embedded, so supply a TrueType face for this family or drop it from the registry`);
|
|
487
|
-
const built = require_embedded_font_write.buildEmbeddedFontObjects(face, subset,
|
|
690
|
+
const built = require_embedded_font_write.buildEmbeddedFontObjects(face, subset, usedGlyphs, {
|
|
488
691
|
cidFontRef: require_objects.pdfRef(alloc.cidFontNum, 0),
|
|
489
692
|
descriptorRef: require_objects.pdfRef(alloc.descriptorNum, 0),
|
|
490
693
|
fontFileRef: require_objects.pdfRef(alloc.fontFileNum, 0),
|
|
@@ -520,6 +723,7 @@ function writePdf(doc, options = {}) {
|
|
|
520
723
|
}
|
|
521
724
|
if (imageAllocs.size > 0) resourceEntries.set("XObject", require_objects.pdfDict(new Map([...imageAllocs.values()].map((alloc) => [alloc.resourceName, require_objects.pdfRef(alloc.imageNum, 0)]))));
|
|
522
725
|
const resourcesDict = require_objects.pdfDict(resourceEntries);
|
|
726
|
+
const markedStructureByPage = /* @__PURE__ */ new Map();
|
|
523
727
|
const formulasByPage = /* @__PURE__ */ new Map();
|
|
524
728
|
for (const formula of formulas) {
|
|
525
729
|
const forPage = formulasByPage.get(formula.pageIndex);
|
|
@@ -556,7 +760,14 @@ function writePdf(doc, options = {}) {
|
|
|
556
760
|
doc.pages.forEach((page, pageIndex) => {
|
|
557
761
|
require_util_abort.throwIfAborted(options.signal);
|
|
558
762
|
const { pageNum, contentsNum } = pageAllocs[pageIndex];
|
|
559
|
-
|
|
763
|
+
let pageMcid = 0;
|
|
764
|
+
const pageContext = {
|
|
765
|
+
...context,
|
|
766
|
+
nextMcid: () => pageMcid++,
|
|
767
|
+
layerObjectNumberOf: (name) => layerNumByName.get(name)
|
|
768
|
+
};
|
|
769
|
+
const { bytes: contentBytes, substitutions, missingGlyphs, markedStructure } = require_content_write.writeContentStream(page.items, pageContext);
|
|
770
|
+
if (markedStructure.length > 0) markedStructureByPage.set(pageIndex, [...markedStructure]);
|
|
560
771
|
for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
|
|
561
772
|
for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
|
|
562
773
|
const pageFormulas = formulasByPage.get(pageIndex);
|
|
@@ -586,11 +797,41 @@ function writePdf(doc, options = {}) {
|
|
|
586
797
|
["Contents", require_objects.pdfRef(contentsNum, 0)]
|
|
587
798
|
]);
|
|
588
799
|
if (annots.length > 0) pageEntries.set("Annots", require_objects.pdfArray(annots));
|
|
800
|
+
if ((markedStructureByPage.get(pageIndex) ?? []).length > 0) pageEntries.set("StructParents", require_objects.pdfNum(pageIndex));
|
|
589
801
|
objects.push({
|
|
590
802
|
num: pageNum,
|
|
591
803
|
value: require_objects.pdfDict(pageEntries)
|
|
592
804
|
});
|
|
593
805
|
});
|
|
806
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
807
|
+
const nums = [];
|
|
808
|
+
for (const [pageIndex, marks] of markedStructureByPage) {
|
|
809
|
+
const maxMcid = Math.max(...marks.map((mark) => mark.mcid));
|
|
810
|
+
const byMcid = Array.from({ length: maxMcid + 1 }, () => require_objects.pdfNull());
|
|
811
|
+
for (const mark of marks) {
|
|
812
|
+
const elementNum = structElementNumById.get(mark.structureId);
|
|
813
|
+
if (elementNum !== void 0) byMcid[mark.mcid] = require_objects.pdfRef(elementNum, 0);
|
|
814
|
+
}
|
|
815
|
+
nums.push(require_objects.pdfNum(pageIndex), require_objects.pdfArray(byMcid));
|
|
816
|
+
}
|
|
817
|
+
objects.push({
|
|
818
|
+
num: structParentTreeNum,
|
|
819
|
+
value: require_objects.pdfDict({ Nums: require_objects.pdfArray(nums) })
|
|
820
|
+
});
|
|
821
|
+
const rootEntries = [
|
|
822
|
+
["Type", require_objects.pdfName("StructTreeRoot")],
|
|
823
|
+
["K", require_objects.pdfArray((doc.structure ?? []).map((element) => {
|
|
824
|
+
const num = structElementNumById.get(element.id);
|
|
825
|
+
if (num === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
826
|
+
return require_objects.pdfRef(num, 0);
|
|
827
|
+
}))],
|
|
828
|
+
["ParentTree", require_objects.pdfRef(structParentTreeNum, 0)]
|
|
829
|
+
];
|
|
830
|
+
objects.push({
|
|
831
|
+
num: structRootNum,
|
|
832
|
+
value: require_objects.pdfDict(Object.fromEntries(rootEntries))
|
|
833
|
+
});
|
|
834
|
+
}
|
|
594
835
|
let fileId;
|
|
595
836
|
let encryptedObjects = objects;
|
|
596
837
|
if (options.encryption !== void 0 && encryptDictNum !== void 0) {
|
|
@@ -632,7 +873,7 @@ function writePdf(doc, options = {}) {
|
|
|
632
873
|
if (fileId !== void 0 && encryptDictNum !== void 0) {
|
|
633
874
|
trailerEntries.set("ID", require_objects.pdfArray([require_objects.pdfHexString(fileId), require_objects.pdfHexString(fileId)]));
|
|
634
875
|
trailerEntries.set("Encrypt", require_objects.pdfRef(encryptDictNum, 0));
|
|
635
|
-
}
|
|
876
|
+
} else if (trailerIdRestore !== void 0) trailerEntries.set("ID", trailerIdRestore);
|
|
636
877
|
writer.writeAscii("trailer\n");
|
|
637
878
|
require_serialize.writeObject(writer, require_objects.pdfDict(trailerEntries));
|
|
638
879
|
writer.writeAscii("\nstartxref\n");
|
package/dist/write.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LayoutDocument } from "./layout.cjs";
|
|
2
|
-
import { r as EmbeddedFaceSubstitution } from "./embedded-font-
|
|
2
|
+
import { r as EmbeddedFaceSubstitution } from "./embedded-font-oc65VGlr.cjs";
|
|
3
3
|
import { WinAnsiSubstitution } from "./winansi.cjs";
|
|
4
4
|
import { PdfEncryptionOptions } from "./encrypt-write.cjs";
|
|
5
5
|
import { FontRegistry } from "./font-registry.cjs";
|
package/dist/write.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LayoutDocument } from "./layout.js";
|
|
2
|
-
import { r as EmbeddedFaceSubstitution } from "./embedded-font-
|
|
2
|
+
import { r as EmbeddedFaceSubstitution } from "./embedded-font-B4p9a3O3.js";
|
|
3
3
|
import { WinAnsiSubstitution } from "./winansi.js";
|
|
4
4
|
import { PdfEncryptionOptions } from "./encrypt-write.js";
|
|
5
5
|
import { FontRegistry } from "./font-registry.js";
|
package/dist/write.js
CHANGED
|
@@ -3,8 +3,10 @@ import { NOTES_ANNOTATION_AUTHOR } from "./notes-annotation-author.js";
|
|
|
3
3
|
import { pdfArray, pdfDict, pdfHexString, pdfLiteralString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
|
|
4
4
|
import { ByteWriter, concatBytes } from "./bytes/writer.js";
|
|
5
5
|
import { writeObject } from "./serialize.js";
|
|
6
|
+
import { ByteReader } from "./bytes/reader.js";
|
|
6
7
|
import { deflate } from "./bytes/flate.js";
|
|
7
8
|
import { base64ToBytes } from "./util/base64.js";
|
|
9
|
+
import { parseValue } from "./parse.js";
|
|
8
10
|
import { throwIfAborted } from "./util/abort.js";
|
|
9
11
|
import { randomBytes } from "./crypto/random.js";
|
|
10
12
|
import { createStandardEncryptor, encryptIndirectObject } from "./encrypt-write.js";
|
|
@@ -251,6 +253,24 @@ function buildNotesAnnotDict(notes) {
|
|
|
251
253
|
function xrefEntry(offset, generation, inUse) {
|
|
252
254
|
return `${offset.toString().padStart(10, "0")} ${generation.toString().padStart(5, "0")} ${inUse ? "n" : "f"} \n`;
|
|
253
255
|
}
|
|
256
|
+
function parseResidueRow(residue) {
|
|
257
|
+
const reader = new ByteReader(new TextEncoder().encode(residue.xml));
|
|
258
|
+
return parseValue(reader, () => {});
|
|
259
|
+
}
|
|
260
|
+
function objectContainsReference(obj) {
|
|
261
|
+
if (obj.kind === "ref") return true;
|
|
262
|
+
if (obj.kind === "array") return obj.items.some(objectContainsReference);
|
|
263
|
+
if (obj.kind === "dict") return [...obj.entries.values()].some(objectContainsReference);
|
|
264
|
+
if (obj.kind === "stream") return [...obj.dict.entries.values()].some(objectContainsReference);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function restoreResidueRow(source, key) {
|
|
268
|
+
const row = source?.[key];
|
|
269
|
+
if (row === void 0) return;
|
|
270
|
+
const parsed = parseResidueRow(row);
|
|
271
|
+
if (parsed === void 0 || objectContainsReference(parsed)) return;
|
|
272
|
+
return parsed;
|
|
273
|
+
}
|
|
254
274
|
function writePdf(doc, options = {}) {
|
|
255
275
|
const compress = options.compress ?? true;
|
|
256
276
|
const registry = options.fonts;
|
|
@@ -339,10 +359,80 @@ function writePdf(doc, options = {}) {
|
|
|
339
359
|
};
|
|
340
360
|
for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
|
|
341
361
|
}
|
|
362
|
+
const layerNumByName = /* @__PURE__ */ new Map();
|
|
363
|
+
for (const layer of doc.layers ?? []) layerNumByName.set(layer.name, nextObjNum++);
|
|
364
|
+
const formObjectNums = [];
|
|
365
|
+
const countFieldObjects = (fields) => {
|
|
366
|
+
let n = 0;
|
|
367
|
+
for (const field of fields) n += 1 + (field.fieldType !== "group" && field.widgets.length > 1 ? field.widgets.length - 1 : 0) + countFieldObjects(field.children);
|
|
368
|
+
return n;
|
|
369
|
+
};
|
|
370
|
+
for (let i = 0; i < countFieldObjects(doc.form ?? []); i += 1) formObjectNums.push(nextObjNum++);
|
|
371
|
+
const formNumByField = /* @__PURE__ */ new Map();
|
|
372
|
+
const formExtraWidgetNums = /* @__PURE__ */ new Map();
|
|
373
|
+
let formNumCursor = 0;
|
|
374
|
+
const claimFormNums = (fields) => {
|
|
375
|
+
for (const field of fields) {
|
|
376
|
+
formNumByField.set(field, formObjectNums[formNumCursor++]);
|
|
377
|
+
if (field.fieldType !== "group" && field.widgets.length > 1) formExtraWidgetNums.set(field, field.widgets.slice(1).map(() => formObjectNums[formNumCursor++]));
|
|
378
|
+
claimFormNums(field.children);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
claimFormNums(doc.form ?? []);
|
|
382
|
+
const formNumOf = (field) => {
|
|
383
|
+
const num = formNumByField.get(field);
|
|
384
|
+
if (num === void 0) throw new Error("AcroForm field object number was not claimed -- this is a writePdf internal invariant violation");
|
|
385
|
+
return num;
|
|
386
|
+
};
|
|
387
|
+
const structElementNumById = /* @__PURE__ */ new Map();
|
|
388
|
+
const countElements = (elements) => {
|
|
389
|
+
let n = 0;
|
|
390
|
+
for (const element of elements) {
|
|
391
|
+
structElementNumById.set(element.id, nextObjNum++);
|
|
392
|
+
n += 1 + countElements(element.children);
|
|
393
|
+
}
|
|
394
|
+
return n;
|
|
395
|
+
};
|
|
396
|
+
const structElementCount = countElements(doc.structure ?? []);
|
|
397
|
+
const structRootNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
398
|
+
const structParentTreeNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
399
|
+
const residueXmpNum = doc.source?.xmp !== void 0 ? nextObjNum++ : void 0;
|
|
342
400
|
const objects = [];
|
|
343
401
|
const catalogEntries = [["Type", pdfName("Catalog")], ["Pages", pdfRef(pagesNum, 0)]];
|
|
344
402
|
if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", pdfRef(attachmentsNamesNum, 0)]);
|
|
345
403
|
if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", pdfRef(outlineRootNum, 0)]);
|
|
404
|
+
if (layerNumByName.size > 0) {
|
|
405
|
+
const ocgRefs = [...layerNumByName.values()].map((num) => pdfRef(num, 0));
|
|
406
|
+
const visible = [];
|
|
407
|
+
const hidden = [];
|
|
408
|
+
for (const layer of doc.layers ?? []) {
|
|
409
|
+
const num = layerNumByName.get(layer.name);
|
|
410
|
+
(layer.visible ? visible : hidden).push(pdfRef(num, 0));
|
|
411
|
+
}
|
|
412
|
+
const defaultConfigEntries = [];
|
|
413
|
+
if (visible.length > 0) defaultConfigEntries.push(["ON", pdfArray(visible)]);
|
|
414
|
+
if (hidden.length > 0) defaultConfigEntries.push(["OFF", pdfArray(hidden)]);
|
|
415
|
+
catalogEntries.push(["OCProperties", pdfDict({
|
|
416
|
+
OCGs: pdfArray(ocgRefs),
|
|
417
|
+
D: pdfDict(Object.fromEntries(defaultConfigEntries))
|
|
418
|
+
})]);
|
|
419
|
+
}
|
|
420
|
+
if (doc.form !== void 0 && doc.form.length > 0) catalogEntries.push(["AcroForm", pdfDict({ Fields: pdfArray(doc.form.map((field) => pdfRef(formNumOf(field), 0))) })]);
|
|
421
|
+
if (structRootNum !== void 0) catalogEntries.push(["StructTreeRoot", pdfRef(structRootNum, 0)]);
|
|
422
|
+
if (residueXmpNum !== void 0) catalogEntries.push(["Metadata", pdfRef(residueXmpNum, 0)]);
|
|
423
|
+
const trailerIdRestore = restoreResidueRow(doc.source, "trailer-id");
|
|
424
|
+
for (const [rowKey, catalogKey] of [
|
|
425
|
+
["viewer-preferences", "ViewerPreferences"],
|
|
426
|
+
["page-mode", "PageMode"],
|
|
427
|
+
["page-layout", "PageLayout"],
|
|
428
|
+
["output-intents", "OutputIntents"],
|
|
429
|
+
["piece-info", "PieceInfo"],
|
|
430
|
+
["legal", "Legal"],
|
|
431
|
+
["collection", "Collection"]
|
|
432
|
+
]) {
|
|
433
|
+
const restored = restoreResidueRow(doc.source, rowKey);
|
|
434
|
+
if (restored !== void 0) catalogEntries.push([catalogKey, restored]);
|
|
435
|
+
}
|
|
346
436
|
objects.push({
|
|
347
437
|
num: catalogNum,
|
|
348
438
|
value: pdfDict(Object.fromEntries(catalogEntries))
|
|
@@ -426,6 +516,118 @@ function writePdf(doc, options = {}) {
|
|
|
426
516
|
})
|
|
427
517
|
});
|
|
428
518
|
}
|
|
519
|
+
for (const layer of doc.layers ?? []) {
|
|
520
|
+
const num = layerNumByName.get(layer.name);
|
|
521
|
+
objects.push({
|
|
522
|
+
num,
|
|
523
|
+
value: pdfDict({
|
|
524
|
+
Type: pdfName("OCG"),
|
|
525
|
+
Name: pdfLiteralString(new TextEncoder().encode(layer.name))
|
|
526
|
+
})
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
const widgetRectArray = (widget) => pdfArray([
|
|
530
|
+
widget.xPt,
|
|
531
|
+
widget.yPt,
|
|
532
|
+
widget.xPt + widget.widthPt,
|
|
533
|
+
widget.yPt + widget.heightPt
|
|
534
|
+
].map((n) => pdfNum(n)));
|
|
535
|
+
const widgetDict = (widget) => pdfDict({
|
|
536
|
+
Subtype: pdfName("Widget"),
|
|
537
|
+
Rect: widgetRectArray(widget),
|
|
538
|
+
P: pdfRef(pageAllocs[widget.pageIndex].pageNum, 0)
|
|
539
|
+
});
|
|
540
|
+
const FIELD_TYPE_PDF_NAME = {
|
|
541
|
+
text: "Tx",
|
|
542
|
+
checkbox: "Btn",
|
|
543
|
+
radio: "Btn",
|
|
544
|
+
button: "Btn",
|
|
545
|
+
listbox: "Ch",
|
|
546
|
+
combobox: "Ch",
|
|
547
|
+
signature: "Sig"
|
|
548
|
+
};
|
|
549
|
+
const emitFormFieldObjects = (fields, parentName) => {
|
|
550
|
+
for (const field of fields) {
|
|
551
|
+
const ownName = parentName.length > 0 && field.name.startsWith(`${parentName}.`) ? field.name.slice(parentName.length + 1) : field.name;
|
|
552
|
+
const entries = [];
|
|
553
|
+
if (ownName.length > 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(ownName))]);
|
|
554
|
+
if (field.alias !== void 0) entries.push(["TU", pdfLiteralString(new TextEncoder().encode(field.alias))]);
|
|
555
|
+
if (field.fieldType === "group") entries.push(["Kids", pdfArray(field.children.map((child) => pdfRef(formNumOf(child), 0)))]);
|
|
556
|
+
else {
|
|
557
|
+
entries.push(["FT", pdfName(FIELD_TYPE_PDF_NAME[field.fieldType])]);
|
|
558
|
+
const FLAG_READ_ONLY = 1;
|
|
559
|
+
const FLAG_PUSHBUTTON = 4;
|
|
560
|
+
const FLAG_RADIO = 32768;
|
|
561
|
+
const FLAG_COMBO = 131072;
|
|
562
|
+
let flags = 0;
|
|
563
|
+
if (field.readOnly === true) flags |= FLAG_READ_ONLY;
|
|
564
|
+
if (field.fieldType === "button") flags |= FLAG_PUSHBUTTON;
|
|
565
|
+
if (field.fieldType === "radio") flags |= FLAG_RADIO;
|
|
566
|
+
if (field.fieldType === "combobox") flags |= FLAG_COMBO;
|
|
567
|
+
if (flags !== 0) entries.push(["Ff", pdfNum(flags)]);
|
|
568
|
+
if (field.fieldType === "text" || field.fieldType === "listbox" || field.fieldType === "combobox") {
|
|
569
|
+
if (field.value !== void 0) entries.push(["V", pdfLiteralString(new TextEncoder().encode(field.value))]);
|
|
570
|
+
} else if (field.fieldType === "checkbox" || field.fieldType === "radio") entries.push(["V", pdfName(field.checked === false || field.value === void 0 ? field.value ?? (field.checked === true ? "Yes" : "Off") : field.value)]);
|
|
571
|
+
if (field.options !== void 0) entries.push(["Opt", pdfArray(field.options.map((option) => pdfLiteralString(new TextEncoder().encode(option))))]);
|
|
572
|
+
const firstWidget = field.widgets[0];
|
|
573
|
+
if (field.widgets.length === 1 && firstWidget !== void 0) {
|
|
574
|
+
entries.push(["Subtype", pdfName("Widget")]);
|
|
575
|
+
entries.push(["Rect", widgetRectArray(firstWidget)]);
|
|
576
|
+
entries.push(["P", pdfRef(pageAllocs[firstWidget.pageIndex].pageNum, 0)]);
|
|
577
|
+
} else if (field.widgets.length > 1 && firstWidget !== void 0) {
|
|
578
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
579
|
+
entries.push(["Kids", pdfArray([widgetDict(firstWidget), ...extraNums.map((num) => pdfRef(num, 0))])]);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
objects.push({
|
|
583
|
+
num: formNumOf(field),
|
|
584
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
585
|
+
});
|
|
586
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
587
|
+
for (const [index, num] of extraNums.entries()) {
|
|
588
|
+
const widget = field.widgets[index + 1];
|
|
589
|
+
objects.push({
|
|
590
|
+
num,
|
|
591
|
+
value: widgetDict(widget)
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
emitFormFieldObjects(field.children, field.name);
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
emitFormFieldObjects(doc.form ?? [], "");
|
|
598
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
599
|
+
const emitStructureElement = (element, parentNum) => {
|
|
600
|
+
const entries = [
|
|
601
|
+
["Type", pdfName("StructElem")],
|
|
602
|
+
["S", pdfName(element.type)],
|
|
603
|
+
["P", pdfRef(parentNum, 0)]
|
|
604
|
+
];
|
|
605
|
+
if (element.title !== void 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(element.title))]);
|
|
606
|
+
if (element.language !== void 0) entries.push(["Lang", pdfLiteralString(new TextEncoder().encode(element.language))]);
|
|
607
|
+
if (element.alt !== void 0) entries.push(["Alt", pdfLiteralString(new TextEncoder().encode(element.alt))]);
|
|
608
|
+
if (element.actualText !== void 0) entries.push(["ActualText", pdfLiteralString(new TextEncoder().encode(element.actualText))]);
|
|
609
|
+
if (element.children.length > 0) entries.push(["K", pdfArray(element.children.map((child) => {
|
|
610
|
+
const num = structElementNumById.get(child.id);
|
|
611
|
+
if (num === void 0) throw new Error(`structure element "${child.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
612
|
+
return pdfRef(num, 0);
|
|
613
|
+
}))]);
|
|
614
|
+
const ownNum = structElementNumById.get(element.id);
|
|
615
|
+
if (ownNum === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
616
|
+
objects.push({
|
|
617
|
+
num: ownNum,
|
|
618
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
619
|
+
});
|
|
620
|
+
for (const child of element.children) emitStructureElement(child, ownNum);
|
|
621
|
+
};
|
|
622
|
+
for (const element of doc.structure ?? []) emitStructureElement(element, structRootNum);
|
|
623
|
+
}
|
|
624
|
+
if (residueXmpNum !== void 0 && doc.source?.xmp !== void 0) objects.push({
|
|
625
|
+
num: residueXmpNum,
|
|
626
|
+
value: pdfStream(pdfDict({
|
|
627
|
+
Type: pdfName("Metadata"),
|
|
628
|
+
Subtype: pdfName("XML")
|
|
629
|
+
}), new TextEncoder().encode(doc.source.xmp.xml))
|
|
630
|
+
});
|
|
429
631
|
for (const [standardName, alloc] of fontAllocs) {
|
|
430
632
|
const { font, descriptor } = buildFontObjects(standardName, pdfRef(alloc.descNum, 0));
|
|
431
633
|
objects.push({
|
|
@@ -481,9 +683,10 @@ function writePdf(doc, options = {}) {
|
|
|
481
683
|
});
|
|
482
684
|
}
|
|
483
685
|
for (const [face, alloc] of embeddedAllocs) {
|
|
484
|
-
const
|
|
686
|
+
const usedGlyphs = collectEmbeddedGlyphs(alloc.texts, face);
|
|
687
|
+
const subset = subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b), [...usedGlyphs.keys()].sort((a, b) => a - b));
|
|
485
688
|
if (subset === void 0) throw new Error(`font "${face.postScriptName}" resolved to an embeddable face, but its glyph outlines could not be subsetted -- only TrueType-outline ('glyf') fonts can be embedded, so supply a TrueType face for this family or drop it from the registry`);
|
|
486
|
-
const built = buildEmbeddedFontObjects(face, subset,
|
|
689
|
+
const built = buildEmbeddedFontObjects(face, subset, usedGlyphs, {
|
|
487
690
|
cidFontRef: pdfRef(alloc.cidFontNum, 0),
|
|
488
691
|
descriptorRef: pdfRef(alloc.descriptorNum, 0),
|
|
489
692
|
fontFileRef: pdfRef(alloc.fontFileNum, 0),
|
|
@@ -519,6 +722,7 @@ function writePdf(doc, options = {}) {
|
|
|
519
722
|
}
|
|
520
723
|
if (imageAllocs.size > 0) resourceEntries.set("XObject", pdfDict(new Map([...imageAllocs.values()].map((alloc) => [alloc.resourceName, pdfRef(alloc.imageNum, 0)]))));
|
|
521
724
|
const resourcesDict = pdfDict(resourceEntries);
|
|
725
|
+
const markedStructureByPage = /* @__PURE__ */ new Map();
|
|
522
726
|
const formulasByPage = /* @__PURE__ */ new Map();
|
|
523
727
|
for (const formula of formulas) {
|
|
524
728
|
const forPage = formulasByPage.get(formula.pageIndex);
|
|
@@ -555,7 +759,14 @@ function writePdf(doc, options = {}) {
|
|
|
555
759
|
doc.pages.forEach((page, pageIndex) => {
|
|
556
760
|
throwIfAborted(options.signal);
|
|
557
761
|
const { pageNum, contentsNum } = pageAllocs[pageIndex];
|
|
558
|
-
|
|
762
|
+
let pageMcid = 0;
|
|
763
|
+
const pageContext = {
|
|
764
|
+
...context,
|
|
765
|
+
nextMcid: () => pageMcid++,
|
|
766
|
+
layerObjectNumberOf: (name) => layerNumByName.get(name)
|
|
767
|
+
};
|
|
768
|
+
const { bytes: contentBytes, substitutions, missingGlyphs, markedStructure } = writeContentStream(page.items, pageContext);
|
|
769
|
+
if (markedStructure.length > 0) markedStructureByPage.set(pageIndex, [...markedStructure]);
|
|
559
770
|
for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
|
|
560
771
|
for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
|
|
561
772
|
const pageFormulas = formulasByPage.get(pageIndex);
|
|
@@ -585,11 +796,41 @@ function writePdf(doc, options = {}) {
|
|
|
585
796
|
["Contents", pdfRef(contentsNum, 0)]
|
|
586
797
|
]);
|
|
587
798
|
if (annots.length > 0) pageEntries.set("Annots", pdfArray(annots));
|
|
799
|
+
if ((markedStructureByPage.get(pageIndex) ?? []).length > 0) pageEntries.set("StructParents", pdfNum(pageIndex));
|
|
588
800
|
objects.push({
|
|
589
801
|
num: pageNum,
|
|
590
802
|
value: pdfDict(pageEntries)
|
|
591
803
|
});
|
|
592
804
|
});
|
|
805
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
806
|
+
const nums = [];
|
|
807
|
+
for (const [pageIndex, marks] of markedStructureByPage) {
|
|
808
|
+
const maxMcid = Math.max(...marks.map((mark) => mark.mcid));
|
|
809
|
+
const byMcid = Array.from({ length: maxMcid + 1 }, () => pdfNull());
|
|
810
|
+
for (const mark of marks) {
|
|
811
|
+
const elementNum = structElementNumById.get(mark.structureId);
|
|
812
|
+
if (elementNum !== void 0) byMcid[mark.mcid] = pdfRef(elementNum, 0);
|
|
813
|
+
}
|
|
814
|
+
nums.push(pdfNum(pageIndex), pdfArray(byMcid));
|
|
815
|
+
}
|
|
816
|
+
objects.push({
|
|
817
|
+
num: structParentTreeNum,
|
|
818
|
+
value: pdfDict({ Nums: pdfArray(nums) })
|
|
819
|
+
});
|
|
820
|
+
const rootEntries = [
|
|
821
|
+
["Type", pdfName("StructTreeRoot")],
|
|
822
|
+
["K", pdfArray((doc.structure ?? []).map((element) => {
|
|
823
|
+
const num = structElementNumById.get(element.id);
|
|
824
|
+
if (num === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
825
|
+
return pdfRef(num, 0);
|
|
826
|
+
}))],
|
|
827
|
+
["ParentTree", pdfRef(structParentTreeNum, 0)]
|
|
828
|
+
];
|
|
829
|
+
objects.push({
|
|
830
|
+
num: structRootNum,
|
|
831
|
+
value: pdfDict(Object.fromEntries(rootEntries))
|
|
832
|
+
});
|
|
833
|
+
}
|
|
593
834
|
let fileId;
|
|
594
835
|
let encryptedObjects = objects;
|
|
595
836
|
if (options.encryption !== void 0 && encryptDictNum !== void 0) {
|
|
@@ -631,7 +872,7 @@ function writePdf(doc, options = {}) {
|
|
|
631
872
|
if (fileId !== void 0 && encryptDictNum !== void 0) {
|
|
632
873
|
trailerEntries.set("ID", pdfArray([pdfHexString(fileId), pdfHexString(fileId)]));
|
|
633
874
|
trailerEntries.set("Encrypt", pdfRef(encryptDictNum, 0));
|
|
634
|
-
}
|
|
875
|
+
} else if (trailerIdRestore !== void 0) trailerEntries.set("ID", trailerIdRestore);
|
|
635
876
|
writer.writeAscii("trailer\n");
|
|
636
877
|
writeObject(writer, pdfDict(trailerEntries));
|
|
637
878
|
writer.writeAscii("\nstartxref\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdf-codec",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on its own codec-owned LayoutDocument item model and Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|