pdf-codec 4.0.13 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/annotations.d.cts +1 -1
- package/dist/annotations.d.ts +1 -1
- package/dist/attachments.d.cts +1 -1
- package/dist/attachments.d.ts +1 -1
- package/dist/content-read.d.cts +1 -1
- package/dist/content-read.d.ts +1 -1
- package/dist/crypto/random.cjs +9 -0
- package/dist/crypto/random.d.cts +4 -0
- package/dist/crypto/random.d.ts +4 -0
- package/dist/crypto/random.js +8 -0
- package/dist/document.d.cts +1 -1
- package/dist/document.d.ts +1 -1
- package/dist/embedded-font-write.d.cts +1 -1
- package/dist/embedded-font-write.d.ts +1 -1
- package/dist/encrypt-write.cjs +234 -0
- package/dist/encrypt-write.d.cts +31 -0
- package/dist/encrypt-write.d.ts +31 -0
- package/dist/encrypt-write.js +231 -0
- package/dist/encrypt.cjs +50 -20
- package/dist/encrypt.d.cts +18 -2
- package/dist/encrypt.d.ts +18 -2
- package/dist/encrypt.js +35 -21
- package/dist/filters.d.cts +1 -1
- package/dist/filters.d.ts +1 -1
- package/dist/font-read.d.cts +1 -1
- package/dist/font-read.d.ts +1 -1
- package/dist/form.d.cts +1 -1
- package/dist/form.d.ts +1 -1
- package/dist/images-read.d.cts +1 -1
- package/dist/images-read.d.ts +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/interpret.d.cts +1 -1
- package/dist/interpret.d.ts +1 -1
- package/dist/math-font-write.d.cts +1 -1
- package/dist/math-font-write.d.ts +1 -1
- package/dist/names.d.cts +1 -1
- package/dist/names.d.ts +1 -1
- package/dist/navigation.d.cts +1 -1
- package/dist/navigation.d.ts +1 -1
- package/dist/objects-B7HdMeWS.d.cts +59 -0
- package/dist/objects-B7HdMeWS.d.ts +59 -0
- package/dist/objects.d.cts +1 -58
- package/dist/objects.d.ts +1 -58
- package/dist/optional-content.d.cts +1 -1
- package/dist/optional-content.d.ts +1 -1
- package/dist/parse.d.cts +1 -1
- package/dist/parse.d.ts +1 -1
- package/dist/predictors.d.cts +1 -1
- package/dist/predictors.d.ts +1 -1
- package/dist/serialize.d.cts +1 -1
- package/dist/serialize.d.ts +1 -1
- package/dist/structure.d.cts +1 -1
- package/dist/structure.d.ts +1 -1
- package/dist/tounicode.d.cts +1 -1
- package/dist/tounicode.d.ts +1 -1
- package/dist/write.cjs +123 -15
- package/dist/write.d.cts +2 -0
- package/dist/write.d.ts +2 -0
- package/dist/write.js +124 -16
- package/dist/xref.d.cts +1 -1
- package/dist/xref.d.ts +1 -1
- package/package.json +1 -1
package/dist/write.cjs
CHANGED
|
@@ -7,6 +7,8 @@ const require_serialize = require("./serialize.cjs");
|
|
|
7
7
|
const require_bytes_flate = require("./bytes/flate.cjs");
|
|
8
8
|
const require_util_base64 = require("./util/base64.cjs");
|
|
9
9
|
const require_util_abort = require("./util/abort.cjs");
|
|
10
|
+
const require_crypto_random = require("./crypto/random.cjs");
|
|
11
|
+
const require_encrypt_write = require("./encrypt-write.cjs");
|
|
10
12
|
const require_image_jpeg_info = require("./image/jpeg-info.cjs");
|
|
11
13
|
const require_image_png_decode = require("./image/png-decode.cjs");
|
|
12
14
|
const require_embedded_font = require("./embedded-font.cjs");
|
|
@@ -30,6 +32,7 @@ const FLAG_SERIF = 2;
|
|
|
30
32
|
const FLAG_NONSYMBOLIC = 32;
|
|
31
33
|
const FLAG_ITALIC = 64;
|
|
32
34
|
const FLAG_FORCE_BOLD = 262144;
|
|
35
|
+
const FILE_ID_BYTES = 16;
|
|
33
36
|
function textToPdfString(text) {
|
|
34
37
|
const bytes = new Uint8Array(2 + text.length * 2);
|
|
35
38
|
bytes[0] = 254;
|
|
@@ -199,11 +202,14 @@ function destinationViewArray(target) {
|
|
|
199
202
|
if (target.kind === "fitBV") return [require_objects.pdfName("FitBV"), n(target.leftPt)];
|
|
200
203
|
return [require_objects.pdfName(target.kind === "fitB" ? "FitB" : "Fit")];
|
|
201
204
|
}
|
|
202
|
-
function
|
|
203
|
-
const destination = doc.destinations?.find((d) => d.name ===
|
|
204
|
-
if (destination === void 0) throw new Error(
|
|
205
|
+
function resolveDestinationArray(doc, pageAllocs, name, what) {
|
|
206
|
+
const destination = doc.destinations?.find((d) => d.name === name);
|
|
207
|
+
if (destination === void 0) throw new Error(`${what} names destination "${name}", which the document's destinations table does not carry -- this is a caller-invariant violation`);
|
|
205
208
|
const targetPage = pageAllocs[destination.pageIndex];
|
|
206
|
-
if (targetPage === void 0) throw new Error(`destination "${
|
|
209
|
+
if (targetPage === void 0) throw new Error(`destination "${destination.name}" names page index ${destination.pageIndex}, which is beyond the document's own pages -- this is a caller-invariant violation`);
|
|
210
|
+
return [require_objects.pdfRef(targetPage.pageNum, 0), ...destinationViewArray(destination.target)];
|
|
211
|
+
}
|
|
212
|
+
function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
207
213
|
return require_objects.pdfDict({
|
|
208
214
|
Type: require_objects.pdfName("Annot"),
|
|
209
215
|
Subtype: require_objects.pdfName("Link"),
|
|
@@ -218,7 +224,7 @@ function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
|
218
224
|
0,
|
|
219
225
|
0
|
|
220
226
|
].map((v) => require_objects.pdfNum(v))),
|
|
221
|
-
Dest: require_objects.pdfArray(
|
|
227
|
+
Dest: require_objects.pdfArray(resolveDestinationArray(doc, pageAllocs, link.destination, "internal link"))
|
|
222
228
|
});
|
|
223
229
|
}
|
|
224
230
|
function isLinkItem(item) {
|
|
@@ -318,13 +324,29 @@ function writePdf(doc, options = {}) {
|
|
|
318
324
|
pageNum: nextObjNum++,
|
|
319
325
|
contentsNum: nextObjNum++
|
|
320
326
|
}));
|
|
327
|
+
const encryptDictNum = options.encryption === void 0 ? void 0 : nextObjNum++;
|
|
328
|
+
const attachmentAllocs = (doc.attachments ?? []).map(() => ({
|
|
329
|
+
fileNum: nextObjNum++,
|
|
330
|
+
specNum: nextObjNum++
|
|
331
|
+
}));
|
|
332
|
+
const attachmentsNamesNum = attachmentAllocs.length > 0 ? nextObjNum++ : void 0;
|
|
333
|
+
const outlineRootNum = (doc.outline ?? []).length > 0 ? nextObjNum++ : void 0;
|
|
334
|
+
const outlineItemNums = [];
|
|
335
|
+
if (outlineRootNum !== void 0) {
|
|
336
|
+
const countItems = (items) => {
|
|
337
|
+
let n = 0;
|
|
338
|
+
for (const item of items) n += 1 + countItems(item.children);
|
|
339
|
+
return n;
|
|
340
|
+
};
|
|
341
|
+
for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
|
|
342
|
+
}
|
|
321
343
|
const objects = [];
|
|
344
|
+
const catalogEntries = [["Type", require_objects.pdfName("Catalog")], ["Pages", require_objects.pdfRef(pagesNum, 0)]];
|
|
345
|
+
if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", require_objects.pdfRef(attachmentsNamesNum, 0)]);
|
|
346
|
+
if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", require_objects.pdfRef(outlineRootNum, 0)]);
|
|
322
347
|
objects.push({
|
|
323
348
|
num: catalogNum,
|
|
324
|
-
value: require_objects.pdfDict(
|
|
325
|
-
Type: require_objects.pdfName("Catalog"),
|
|
326
|
-
Pages: require_objects.pdfRef(pagesNum, 0)
|
|
327
|
-
})
|
|
349
|
+
value: require_objects.pdfDict(Object.fromEntries(catalogEntries))
|
|
328
350
|
});
|
|
329
351
|
objects.push({
|
|
330
352
|
num: pagesNum,
|
|
@@ -338,6 +360,73 @@ function writePdf(doc, options = {}) {
|
|
|
338
360
|
num: infoNum,
|
|
339
361
|
value: buildInfoDict(doc)
|
|
340
362
|
});
|
|
363
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
364
|
+
const alloc = attachmentAllocs[index];
|
|
365
|
+
const fileEntries = [["Type", require_objects.pdfName("EmbeddedFile")]];
|
|
366
|
+
if (attachment.mimeType !== void 0) fileEntries.push(["Subtype", require_objects.pdfName(attachment.mimeType)]);
|
|
367
|
+
objects.push({
|
|
368
|
+
num: alloc.fileNum,
|
|
369
|
+
value: require_objects.pdfStream(require_objects.pdfDict(Object.fromEntries(fileEntries)), require_util_base64.base64ToBytes(attachment.base64))
|
|
370
|
+
});
|
|
371
|
+
const specEntries = [
|
|
372
|
+
["Type", require_objects.pdfName("Filespec")],
|
|
373
|
+
["F", require_objects.pdfLiteralString(new TextEncoder().encode(attachment.name))],
|
|
374
|
+
["EF", require_objects.pdfDict({ F: require_objects.pdfRef(alloc.fileNum, 0) })]
|
|
375
|
+
];
|
|
376
|
+
if (attachment.description !== void 0) specEntries.push(["Desc", require_objects.pdfLiteralString(new TextEncoder().encode(attachment.description))]);
|
|
377
|
+
objects.push({
|
|
378
|
+
num: alloc.specNum,
|
|
379
|
+
value: require_objects.pdfDict(Object.fromEntries(specEntries))
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (attachmentsNamesNum !== void 0) {
|
|
383
|
+
const names = [];
|
|
384
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
385
|
+
names.push(require_objects.pdfLiteralString(new TextEncoder().encode(attachment.name)));
|
|
386
|
+
names.push(require_objects.pdfRef(attachmentAllocs[index].specNum, 0));
|
|
387
|
+
}
|
|
388
|
+
objects.push({
|
|
389
|
+
num: attachmentsNamesNum,
|
|
390
|
+
value: require_objects.pdfDict({ EmbeddedFiles: require_objects.pdfDict({ Names: require_objects.pdfArray(names) }) })
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
if (outlineRootNum !== void 0 && (doc.outline ?? []).length > 0) {
|
|
394
|
+
let itemCursor = 0;
|
|
395
|
+
const emitItems = (items, parentNum) => {
|
|
396
|
+
const siblingNums = [];
|
|
397
|
+
let prevNum;
|
|
398
|
+
for (const item of items) {
|
|
399
|
+
const ownNum = outlineItemNums[itemCursor];
|
|
400
|
+
itemCursor += 1;
|
|
401
|
+
siblingNums.push(ownNum);
|
|
402
|
+
const childNums = emitItems(item.children, ownNum);
|
|
403
|
+
const entries = [["Title", require_objects.pdfLiteralString(new TextEncoder().encode(item.title))], ["Parent", require_objects.pdfRef(parentNum, 0)]];
|
|
404
|
+
if (item.destination !== void 0) entries.push(["Dest", require_objects.pdfArray(resolveDestinationArray(doc, pageAllocs, item.destination, `outline item "${item.title}"`))]);
|
|
405
|
+
if (prevNum !== void 0) entries.push(["Prev", require_objects.pdfRef(prevNum, 0)]);
|
|
406
|
+
if (siblingNums.length < items.length) entries.push(["Next", require_objects.pdfRef(outlineItemNums[itemCursor], 0)]);
|
|
407
|
+
if (childNums.length > 0) {
|
|
408
|
+
entries.push(["First", require_objects.pdfRef(childNums[0], 0)]);
|
|
409
|
+
entries.push(["Last", require_objects.pdfRef(childNums[childNums.length - 1], 0)]);
|
|
410
|
+
entries.push(["Count", require_objects.pdfNum(childNums.length)]);
|
|
411
|
+
}
|
|
412
|
+
objects.push({
|
|
413
|
+
num: ownNum,
|
|
414
|
+
value: require_objects.pdfDict(Object.fromEntries(entries))
|
|
415
|
+
});
|
|
416
|
+
prevNum = ownNum;
|
|
417
|
+
}
|
|
418
|
+
return siblingNums;
|
|
419
|
+
};
|
|
420
|
+
const topLevelNums = emitItems(doc.outline ?? [], outlineRootNum);
|
|
421
|
+
objects.push({
|
|
422
|
+
num: outlineRootNum,
|
|
423
|
+
value: require_objects.pdfDict({
|
|
424
|
+
Type: require_objects.pdfName("Outlines"),
|
|
425
|
+
First: require_objects.pdfRef(topLevelNums[0], 0),
|
|
426
|
+
Last: require_objects.pdfRef(topLevelNums[topLevelNums.length - 1], 0)
|
|
427
|
+
})
|
|
428
|
+
});
|
|
429
|
+
}
|
|
341
430
|
for (const [standardName, alloc] of fontAllocs) {
|
|
342
431
|
const { font, descriptor } = buildFontObjects(standardName, require_objects.pdfRef(alloc.descNum, 0));
|
|
343
432
|
objects.push({
|
|
@@ -502,10 +591,24 @@ function writePdf(doc, options = {}) {
|
|
|
502
591
|
value: require_objects.pdfDict(pageEntries)
|
|
503
592
|
});
|
|
504
593
|
});
|
|
594
|
+
let fileId;
|
|
595
|
+
let encryptedObjects = objects;
|
|
596
|
+
if (options.encryption !== void 0 && encryptDictNum !== void 0) {
|
|
597
|
+
fileId = require_crypto_random.randomBytes(FILE_ID_BYTES);
|
|
598
|
+
const encryptor = require_encrypt_write.createStandardEncryptor(options.encryption, fileId);
|
|
599
|
+
encryptedObjects = objects.map(({ num, value }) => ({
|
|
600
|
+
num,
|
|
601
|
+
value: require_encrypt_write.encryptIndirectObject(value, num, 0, encryptor)
|
|
602
|
+
}));
|
|
603
|
+
encryptedObjects.push({
|
|
604
|
+
num: encryptDictNum,
|
|
605
|
+
value: encryptor.encryptDict
|
|
606
|
+
});
|
|
607
|
+
}
|
|
505
608
|
const writer = new require_bytes_writer.ByteWriter();
|
|
506
609
|
writer.writeAscii("%PDF-1.7\n");
|
|
507
610
|
const offsets = /* @__PURE__ */ new Map();
|
|
508
|
-
for (const { num, value } of
|
|
611
|
+
for (const { num, value } of encryptedObjects) {
|
|
509
612
|
offsets.set(num, writer.length);
|
|
510
613
|
writer.writeAscii(`${num} 0 obj\n`);
|
|
511
614
|
require_serialize.writeObject(writer, value);
|
|
@@ -521,12 +624,17 @@ function writePdf(doc, options = {}) {
|
|
|
521
624
|
if (offset === void 0) throw new Error(`object ${num} was allocated but never written -- this is a writePdf internal invariant violation`);
|
|
522
625
|
writer.writeAscii(xrefEntry(offset, 0, true));
|
|
523
626
|
}
|
|
627
|
+
const trailerEntries = /* @__PURE__ */ new Map([
|
|
628
|
+
["Size", require_objects.pdfNum(maxObjNum + 1)],
|
|
629
|
+
["Root", require_objects.pdfRef(catalogNum, 0)],
|
|
630
|
+
["Info", require_objects.pdfRef(infoNum, 0)]
|
|
631
|
+
]);
|
|
632
|
+
if (fileId !== void 0 && encryptDictNum !== void 0) {
|
|
633
|
+
trailerEntries.set("ID", require_objects.pdfArray([require_objects.pdfHexString(fileId), require_objects.pdfHexString(fileId)]));
|
|
634
|
+
trailerEntries.set("Encrypt", require_objects.pdfRef(encryptDictNum, 0));
|
|
635
|
+
}
|
|
524
636
|
writer.writeAscii("trailer\n");
|
|
525
|
-
require_serialize.writeObject(writer, require_objects.pdfDict(
|
|
526
|
-
Size: require_objects.pdfNum(maxObjNum + 1),
|
|
527
|
-
Root: require_objects.pdfRef(catalogNum, 0),
|
|
528
|
-
Info: require_objects.pdfRef(infoNum, 0)
|
|
529
|
-
}));
|
|
637
|
+
require_serialize.writeObject(writer, require_objects.pdfDict(trailerEntries));
|
|
530
638
|
writer.writeAscii("\nstartxref\n");
|
|
531
639
|
writer.writeAscii(`${xrefOffset}\n`);
|
|
532
640
|
writer.writeAscii("%%EOF");
|
package/dist/write.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LayoutDocument } from "./layout.cjs";
|
|
2
2
|
import { r as EmbeddedFaceSubstitution } from "./embedded-font-BU6Jgcof.cjs";
|
|
3
3
|
import { WinAnsiSubstitution } from "./winansi.cjs";
|
|
4
|
+
import { PdfEncryptionOptions } from "./encrypt-write.cjs";
|
|
4
5
|
import { FontRegistry } from "./font-registry.cjs";
|
|
5
6
|
import { PositionedFormula } from "document-schema.js";
|
|
6
7
|
//#region src/write.d.ts
|
|
@@ -15,6 +16,7 @@ interface WritePdfOptions {
|
|
|
15
16
|
}) => void;
|
|
16
17
|
readonly fonts?: FontRegistry;
|
|
17
18
|
readonly formulas?: readonly PositionedFormula[];
|
|
19
|
+
readonly encryption?: PdfEncryptionOptions;
|
|
18
20
|
}
|
|
19
21
|
declare function writePdf(doc: LayoutDocument, options?: WritePdfOptions): Uint8Array<ArrayBuffer>;
|
|
20
22
|
//#endregion
|
package/dist/write.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LayoutDocument } from "./layout.js";
|
|
2
2
|
import { r as EmbeddedFaceSubstitution } from "./embedded-font-fREdbxnr.js";
|
|
3
3
|
import { WinAnsiSubstitution } from "./winansi.js";
|
|
4
|
+
import { PdfEncryptionOptions } from "./encrypt-write.js";
|
|
4
5
|
import { FontRegistry } from "./font-registry.js";
|
|
5
6
|
import { PositionedFormula } from "document-schema.js";
|
|
6
7
|
//#region src/write.d.ts
|
|
@@ -15,6 +16,7 @@ interface WritePdfOptions {
|
|
|
15
16
|
}) => void;
|
|
16
17
|
readonly fonts?: FontRegistry;
|
|
17
18
|
readonly formulas?: readonly PositionedFormula[];
|
|
19
|
+
readonly encryption?: PdfEncryptionOptions;
|
|
18
20
|
}
|
|
19
21
|
declare function writePdf(doc: LayoutDocument, options?: WritePdfOptions): Uint8Array<ArrayBuffer>;
|
|
20
22
|
//#endregion
|
package/dist/write.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { n as widthOfCode, p as winAnsiGlyphName, t as STANDARD_METRICS } from "./afm-widths-De_QMWgC.js";
|
|
2
2
|
import { NOTES_ANNOTATION_AUTHOR } from "./notes-annotation-author.js";
|
|
3
|
-
import { pdfArray, pdfDict, pdfHexString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
|
|
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
6
|
import { deflate } from "./bytes/flate.js";
|
|
7
7
|
import { base64ToBytes } from "./util/base64.js";
|
|
8
8
|
import { throwIfAborted } from "./util/abort.js";
|
|
9
|
+
import { randomBytes } from "./crypto/random.js";
|
|
10
|
+
import { createStandardEncryptor, encryptIndirectObject } from "./encrypt-write.js";
|
|
9
11
|
import { readJpegInfo } from "./image/jpeg-info.js";
|
|
10
12
|
import { decodePng } from "./image/png-decode.js";
|
|
11
13
|
import { collectEmbeddedGlyphs } from "./embedded-font.js";
|
|
@@ -29,6 +31,7 @@ const FLAG_SERIF = 2;
|
|
|
29
31
|
const FLAG_NONSYMBOLIC = 32;
|
|
30
32
|
const FLAG_ITALIC = 64;
|
|
31
33
|
const FLAG_FORCE_BOLD = 262144;
|
|
34
|
+
const FILE_ID_BYTES = 16;
|
|
32
35
|
function textToPdfString(text) {
|
|
33
36
|
const bytes = new Uint8Array(2 + text.length * 2);
|
|
34
37
|
bytes[0] = 254;
|
|
@@ -198,11 +201,14 @@ function destinationViewArray(target) {
|
|
|
198
201
|
if (target.kind === "fitBV") return [pdfName("FitBV"), n(target.leftPt)];
|
|
199
202
|
return [pdfName(target.kind === "fitB" ? "FitB" : "Fit")];
|
|
200
203
|
}
|
|
201
|
-
function
|
|
202
|
-
const destination = doc.destinations?.find((d) => d.name ===
|
|
203
|
-
if (destination === void 0) throw new Error(
|
|
204
|
+
function resolveDestinationArray(doc, pageAllocs, name, what) {
|
|
205
|
+
const destination = doc.destinations?.find((d) => d.name === name);
|
|
206
|
+
if (destination === void 0) throw new Error(`${what} names destination "${name}", which the document's destinations table does not carry -- this is a caller-invariant violation`);
|
|
204
207
|
const targetPage = pageAllocs[destination.pageIndex];
|
|
205
|
-
if (targetPage === void 0) throw new Error(`destination "${
|
|
208
|
+
if (targetPage === void 0) throw new Error(`destination "${destination.name}" names page index ${destination.pageIndex}, which is beyond the document's own pages -- this is a caller-invariant violation`);
|
|
209
|
+
return [pdfRef(targetPage.pageNum, 0), ...destinationViewArray(destination.target)];
|
|
210
|
+
}
|
|
211
|
+
function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
206
212
|
return pdfDict({
|
|
207
213
|
Type: pdfName("Annot"),
|
|
208
214
|
Subtype: pdfName("Link"),
|
|
@@ -217,7 +223,7 @@ function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
|
217
223
|
0,
|
|
218
224
|
0
|
|
219
225
|
].map((v) => pdfNum(v))),
|
|
220
|
-
Dest: pdfArray(
|
|
226
|
+
Dest: pdfArray(resolveDestinationArray(doc, pageAllocs, link.destination, "internal link"))
|
|
221
227
|
});
|
|
222
228
|
}
|
|
223
229
|
function isLinkItem(item) {
|
|
@@ -317,13 +323,29 @@ function writePdf(doc, options = {}) {
|
|
|
317
323
|
pageNum: nextObjNum++,
|
|
318
324
|
contentsNum: nextObjNum++
|
|
319
325
|
}));
|
|
326
|
+
const encryptDictNum = options.encryption === void 0 ? void 0 : nextObjNum++;
|
|
327
|
+
const attachmentAllocs = (doc.attachments ?? []).map(() => ({
|
|
328
|
+
fileNum: nextObjNum++,
|
|
329
|
+
specNum: nextObjNum++
|
|
330
|
+
}));
|
|
331
|
+
const attachmentsNamesNum = attachmentAllocs.length > 0 ? nextObjNum++ : void 0;
|
|
332
|
+
const outlineRootNum = (doc.outline ?? []).length > 0 ? nextObjNum++ : void 0;
|
|
333
|
+
const outlineItemNums = [];
|
|
334
|
+
if (outlineRootNum !== void 0) {
|
|
335
|
+
const countItems = (items) => {
|
|
336
|
+
let n = 0;
|
|
337
|
+
for (const item of items) n += 1 + countItems(item.children);
|
|
338
|
+
return n;
|
|
339
|
+
};
|
|
340
|
+
for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
|
|
341
|
+
}
|
|
320
342
|
const objects = [];
|
|
343
|
+
const catalogEntries = [["Type", pdfName("Catalog")], ["Pages", pdfRef(pagesNum, 0)]];
|
|
344
|
+
if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", pdfRef(attachmentsNamesNum, 0)]);
|
|
345
|
+
if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", pdfRef(outlineRootNum, 0)]);
|
|
321
346
|
objects.push({
|
|
322
347
|
num: catalogNum,
|
|
323
|
-
value: pdfDict(
|
|
324
|
-
Type: pdfName("Catalog"),
|
|
325
|
-
Pages: pdfRef(pagesNum, 0)
|
|
326
|
-
})
|
|
348
|
+
value: pdfDict(Object.fromEntries(catalogEntries))
|
|
327
349
|
});
|
|
328
350
|
objects.push({
|
|
329
351
|
num: pagesNum,
|
|
@@ -337,6 +359,73 @@ function writePdf(doc, options = {}) {
|
|
|
337
359
|
num: infoNum,
|
|
338
360
|
value: buildInfoDict(doc)
|
|
339
361
|
});
|
|
362
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
363
|
+
const alloc = attachmentAllocs[index];
|
|
364
|
+
const fileEntries = [["Type", pdfName("EmbeddedFile")]];
|
|
365
|
+
if (attachment.mimeType !== void 0) fileEntries.push(["Subtype", pdfName(attachment.mimeType)]);
|
|
366
|
+
objects.push({
|
|
367
|
+
num: alloc.fileNum,
|
|
368
|
+
value: pdfStream(pdfDict(Object.fromEntries(fileEntries)), base64ToBytes(attachment.base64))
|
|
369
|
+
});
|
|
370
|
+
const specEntries = [
|
|
371
|
+
["Type", pdfName("Filespec")],
|
|
372
|
+
["F", pdfLiteralString(new TextEncoder().encode(attachment.name))],
|
|
373
|
+
["EF", pdfDict({ F: pdfRef(alloc.fileNum, 0) })]
|
|
374
|
+
];
|
|
375
|
+
if (attachment.description !== void 0) specEntries.push(["Desc", pdfLiteralString(new TextEncoder().encode(attachment.description))]);
|
|
376
|
+
objects.push({
|
|
377
|
+
num: alloc.specNum,
|
|
378
|
+
value: pdfDict(Object.fromEntries(specEntries))
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
if (attachmentsNamesNum !== void 0) {
|
|
382
|
+
const names = [];
|
|
383
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
384
|
+
names.push(pdfLiteralString(new TextEncoder().encode(attachment.name)));
|
|
385
|
+
names.push(pdfRef(attachmentAllocs[index].specNum, 0));
|
|
386
|
+
}
|
|
387
|
+
objects.push({
|
|
388
|
+
num: attachmentsNamesNum,
|
|
389
|
+
value: pdfDict({ EmbeddedFiles: pdfDict({ Names: pdfArray(names) }) })
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
if (outlineRootNum !== void 0 && (doc.outline ?? []).length > 0) {
|
|
393
|
+
let itemCursor = 0;
|
|
394
|
+
const emitItems = (items, parentNum) => {
|
|
395
|
+
const siblingNums = [];
|
|
396
|
+
let prevNum;
|
|
397
|
+
for (const item of items) {
|
|
398
|
+
const ownNum = outlineItemNums[itemCursor];
|
|
399
|
+
itemCursor += 1;
|
|
400
|
+
siblingNums.push(ownNum);
|
|
401
|
+
const childNums = emitItems(item.children, ownNum);
|
|
402
|
+
const entries = [["Title", pdfLiteralString(new TextEncoder().encode(item.title))], ["Parent", pdfRef(parentNum, 0)]];
|
|
403
|
+
if (item.destination !== void 0) entries.push(["Dest", pdfArray(resolveDestinationArray(doc, pageAllocs, item.destination, `outline item "${item.title}"`))]);
|
|
404
|
+
if (prevNum !== void 0) entries.push(["Prev", pdfRef(prevNum, 0)]);
|
|
405
|
+
if (siblingNums.length < items.length) entries.push(["Next", pdfRef(outlineItemNums[itemCursor], 0)]);
|
|
406
|
+
if (childNums.length > 0) {
|
|
407
|
+
entries.push(["First", pdfRef(childNums[0], 0)]);
|
|
408
|
+
entries.push(["Last", pdfRef(childNums[childNums.length - 1], 0)]);
|
|
409
|
+
entries.push(["Count", pdfNum(childNums.length)]);
|
|
410
|
+
}
|
|
411
|
+
objects.push({
|
|
412
|
+
num: ownNum,
|
|
413
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
414
|
+
});
|
|
415
|
+
prevNum = ownNum;
|
|
416
|
+
}
|
|
417
|
+
return siblingNums;
|
|
418
|
+
};
|
|
419
|
+
const topLevelNums = emitItems(doc.outline ?? [], outlineRootNum);
|
|
420
|
+
objects.push({
|
|
421
|
+
num: outlineRootNum,
|
|
422
|
+
value: pdfDict({
|
|
423
|
+
Type: pdfName("Outlines"),
|
|
424
|
+
First: pdfRef(topLevelNums[0], 0),
|
|
425
|
+
Last: pdfRef(topLevelNums[topLevelNums.length - 1], 0)
|
|
426
|
+
})
|
|
427
|
+
});
|
|
428
|
+
}
|
|
340
429
|
for (const [standardName, alloc] of fontAllocs) {
|
|
341
430
|
const { font, descriptor } = buildFontObjects(standardName, pdfRef(alloc.descNum, 0));
|
|
342
431
|
objects.push({
|
|
@@ -501,10 +590,24 @@ function writePdf(doc, options = {}) {
|
|
|
501
590
|
value: pdfDict(pageEntries)
|
|
502
591
|
});
|
|
503
592
|
});
|
|
593
|
+
let fileId;
|
|
594
|
+
let encryptedObjects = objects;
|
|
595
|
+
if (options.encryption !== void 0 && encryptDictNum !== void 0) {
|
|
596
|
+
fileId = randomBytes(FILE_ID_BYTES);
|
|
597
|
+
const encryptor = createStandardEncryptor(options.encryption, fileId);
|
|
598
|
+
encryptedObjects = objects.map(({ num, value }) => ({
|
|
599
|
+
num,
|
|
600
|
+
value: encryptIndirectObject(value, num, 0, encryptor)
|
|
601
|
+
}));
|
|
602
|
+
encryptedObjects.push({
|
|
603
|
+
num: encryptDictNum,
|
|
604
|
+
value: encryptor.encryptDict
|
|
605
|
+
});
|
|
606
|
+
}
|
|
504
607
|
const writer = new ByteWriter();
|
|
505
608
|
writer.writeAscii("%PDF-1.7\n");
|
|
506
609
|
const offsets = /* @__PURE__ */ new Map();
|
|
507
|
-
for (const { num, value } of
|
|
610
|
+
for (const { num, value } of encryptedObjects) {
|
|
508
611
|
offsets.set(num, writer.length);
|
|
509
612
|
writer.writeAscii(`${num} 0 obj\n`);
|
|
510
613
|
writeObject(writer, value);
|
|
@@ -520,12 +623,17 @@ function writePdf(doc, options = {}) {
|
|
|
520
623
|
if (offset === void 0) throw new Error(`object ${num} was allocated but never written -- this is a writePdf internal invariant violation`);
|
|
521
624
|
writer.writeAscii(xrefEntry(offset, 0, true));
|
|
522
625
|
}
|
|
626
|
+
const trailerEntries = /* @__PURE__ */ new Map([
|
|
627
|
+
["Size", pdfNum(maxObjNum + 1)],
|
|
628
|
+
["Root", pdfRef(catalogNum, 0)],
|
|
629
|
+
["Info", pdfRef(infoNum, 0)]
|
|
630
|
+
]);
|
|
631
|
+
if (fileId !== void 0 && encryptDictNum !== void 0) {
|
|
632
|
+
trailerEntries.set("ID", pdfArray([pdfHexString(fileId), pdfHexString(fileId)]));
|
|
633
|
+
trailerEntries.set("Encrypt", pdfRef(encryptDictNum, 0));
|
|
634
|
+
}
|
|
523
635
|
writer.writeAscii("trailer\n");
|
|
524
|
-
writeObject(writer, pdfDict(
|
|
525
|
-
Size: pdfNum(maxObjNum + 1),
|
|
526
|
-
Root: pdfRef(catalogNum, 0),
|
|
527
|
-
Info: pdfRef(infoNum, 0)
|
|
528
|
-
}));
|
|
636
|
+
writeObject(writer, pdfDict(trailerEntries));
|
|
529
637
|
writer.writeAscii("\nstartxref\n");
|
|
530
638
|
writer.writeAscii(`${xrefOffset}\n`);
|
|
531
639
|
writer.writeAscii("%%EOF");
|
package/dist/xref.d.cts
CHANGED
package/dist/xref.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdf-codec",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.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": {
|