pdf-parser.js 3.0.7 → 4.5.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/README.md +105 -54
- package/dist/{afm-widths-Dxucrg7D.js → afm-widths-BTu0IDp2.cjs} +1517 -4
- package/dist/{afm-widths-DyDq56Ph.d.cts → afm-widths-CneRyu5l.d.cts} +1 -1
- package/dist/{afm-widths-DyDq56Ph.d.ts → afm-widths-CneRyu5l.d.ts} +1 -1
- package/dist/{afm-widths-BoeTOK2r.cjs → afm-widths-De_QMWgC.js} +1416 -51
- package/dist/afm-widths.cjs +1 -1
- package/dist/afm-widths.d.cts +1 -1
- package/dist/afm-widths.d.ts +1 -1
- package/dist/afm-widths.js +1 -1
- package/dist/annotations.cjs +104 -0
- package/dist/annotations.d.cts +9 -0
- package/dist/annotations.d.ts +9 -0
- package/dist/annotations.js +103 -0
- package/dist/attachments.cjs +65 -0
- package/dist/attachments.d.cts +8 -0
- package/dist/attachments.d.ts +8 -0
- package/dist/attachments.js +64 -0
- package/dist/builtin-encoding.cjs +221 -0
- package/dist/builtin-encoding.d.cts +8 -0
- package/dist/builtin-encoding.d.ts +8 -0
- package/dist/builtin-encoding.js +220 -0
- package/dist/bytes/flate.cjs +1 -1
- package/dist/bytes/flate.js +1 -1
- package/dist/cff.cjs +14 -0
- package/dist/cff.d.cts +4 -1
- package/dist/cff.d.ts +4 -1
- package/dist/cff.js +12 -1
- package/dist/cmap-table.cjs +76 -13
- package/dist/cmap-table.d.cts +9 -1
- package/dist/cmap-table.d.ts +9 -1
- package/dist/cmap-table.js +77 -15
- package/dist/codec.cjs +1 -1
- package/dist/codec.d.cts +134 -0
- package/dist/codec.d.ts +134 -0
- package/dist/codec.js +1 -1
- package/dist/content-read.cjs +1 -1
- package/dist/content-read.d.cts +3 -3
- package/dist/content-read.d.ts +3 -3
- package/dist/content-read.js +1 -1
- package/dist/content-write.cjs +32 -10
- package/dist/content-write.d.cts +12 -5
- package/dist/content-write.d.ts +12 -5
- package/dist/content-write.js +32 -10
- 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/diagnostics.d.cts +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/document.cjs +12 -3
- package/dist/document.d.cts +3 -1
- package/dist/document.d.ts +3 -1
- package/dist/document.js +12 -3
- 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.cjs +1 -1
- package/dist/embedded-font-write.d.cts +3 -3
- package/dist/embedded-font-write.d.ts +3 -3
- package/dist/embedded-font-write.js +1 -1
- 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/encoding.cjs +10 -1
- package/dist/encoding.d.cts +10 -1
- package/dist/encoding.d.ts +10 -1
- package/dist/encoding.js +2 -2
- 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 +51 -21
- package/dist/encrypt.d.cts +19 -3
- package/dist/encrypt.d.ts +19 -3
- package/dist/encrypt.js +36 -22
- package/dist/filters.cjs +18 -14
- package/dist/filters.d.cts +1 -1
- package/dist/filters.d.ts +1 -1
- package/dist/filters.js +18 -14
- package/dist/font-read.cjs +68 -13
- package/dist/font-read.d.cts +1 -1
- package/dist/font-read.d.ts +1 -1
- package/dist/font-read.js +69 -14
- package/dist/font-registry.cjs +1 -1
- package/dist/font-registry.d.cts +4 -4
- package/dist/font-registry.d.ts +4 -4
- package/dist/font-registry.js +1 -1
- package/dist/font-substitutes.d.cts +1 -1
- package/dist/font-substitutes.d.ts +1 -1
- package/dist/font-tables.cjs +31 -0
- package/dist/font-tables.d.cts +3 -1
- package/dist/font-tables.d.ts +3 -1
- package/dist/font-tables.js +31 -2
- package/dist/fonts.d.cts +2 -2
- package/dist/fonts.d.ts +2 -2
- package/dist/form.cjs +138 -0
- package/dist/form.d.cts +9 -0
- package/dist/form.d.ts +9 -0
- package/dist/form.js +137 -0
- 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/image/ccitt-encode.cjs +119 -0
- package/dist/image/ccitt-encode.d.cts +9 -0
- package/dist/image/ccitt-encode.d.ts +9 -0
- package/dist/image/ccitt-encode.js +118 -0
- package/dist/image/ccitt.cjs +3 -0
- package/dist/image/ccitt.d.cts +4 -1
- package/dist/image/ccitt.d.ts +4 -1
- package/dist/image/ccitt.js +1 -1
- package/dist/image/jbig2-bitmap.d.cts +1 -1
- package/dist/image/jbig2-bitmap.d.ts +1 -1
- package/dist/image/jbig2.cjs +3 -1
- package/dist/image/jbig2.js +3 -1
- package/dist/image/jp2-boxes.d.cts +1 -1
- package/dist/image/jp2-boxes.d.ts +1 -1
- package/dist/image/jpeg2000-codestream.d.cts +3 -3
- package/dist/image/jpeg2000-codestream.d.ts +3 -3
- package/dist/image/jpeg2000-t1.d.cts +1 -1
- package/dist/image/jpeg2000-t1.d.ts +1 -1
- package/dist/image/jpeg2000.cjs +1 -0
- package/dist/image/jpeg2000.d.cts +3 -0
- package/dist/image/jpeg2000.d.ts +3 -0
- package/dist/image/jpeg2000.js +1 -0
- package/dist/image/png-decode.cjs +1 -1
- package/dist/image/png-decode.js +1 -1
- package/dist/image/png-filter.d.cts +1 -1
- package/dist/image/png-filter.d.ts +1 -1
- package/dist/images-read.cjs +18 -12
- package/dist/images-read.d.cts +2 -2
- package/dist/images-read.d.ts +2 -2
- package/dist/images-read.js +15 -9
- package/dist/index.cjs +17 -4
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +6 -5
- package/dist/interpret.cjs +178 -56
- package/dist/interpret.d.cts +27 -12
- package/dist/interpret.d.ts +27 -12
- package/dist/interpret.js +178 -56
- package/dist/layout.cjs +149 -2
- package/dist/layout.d.cts +394 -1
- package/dist/layout.d.ts +394 -1
- package/dist/layout.js +140 -4
- package/dist/lexer.d.cts +9 -9
- package/dist/lexer.d.ts +9 -9
- package/dist/math-content-write.cjs +1 -1
- package/dist/math-content-write.js +1 -1
- package/dist/math-font-write.cjs +1 -1
- package/dist/math-font-write.d.cts +1 -1
- package/dist/math-font-write.d.ts +1 -1
- package/dist/math-font-write.js +1 -1
- package/dist/math-font.cjs +2 -2
- package/dist/math-font.d.cts +1 -1
- package/dist/math-font.d.ts +1 -1
- package/dist/math-font.js +2 -2
- package/dist/{math-stretch-a_rHNRvc.d.ts → math-stretch-BbC2o4Br.d.ts} +1 -1
- package/dist/{math-stretch-E26z6byT.d.cts → math-stretch-C2JanDAz.d.cts} +1 -1
- package/dist/math-stretch.d.cts +1 -1
- package/dist/math-stretch.d.ts +1 -1
- package/dist/measure.cjs +1 -1
- package/dist/measure.d.cts +1 -1
- package/dist/measure.d.ts +1 -1
- package/dist/measure.js +1 -1
- package/dist/names.cjs +41 -0
- package/dist/names.d.cts +11 -0
- package/dist/names.d.ts +11 -0
- package/dist/names.js +40 -0
- package/dist/navigation.cjs +210 -0
- package/dist/navigation.d.cts +18 -0
- package/dist/navigation.d.ts +18 -0
- package/dist/navigation.js +207 -0
- package/dist/notes-annotation-author.cjs +5 -0
- package/dist/notes-annotation-author.d.cts +4 -0
- package/dist/notes-annotation-author.d.ts +4 -0
- package/dist/notes-annotation-author.js +4 -0
- 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.cjs +63 -0
- package/dist/optional-content.d.cts +12 -0
- package/dist/optional-content.d.ts +12 -0
- package/dist/optional-content.js +62 -0
- package/dist/parse.cjs +1 -1
- package/dist/parse.d.cts +2 -2
- package/dist/parse.d.ts +2 -2
- package/dist/parse.js +1 -1
- package/dist/pdf-text.cjs +21 -0
- package/dist/pdf-text.d.cts +5 -0
- package/dist/pdf-text.d.ts +5 -0
- package/dist/pdf-text.js +19 -0
- package/dist/predictors.d.cts +1 -1
- package/dist/predictors.d.ts +1 -1
- package/dist/read.cjs +287 -72
- package/dist/read.d.cts +2 -4
- package/dist/read.d.ts +2 -4
- package/dist/read.js +284 -67
- package/dist/serialize.cjs +5 -1
- package/dist/serialize.d.cts +3 -2
- package/dist/serialize.d.ts +3 -2
- package/dist/serialize.js +5 -2
- 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/structure.cjs +184 -0
- package/dist/structure.d.cts +12 -0
- package/dist/structure.d.ts +12 -0
- package/dist/structure.js +183 -0
- package/dist/tounicode.cjs +8 -3
- package/dist/tounicode.d.cts +2 -2
- package/dist/tounicode.d.ts +2 -2
- package/dist/tounicode.js +8 -3
- package/dist/util/base64.cjs +4 -4
- package/dist/util/base64.js +4 -4
- package/dist/winansi.cjs +1 -1
- package/dist/winansi.d.cts +1 -1
- package/dist/winansi.d.ts +1 -1
- package/dist/winansi.js +1 -1
- package/dist/write.cjs +464 -21
- package/dist/write.d.cts +4 -3
- package/dist/write.d.ts +4 -3
- package/dist/write.js +464 -20
- package/dist/xmp.cjs +46 -0
- package/dist/xmp.d.cts +14 -0
- package/dist/xmp.d.ts +14 -0
- package/dist/xmp.js +45 -0
- package/dist/xref.cjs +2 -2
- package/dist/xref.d.cts +3 -3
- package/dist/xref.d.ts +3 -3
- package/dist/xref.js +2 -2
- package/package.json +46 -31
- package/dist/image/png-encode.cjs +0 -64
- package/dist/image/png-encode.d.cts +0 -8
- package/dist/image/png-encode.d.ts +0 -8
- package/dist/image/png-encode.js +0 -63
package/dist/write.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { n as widthOfCode, p as winAnsiGlyphName, t as STANDARD_METRICS } from "./afm-widths-De_QMWgC.js";
|
|
2
|
+
import { NOTES_ANNOTATION_AUTHOR } from "./notes-annotation-author.js";
|
|
3
|
+
import { pdfArray, pdfBool, pdfDict, pdfHexString, pdfLiteralString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
|
|
3
4
|
import { ByteWriter, concatBytes } from "./bytes/writer.js";
|
|
4
|
-
import {
|
|
5
|
+
import { writeObject } from "./serialize.js";
|
|
6
|
+
import { ByteReader } from "./bytes/reader.js";
|
|
5
7
|
import { deflate } from "./bytes/flate.js";
|
|
8
|
+
import { base64ToBytes } from "./util/base64.js";
|
|
9
|
+
import { parseValue } from "./parse.js";
|
|
6
10
|
import { throwIfAborted } from "./util/abort.js";
|
|
11
|
+
import { randomBytes } from "./crypto/random.js";
|
|
12
|
+
import { createStandardEncryptor, encryptIndirectObject } from "./encrypt-write.js";
|
|
7
13
|
import { readJpegInfo } from "./image/jpeg-info.js";
|
|
14
|
+
import { encodeCcittFax } from "./image/ccitt-encode.js";
|
|
8
15
|
import { decodePng } from "./image/png-decode.js";
|
|
9
16
|
import { collectEmbeddedGlyphs } from "./embedded-font.js";
|
|
10
|
-
import { writeObject } from "./serialize.js";
|
|
11
17
|
import { writeContentStream } from "./content-write.js";
|
|
12
18
|
import { buildEmbeddedFontObjects } from "./embedded-font-write.js";
|
|
13
19
|
import { resolveFaceWithRegistry } from "./font-registry.js";
|
|
@@ -28,6 +34,7 @@ const FLAG_SERIF = 2;
|
|
|
28
34
|
const FLAG_NONSYMBOLIC = 32;
|
|
29
35
|
const FLAG_ITALIC = 64;
|
|
30
36
|
const FLAG_FORCE_BOLD = 262144;
|
|
37
|
+
const FILE_ID_BYTES = 16;
|
|
31
38
|
function textToPdfString(text) {
|
|
32
39
|
const bytes = new Uint8Array(2 + text.length * 2);
|
|
33
40
|
bytes[0] = 254;
|
|
@@ -138,9 +145,57 @@ function pngImageDict(width, height, colorSpace, compress) {
|
|
|
138
145
|
if (compress) entries.set("Filter", pdfName("FlateDecode"));
|
|
139
146
|
return pdfDict(entries);
|
|
140
147
|
}
|
|
148
|
+
function packBilevel(raw) {
|
|
149
|
+
const rowBytes = raw.width + 7 >> 3;
|
|
150
|
+
const packed = new Uint8Array(rowBytes * raw.height);
|
|
151
|
+
for (let y = 0; y < raw.height; y++) for (let x = 0; x < raw.width; x++) {
|
|
152
|
+
const sample = raw.data[y * raw.width + x] ?? 0;
|
|
153
|
+
if (sample !== 0 && sample !== 255) return;
|
|
154
|
+
if (sample === 255) {
|
|
155
|
+
const index = y * rowBytes + (x >> 3);
|
|
156
|
+
packed[index] = (packed[index] ?? 0) | 128 >> (x & 7);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return packed;
|
|
160
|
+
}
|
|
141
161
|
function preparePngImage(bytes, compress) {
|
|
142
162
|
const raw = decodePng(bytes);
|
|
143
163
|
const colorSpace = raw.channels === 1 ? "DeviceGray" : "DeviceRGB";
|
|
164
|
+
if (compress && raw.channels === 1 && raw.alpha === void 0) {
|
|
165
|
+
const bilevel = packBilevel(raw);
|
|
166
|
+
if (bilevel !== void 0) {
|
|
167
|
+
const flate = deflate(raw.data);
|
|
168
|
+
const g4 = encodeCcittFax(bilevel, {
|
|
169
|
+
columns: raw.width,
|
|
170
|
+
rows: raw.height,
|
|
171
|
+
maxBytes: flate.length
|
|
172
|
+
});
|
|
173
|
+
if (g4 !== void 0) return {
|
|
174
|
+
dict: pdfDict(/* @__PURE__ */ new Map([
|
|
175
|
+
["Type", pdfName("XObject")],
|
|
176
|
+
["Subtype", pdfName("Image")],
|
|
177
|
+
["Width", pdfNum(raw.width)],
|
|
178
|
+
["Height", pdfNum(raw.height)],
|
|
179
|
+
["ColorSpace", pdfName("DeviceGray")],
|
|
180
|
+
["BitsPerComponent", pdfNum(1)],
|
|
181
|
+
["Filter", pdfName("CCITTFaxDecode")],
|
|
182
|
+
["DecodeParms", pdfDict(/* @__PURE__ */ new Map([
|
|
183
|
+
["K", pdfNum(-1)],
|
|
184
|
+
["Columns", pdfNum(raw.width)],
|
|
185
|
+
["Rows", pdfNum(raw.height)],
|
|
186
|
+
["BlackIs1", pdfBool(false)]
|
|
187
|
+
]))]
|
|
188
|
+
])),
|
|
189
|
+
raw: g4,
|
|
190
|
+
alpha: void 0
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
dict: pngImageDict(raw.width, raw.height, colorSpace, true),
|
|
194
|
+
raw: flate,
|
|
195
|
+
alpha: void 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
144
199
|
return {
|
|
145
200
|
dict: pngImageDict(raw.width, raw.height, colorSpace, compress),
|
|
146
201
|
raw: compress ? deflate(raw.data) : raw.data,
|
|
@@ -176,11 +231,59 @@ function buildLinkAnnotDict(link) {
|
|
|
176
231
|
})
|
|
177
232
|
});
|
|
178
233
|
}
|
|
234
|
+
function destinationViewArray(target) {
|
|
235
|
+
const n = (value) => value === void 0 ? pdfNull() : pdfNum(value);
|
|
236
|
+
if (target.kind === "xyz") return [
|
|
237
|
+
pdfName("XYZ"),
|
|
238
|
+
n(target.leftPt),
|
|
239
|
+
n(target.topPt),
|
|
240
|
+
n(target.zoom)
|
|
241
|
+
];
|
|
242
|
+
if (target.kind === "fitH") return [pdfName("FitH"), n(target.topPt)];
|
|
243
|
+
if (target.kind === "fitV") return [pdfName("FitV"), n(target.leftPt)];
|
|
244
|
+
if (target.kind === "fitR") return [
|
|
245
|
+
pdfName("FitR"),
|
|
246
|
+
n(target.leftPt),
|
|
247
|
+
n(target.bottomPt),
|
|
248
|
+
n(target.rightPt),
|
|
249
|
+
n(target.topPt)
|
|
250
|
+
];
|
|
251
|
+
if (target.kind === "fitBH") return [pdfName("FitBH"), n(target.topPt)];
|
|
252
|
+
if (target.kind === "fitBV") return [pdfName("FitBV"), n(target.leftPt)];
|
|
253
|
+
return [pdfName(target.kind === "fitB" ? "FitB" : "Fit")];
|
|
254
|
+
}
|
|
255
|
+
function resolveDestinationArray(doc, pageAllocs, name, what) {
|
|
256
|
+
const destination = doc.destinations?.find((d) => d.name === name);
|
|
257
|
+
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`);
|
|
258
|
+
const targetPage = pageAllocs[destination.pageIndex];
|
|
259
|
+
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`);
|
|
260
|
+
return [pdfRef(targetPage.pageNum, 0), ...destinationViewArray(destination.target)];
|
|
261
|
+
}
|
|
262
|
+
function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
263
|
+
return pdfDict({
|
|
264
|
+
Type: pdfName("Annot"),
|
|
265
|
+
Subtype: pdfName("Link"),
|
|
266
|
+
Rect: pdfArray([
|
|
267
|
+
link.xPt,
|
|
268
|
+
link.yPt,
|
|
269
|
+
link.xPt + link.widthPt,
|
|
270
|
+
link.yPt + link.heightPt
|
|
271
|
+
].map((v) => pdfNum(v))),
|
|
272
|
+
Border: pdfArray([
|
|
273
|
+
0,
|
|
274
|
+
0,
|
|
275
|
+
0
|
|
276
|
+
].map((v) => pdfNum(v))),
|
|
277
|
+
Dest: pdfArray(resolveDestinationArray(doc, pageAllocs, link.destination, "internal link"))
|
|
278
|
+
});
|
|
279
|
+
}
|
|
179
280
|
function isLinkItem(item) {
|
|
180
281
|
return item.kind === "link";
|
|
181
282
|
}
|
|
283
|
+
function isInternalLinkItem(item) {
|
|
284
|
+
return item.kind === "internalLink";
|
|
285
|
+
}
|
|
182
286
|
const NOTES_ANNOTATION_HIDDEN_FLAG = 2;
|
|
183
|
-
const NOTES_ANNOTATION_AUTHOR = "documents.js:notes";
|
|
184
287
|
function buildNotesAnnotDict(notes) {
|
|
185
288
|
return pdfDict({
|
|
186
289
|
Type: pdfName("Annot"),
|
|
@@ -199,6 +302,24 @@ function buildNotesAnnotDict(notes) {
|
|
|
199
302
|
function xrefEntry(offset, generation, inUse) {
|
|
200
303
|
return `${offset.toString().padStart(10, "0")} ${generation.toString().padStart(5, "0")} ${inUse ? "n" : "f"} \n`;
|
|
201
304
|
}
|
|
305
|
+
function parseResidueRow(residue) {
|
|
306
|
+
const reader = new ByteReader(new TextEncoder().encode(residue.xml));
|
|
307
|
+
return parseValue(reader, () => {});
|
|
308
|
+
}
|
|
309
|
+
function objectContainsReference(obj) {
|
|
310
|
+
if (obj.kind === "ref") return true;
|
|
311
|
+
if (obj.kind === "array") return obj.items.some(objectContainsReference);
|
|
312
|
+
if (obj.kind === "dict") return [...obj.entries.values()].some(objectContainsReference);
|
|
313
|
+
if (obj.kind === "stream") return [...obj.dict.entries.values()].some(objectContainsReference);
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
function restoreResidueRow(source, key) {
|
|
317
|
+
const row = source?.[key];
|
|
318
|
+
if (row === void 0) return;
|
|
319
|
+
const parsed = parseResidueRow(row);
|
|
320
|
+
if (parsed === void 0 || objectContainsReference(parsed)) return;
|
|
321
|
+
return parsed;
|
|
322
|
+
}
|
|
202
323
|
function writePdf(doc, options = {}) {
|
|
203
324
|
const compress = options.compress ?? true;
|
|
204
325
|
const registry = options.fonts;
|
|
@@ -271,13 +392,99 @@ function writePdf(doc, options = {}) {
|
|
|
271
392
|
pageNum: nextObjNum++,
|
|
272
393
|
contentsNum: nextObjNum++
|
|
273
394
|
}));
|
|
395
|
+
const encryptDictNum = options.encryption === void 0 ? void 0 : nextObjNum++;
|
|
396
|
+
const attachmentAllocs = (doc.attachments ?? []).map(() => ({
|
|
397
|
+
fileNum: nextObjNum++,
|
|
398
|
+
specNum: nextObjNum++
|
|
399
|
+
}));
|
|
400
|
+
const attachmentsNamesNum = attachmentAllocs.length > 0 ? nextObjNum++ : void 0;
|
|
401
|
+
const outlineRootNum = (doc.outline ?? []).length > 0 ? nextObjNum++ : void 0;
|
|
402
|
+
const outlineItemNums = [];
|
|
403
|
+
if (outlineRootNum !== void 0) {
|
|
404
|
+
const countItems = (items) => {
|
|
405
|
+
let n = 0;
|
|
406
|
+
for (const item of items) n += 1 + countItems(item.children);
|
|
407
|
+
return n;
|
|
408
|
+
};
|
|
409
|
+
for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
|
|
410
|
+
}
|
|
411
|
+
const layerNumByName = /* @__PURE__ */ new Map();
|
|
412
|
+
for (const layer of doc.layers ?? []) layerNumByName.set(layer.name, nextObjNum++);
|
|
413
|
+
const formObjectNums = [];
|
|
414
|
+
const countFieldObjects = (fields) => {
|
|
415
|
+
let n = 0;
|
|
416
|
+
for (const field of fields) n += 1 + (field.fieldType !== "group" && field.widgets.length > 1 ? field.widgets.length - 1 : 0) + countFieldObjects(field.children);
|
|
417
|
+
return n;
|
|
418
|
+
};
|
|
419
|
+
for (let i = 0; i < countFieldObjects(doc.form ?? []); i += 1) formObjectNums.push(nextObjNum++);
|
|
420
|
+
const formNumByField = /* @__PURE__ */ new Map();
|
|
421
|
+
const formExtraWidgetNums = /* @__PURE__ */ new Map();
|
|
422
|
+
let formNumCursor = 0;
|
|
423
|
+
const claimFormNums = (fields) => {
|
|
424
|
+
for (const field of fields) {
|
|
425
|
+
formNumByField.set(field, formObjectNums[formNumCursor++]);
|
|
426
|
+
if (field.fieldType !== "group" && field.widgets.length > 1) formExtraWidgetNums.set(field, field.widgets.slice(1).map(() => formObjectNums[formNumCursor++]));
|
|
427
|
+
claimFormNums(field.children);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
claimFormNums(doc.form ?? []);
|
|
431
|
+
const formNumOf = (field) => {
|
|
432
|
+
const num = formNumByField.get(field);
|
|
433
|
+
if (num === void 0) throw new Error("AcroForm field object number was not claimed -- this is a writePdf internal invariant violation");
|
|
434
|
+
return num;
|
|
435
|
+
};
|
|
436
|
+
const structElementNumById = /* @__PURE__ */ new Map();
|
|
437
|
+
const countElements = (elements) => {
|
|
438
|
+
let n = 0;
|
|
439
|
+
for (const element of elements) {
|
|
440
|
+
structElementNumById.set(element.id, nextObjNum++);
|
|
441
|
+
n += 1 + countElements(element.children);
|
|
442
|
+
}
|
|
443
|
+
return n;
|
|
444
|
+
};
|
|
445
|
+
const structElementCount = countElements(doc.structure ?? []);
|
|
446
|
+
const structRootNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
447
|
+
const structParentTreeNum = structElementCount > 0 ? nextObjNum++ : void 0;
|
|
448
|
+
const residueXmpNum = doc.source?.xmp !== void 0 ? nextObjNum++ : void 0;
|
|
274
449
|
const objects = [];
|
|
450
|
+
const catalogEntries = [["Type", pdfName("Catalog")], ["Pages", pdfRef(pagesNum, 0)]];
|
|
451
|
+
if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", pdfRef(attachmentsNamesNum, 0)]);
|
|
452
|
+
if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", pdfRef(outlineRootNum, 0)]);
|
|
453
|
+
if (layerNumByName.size > 0) {
|
|
454
|
+
const ocgRefs = [...layerNumByName.values()].map((num) => pdfRef(num, 0));
|
|
455
|
+
const visible = [];
|
|
456
|
+
const hidden = [];
|
|
457
|
+
for (const layer of doc.layers ?? []) {
|
|
458
|
+
const num = layerNumByName.get(layer.name);
|
|
459
|
+
(layer.visible ? visible : hidden).push(pdfRef(num, 0));
|
|
460
|
+
}
|
|
461
|
+
const defaultConfigEntries = [];
|
|
462
|
+
if (visible.length > 0) defaultConfigEntries.push(["ON", pdfArray(visible)]);
|
|
463
|
+
if (hidden.length > 0) defaultConfigEntries.push(["OFF", pdfArray(hidden)]);
|
|
464
|
+
catalogEntries.push(["OCProperties", pdfDict({
|
|
465
|
+
OCGs: pdfArray(ocgRefs),
|
|
466
|
+
D: pdfDict(Object.fromEntries(defaultConfigEntries))
|
|
467
|
+
})]);
|
|
468
|
+
}
|
|
469
|
+
if (doc.form !== void 0 && doc.form.length > 0) catalogEntries.push(["AcroForm", pdfDict({ Fields: pdfArray(doc.form.map((field) => pdfRef(formNumOf(field), 0))) })]);
|
|
470
|
+
if (structRootNum !== void 0) catalogEntries.push(["StructTreeRoot", pdfRef(structRootNum, 0)]);
|
|
471
|
+
if (residueXmpNum !== void 0) catalogEntries.push(["Metadata", pdfRef(residueXmpNum, 0)]);
|
|
472
|
+
const trailerIdRestore = restoreResidueRow(doc.source, "trailer-id");
|
|
473
|
+
for (const [rowKey, catalogKey] of [
|
|
474
|
+
["viewer-preferences", "ViewerPreferences"],
|
|
475
|
+
["page-mode", "PageMode"],
|
|
476
|
+
["page-layout", "PageLayout"],
|
|
477
|
+
["output-intents", "OutputIntents"],
|
|
478
|
+
["piece-info", "PieceInfo"],
|
|
479
|
+
["legal", "Legal"],
|
|
480
|
+
["collection", "Collection"]
|
|
481
|
+
]) {
|
|
482
|
+
const restored = restoreResidueRow(doc.source, rowKey);
|
|
483
|
+
if (restored !== void 0) catalogEntries.push([catalogKey, restored]);
|
|
484
|
+
}
|
|
275
485
|
objects.push({
|
|
276
486
|
num: catalogNum,
|
|
277
|
-
value: pdfDict(
|
|
278
|
-
Type: pdfName("Catalog"),
|
|
279
|
-
Pages: pdfRef(pagesNum, 0)
|
|
280
|
-
})
|
|
487
|
+
value: pdfDict(Object.fromEntries(catalogEntries))
|
|
281
488
|
});
|
|
282
489
|
objects.push({
|
|
283
490
|
num: pagesNum,
|
|
@@ -291,6 +498,185 @@ function writePdf(doc, options = {}) {
|
|
|
291
498
|
num: infoNum,
|
|
292
499
|
value: buildInfoDict(doc)
|
|
293
500
|
});
|
|
501
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
502
|
+
const alloc = attachmentAllocs[index];
|
|
503
|
+
const fileEntries = [["Type", pdfName("EmbeddedFile")]];
|
|
504
|
+
if (attachment.mimeType !== void 0) fileEntries.push(["Subtype", pdfName(attachment.mimeType)]);
|
|
505
|
+
objects.push({
|
|
506
|
+
num: alloc.fileNum,
|
|
507
|
+
value: pdfStream(pdfDict(Object.fromEntries(fileEntries)), base64ToBytes(attachment.base64))
|
|
508
|
+
});
|
|
509
|
+
const specEntries = [
|
|
510
|
+
["Type", pdfName("Filespec")],
|
|
511
|
+
["F", pdfLiteralString(new TextEncoder().encode(attachment.name))],
|
|
512
|
+
["EF", pdfDict({ F: pdfRef(alloc.fileNum, 0) })]
|
|
513
|
+
];
|
|
514
|
+
if (attachment.description !== void 0) specEntries.push(["Desc", pdfLiteralString(new TextEncoder().encode(attachment.description))]);
|
|
515
|
+
objects.push({
|
|
516
|
+
num: alloc.specNum,
|
|
517
|
+
value: pdfDict(Object.fromEntries(specEntries))
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
if (attachmentsNamesNum !== void 0) {
|
|
521
|
+
const names = [];
|
|
522
|
+
for (const [index, attachment] of (doc.attachments ?? []).entries()) {
|
|
523
|
+
names.push(pdfLiteralString(new TextEncoder().encode(attachment.name)));
|
|
524
|
+
names.push(pdfRef(attachmentAllocs[index].specNum, 0));
|
|
525
|
+
}
|
|
526
|
+
objects.push({
|
|
527
|
+
num: attachmentsNamesNum,
|
|
528
|
+
value: pdfDict({ EmbeddedFiles: pdfDict({ Names: pdfArray(names) }) })
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
if (outlineRootNum !== void 0 && (doc.outline ?? []).length > 0) {
|
|
532
|
+
let itemCursor = 0;
|
|
533
|
+
const emitItems = (items, parentNum) => {
|
|
534
|
+
const siblingNums = [];
|
|
535
|
+
let prevNum;
|
|
536
|
+
for (const item of items) {
|
|
537
|
+
const ownNum = outlineItemNums[itemCursor];
|
|
538
|
+
itemCursor += 1;
|
|
539
|
+
siblingNums.push(ownNum);
|
|
540
|
+
const childNums = emitItems(item.children, ownNum);
|
|
541
|
+
const entries = [["Title", pdfLiteralString(new TextEncoder().encode(item.title))], ["Parent", pdfRef(parentNum, 0)]];
|
|
542
|
+
if (item.destination !== void 0) entries.push(["Dest", pdfArray(resolveDestinationArray(doc, pageAllocs, item.destination, `outline item "${item.title}"`))]);
|
|
543
|
+
if (prevNum !== void 0) entries.push(["Prev", pdfRef(prevNum, 0)]);
|
|
544
|
+
if (siblingNums.length < items.length) entries.push(["Next", pdfRef(outlineItemNums[itemCursor], 0)]);
|
|
545
|
+
if (childNums.length > 0) {
|
|
546
|
+
entries.push(["First", pdfRef(childNums[0], 0)]);
|
|
547
|
+
entries.push(["Last", pdfRef(childNums[childNums.length - 1], 0)]);
|
|
548
|
+
entries.push(["Count", pdfNum(childNums.length)]);
|
|
549
|
+
}
|
|
550
|
+
objects.push({
|
|
551
|
+
num: ownNum,
|
|
552
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
553
|
+
});
|
|
554
|
+
prevNum = ownNum;
|
|
555
|
+
}
|
|
556
|
+
return siblingNums;
|
|
557
|
+
};
|
|
558
|
+
const topLevelNums = emitItems(doc.outline ?? [], outlineRootNum);
|
|
559
|
+
objects.push({
|
|
560
|
+
num: outlineRootNum,
|
|
561
|
+
value: pdfDict({
|
|
562
|
+
Type: pdfName("Outlines"),
|
|
563
|
+
First: pdfRef(topLevelNums[0], 0),
|
|
564
|
+
Last: pdfRef(topLevelNums[topLevelNums.length - 1], 0)
|
|
565
|
+
})
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
for (const layer of doc.layers ?? []) {
|
|
569
|
+
const num = layerNumByName.get(layer.name);
|
|
570
|
+
objects.push({
|
|
571
|
+
num,
|
|
572
|
+
value: pdfDict({
|
|
573
|
+
Type: pdfName("OCG"),
|
|
574
|
+
Name: pdfLiteralString(new TextEncoder().encode(layer.name))
|
|
575
|
+
})
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
const widgetRectArray = (widget) => pdfArray([
|
|
579
|
+
widget.xPt,
|
|
580
|
+
widget.yPt,
|
|
581
|
+
widget.xPt + widget.widthPt,
|
|
582
|
+
widget.yPt + widget.heightPt
|
|
583
|
+
].map((n) => pdfNum(n)));
|
|
584
|
+
const widgetDict = (widget) => pdfDict({
|
|
585
|
+
Subtype: pdfName("Widget"),
|
|
586
|
+
Rect: widgetRectArray(widget),
|
|
587
|
+
P: pdfRef(pageAllocs[widget.pageIndex].pageNum, 0)
|
|
588
|
+
});
|
|
589
|
+
const FIELD_TYPE_PDF_NAME = {
|
|
590
|
+
text: "Tx",
|
|
591
|
+
checkbox: "Btn",
|
|
592
|
+
radio: "Btn",
|
|
593
|
+
button: "Btn",
|
|
594
|
+
listbox: "Ch",
|
|
595
|
+
combobox: "Ch",
|
|
596
|
+
signature: "Sig"
|
|
597
|
+
};
|
|
598
|
+
const emitFormFieldObjects = (fields, parentName) => {
|
|
599
|
+
for (const field of fields) {
|
|
600
|
+
const ownName = parentName.length > 0 && field.name.startsWith(`${parentName}.`) ? field.name.slice(parentName.length + 1) : field.name;
|
|
601
|
+
const entries = [];
|
|
602
|
+
if (ownName.length > 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(ownName))]);
|
|
603
|
+
if (field.alias !== void 0) entries.push(["TU", pdfLiteralString(new TextEncoder().encode(field.alias))]);
|
|
604
|
+
if (field.fieldType === "group") entries.push(["Kids", pdfArray(field.children.map((child) => pdfRef(formNumOf(child), 0)))]);
|
|
605
|
+
else {
|
|
606
|
+
entries.push(["FT", pdfName(FIELD_TYPE_PDF_NAME[field.fieldType])]);
|
|
607
|
+
const FLAG_READ_ONLY = 1;
|
|
608
|
+
const FLAG_PUSHBUTTON = 4;
|
|
609
|
+
const FLAG_RADIO = 32768;
|
|
610
|
+
const FLAG_COMBO = 131072;
|
|
611
|
+
let flags = 0;
|
|
612
|
+
if (field.readOnly === true) flags |= FLAG_READ_ONLY;
|
|
613
|
+
if (field.fieldType === "button") flags |= FLAG_PUSHBUTTON;
|
|
614
|
+
if (field.fieldType === "radio") flags |= FLAG_RADIO;
|
|
615
|
+
if (field.fieldType === "combobox") flags |= FLAG_COMBO;
|
|
616
|
+
if (flags !== 0) entries.push(["Ff", pdfNum(flags)]);
|
|
617
|
+
if (field.fieldType === "text" || field.fieldType === "listbox" || field.fieldType === "combobox") {
|
|
618
|
+
if (field.value !== void 0) entries.push(["V", pdfLiteralString(new TextEncoder().encode(field.value))]);
|
|
619
|
+
} 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)]);
|
|
620
|
+
if (field.options !== void 0) entries.push(["Opt", pdfArray(field.options.map((option) => pdfLiteralString(new TextEncoder().encode(option))))]);
|
|
621
|
+
const firstWidget = field.widgets[0];
|
|
622
|
+
if (field.widgets.length === 1 && firstWidget !== void 0) {
|
|
623
|
+
entries.push(["Subtype", pdfName("Widget")]);
|
|
624
|
+
entries.push(["Rect", widgetRectArray(firstWidget)]);
|
|
625
|
+
entries.push(["P", pdfRef(pageAllocs[firstWidget.pageIndex].pageNum, 0)]);
|
|
626
|
+
} else if (field.widgets.length > 1 && firstWidget !== void 0) {
|
|
627
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
628
|
+
entries.push(["Kids", pdfArray([widgetDict(firstWidget), ...extraNums.map((num) => pdfRef(num, 0))])]);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
objects.push({
|
|
632
|
+
num: formNumOf(field),
|
|
633
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
634
|
+
});
|
|
635
|
+
const extraNums = formExtraWidgetNums.get(field) ?? [];
|
|
636
|
+
for (const [index, num] of extraNums.entries()) {
|
|
637
|
+
const widget = field.widgets[index + 1];
|
|
638
|
+
objects.push({
|
|
639
|
+
num,
|
|
640
|
+
value: widgetDict(widget)
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
emitFormFieldObjects(field.children, field.name);
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
emitFormFieldObjects(doc.form ?? [], "");
|
|
647
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
648
|
+
const emitStructureElement = (element, parentNum) => {
|
|
649
|
+
const entries = [
|
|
650
|
+
["Type", pdfName("StructElem")],
|
|
651
|
+
["S", pdfName(element.type)],
|
|
652
|
+
["P", pdfRef(parentNum, 0)]
|
|
653
|
+
];
|
|
654
|
+
if (element.title !== void 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(element.title))]);
|
|
655
|
+
if (element.language !== void 0) entries.push(["Lang", pdfLiteralString(new TextEncoder().encode(element.language))]);
|
|
656
|
+
if (element.alt !== void 0) entries.push(["Alt", pdfLiteralString(new TextEncoder().encode(element.alt))]);
|
|
657
|
+
if (element.actualText !== void 0) entries.push(["ActualText", pdfLiteralString(new TextEncoder().encode(element.actualText))]);
|
|
658
|
+
if (element.children.length > 0) entries.push(["K", pdfArray(element.children.map((child) => {
|
|
659
|
+
const num = structElementNumById.get(child.id);
|
|
660
|
+
if (num === void 0) throw new Error(`structure element "${child.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
661
|
+
return pdfRef(num, 0);
|
|
662
|
+
}))]);
|
|
663
|
+
const ownNum = structElementNumById.get(element.id);
|
|
664
|
+
if (ownNum === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
665
|
+
objects.push({
|
|
666
|
+
num: ownNum,
|
|
667
|
+
value: pdfDict(Object.fromEntries(entries))
|
|
668
|
+
});
|
|
669
|
+
for (const child of element.children) emitStructureElement(child, ownNum);
|
|
670
|
+
};
|
|
671
|
+
for (const element of doc.structure ?? []) emitStructureElement(element, structRootNum);
|
|
672
|
+
}
|
|
673
|
+
if (residueXmpNum !== void 0 && doc.source?.xmp !== void 0) objects.push({
|
|
674
|
+
num: residueXmpNum,
|
|
675
|
+
value: pdfStream(pdfDict({
|
|
676
|
+
Type: pdfName("Metadata"),
|
|
677
|
+
Subtype: pdfName("XML")
|
|
678
|
+
}), new TextEncoder().encode(doc.source.xmp.xml))
|
|
679
|
+
});
|
|
294
680
|
for (const [standardName, alloc] of fontAllocs) {
|
|
295
681
|
const { font, descriptor } = buildFontObjects(standardName, pdfRef(alloc.descNum, 0));
|
|
296
682
|
objects.push({
|
|
@@ -346,9 +732,10 @@ function writePdf(doc, options = {}) {
|
|
|
346
732
|
});
|
|
347
733
|
}
|
|
348
734
|
for (const [face, alloc] of embeddedAllocs) {
|
|
349
|
-
const
|
|
735
|
+
const usedGlyphs = collectEmbeddedGlyphs(alloc.texts, face);
|
|
736
|
+
const subset = subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b), [...usedGlyphs.keys()].sort((a, b) => a - b));
|
|
350
737
|
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`);
|
|
351
|
-
const built = buildEmbeddedFontObjects(face, subset,
|
|
738
|
+
const built = buildEmbeddedFontObjects(face, subset, usedGlyphs, {
|
|
352
739
|
cidFontRef: pdfRef(alloc.cidFontNum, 0),
|
|
353
740
|
descriptorRef: pdfRef(alloc.descriptorNum, 0),
|
|
354
741
|
fontFileRef: pdfRef(alloc.fontFileNum, 0),
|
|
@@ -384,6 +771,7 @@ function writePdf(doc, options = {}) {
|
|
|
384
771
|
}
|
|
385
772
|
if (imageAllocs.size > 0) resourceEntries.set("XObject", pdfDict(new Map([...imageAllocs.values()].map((alloc) => [alloc.resourceName, pdfRef(alloc.imageNum, 0)]))));
|
|
386
773
|
const resourcesDict = pdfDict(resourceEntries);
|
|
774
|
+
const markedStructureByPage = /* @__PURE__ */ new Map();
|
|
387
775
|
const formulasByPage = /* @__PURE__ */ new Map();
|
|
388
776
|
for (const formula of formulas) {
|
|
389
777
|
const forPage = formulasByPage.get(formula.pageIndex);
|
|
@@ -420,7 +808,14 @@ function writePdf(doc, options = {}) {
|
|
|
420
808
|
doc.pages.forEach((page, pageIndex) => {
|
|
421
809
|
throwIfAborted(options.signal);
|
|
422
810
|
const { pageNum, contentsNum } = pageAllocs[pageIndex];
|
|
423
|
-
|
|
811
|
+
let pageMcid = 0;
|
|
812
|
+
const pageContext = {
|
|
813
|
+
...context,
|
|
814
|
+
nextMcid: () => pageMcid++,
|
|
815
|
+
layerObjectNumberOf: (name) => layerNumByName.get(name)
|
|
816
|
+
};
|
|
817
|
+
const { bytes: contentBytes, substitutions, missingGlyphs, markedStructure } = writeContentStream(page.items, pageContext);
|
|
818
|
+
if (markedStructure.length > 0) markedStructureByPage.set(pageIndex, [...markedStructure]);
|
|
424
819
|
for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
|
|
425
820
|
for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
|
|
426
821
|
const pageFormulas = formulasByPage.get(pageIndex);
|
|
@@ -435,7 +830,7 @@ function writePdf(doc, options = {}) {
|
|
|
435
830
|
num: contentsNum,
|
|
436
831
|
value: pdfStream(contentsDict, finalContentBytes)
|
|
437
832
|
});
|
|
438
|
-
const annots = page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link));
|
|
833
|
+
const annots = [...page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link)), ...page.items.filter(isInternalLinkItem).map((link) => buildInternalLinkAnnotDict(link, doc, pageAllocs))];
|
|
439
834
|
if (page.notes !== void 0 && page.notes.length > 0) annots.push(buildNotesAnnotDict(page.notes));
|
|
440
835
|
const pageEntries = /* @__PURE__ */ new Map([
|
|
441
836
|
["Type", pdfName("Page")],
|
|
@@ -450,15 +845,59 @@ function writePdf(doc, options = {}) {
|
|
|
450
845
|
["Contents", pdfRef(contentsNum, 0)]
|
|
451
846
|
]);
|
|
452
847
|
if (annots.length > 0) pageEntries.set("Annots", pdfArray(annots));
|
|
848
|
+
if ((markedStructureByPage.get(pageIndex) ?? []).length > 0) pageEntries.set("StructParents", pdfNum(pageIndex));
|
|
453
849
|
objects.push({
|
|
454
850
|
num: pageNum,
|
|
455
851
|
value: pdfDict(pageEntries)
|
|
456
852
|
});
|
|
457
853
|
});
|
|
854
|
+
if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
|
|
855
|
+
const nums = [];
|
|
856
|
+
for (const [pageIndex, marks] of markedStructureByPage) {
|
|
857
|
+
const maxMcid = Math.max(...marks.map((mark) => mark.mcid));
|
|
858
|
+
const byMcid = Array.from({ length: maxMcid + 1 }, () => pdfNull());
|
|
859
|
+
for (const mark of marks) {
|
|
860
|
+
const elementNum = structElementNumById.get(mark.structureId);
|
|
861
|
+
if (elementNum !== void 0) byMcid[mark.mcid] = pdfRef(elementNum, 0);
|
|
862
|
+
}
|
|
863
|
+
nums.push(pdfNum(pageIndex), pdfArray(byMcid));
|
|
864
|
+
}
|
|
865
|
+
objects.push({
|
|
866
|
+
num: structParentTreeNum,
|
|
867
|
+
value: pdfDict({ Nums: pdfArray(nums) })
|
|
868
|
+
});
|
|
869
|
+
const rootEntries = [
|
|
870
|
+
["Type", pdfName("StructTreeRoot")],
|
|
871
|
+
["K", pdfArray((doc.structure ?? []).map((element) => {
|
|
872
|
+
const num = structElementNumById.get(element.id);
|
|
873
|
+
if (num === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
|
|
874
|
+
return pdfRef(num, 0);
|
|
875
|
+
}))],
|
|
876
|
+
["ParentTree", pdfRef(structParentTreeNum, 0)]
|
|
877
|
+
];
|
|
878
|
+
objects.push({
|
|
879
|
+
num: structRootNum,
|
|
880
|
+
value: pdfDict(Object.fromEntries(rootEntries))
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
let fileId;
|
|
884
|
+
let encryptedObjects = objects;
|
|
885
|
+
if (options.encryption !== void 0 && encryptDictNum !== void 0) {
|
|
886
|
+
fileId = randomBytes(FILE_ID_BYTES);
|
|
887
|
+
const encryptor = createStandardEncryptor(options.encryption, fileId);
|
|
888
|
+
encryptedObjects = objects.map(({ num, value }) => ({
|
|
889
|
+
num,
|
|
890
|
+
value: encryptIndirectObject(value, num, 0, encryptor)
|
|
891
|
+
}));
|
|
892
|
+
encryptedObjects.push({
|
|
893
|
+
num: encryptDictNum,
|
|
894
|
+
value: encryptor.encryptDict
|
|
895
|
+
});
|
|
896
|
+
}
|
|
458
897
|
const writer = new ByteWriter();
|
|
459
898
|
writer.writeAscii("%PDF-1.7\n");
|
|
460
899
|
const offsets = /* @__PURE__ */ new Map();
|
|
461
|
-
for (const { num, value } of
|
|
900
|
+
for (const { num, value } of encryptedObjects) {
|
|
462
901
|
offsets.set(num, writer.length);
|
|
463
902
|
writer.writeAscii(`${num} 0 obj\n`);
|
|
464
903
|
writeObject(writer, value);
|
|
@@ -474,16 +913,21 @@ function writePdf(doc, options = {}) {
|
|
|
474
913
|
if (offset === void 0) throw new Error(`object ${num} was allocated but never written -- this is a writePdf internal invariant violation`);
|
|
475
914
|
writer.writeAscii(xrefEntry(offset, 0, true));
|
|
476
915
|
}
|
|
916
|
+
const trailerEntries = /* @__PURE__ */ new Map([
|
|
917
|
+
["Size", pdfNum(maxObjNum + 1)],
|
|
918
|
+
["Root", pdfRef(catalogNum, 0)],
|
|
919
|
+
["Info", pdfRef(infoNum, 0)]
|
|
920
|
+
]);
|
|
921
|
+
if (fileId !== void 0 && encryptDictNum !== void 0) {
|
|
922
|
+
trailerEntries.set("ID", pdfArray([pdfHexString(fileId), pdfHexString(fileId)]));
|
|
923
|
+
trailerEntries.set("Encrypt", pdfRef(encryptDictNum, 0));
|
|
924
|
+
} else if (trailerIdRestore !== void 0) trailerEntries.set("ID", trailerIdRestore);
|
|
477
925
|
writer.writeAscii("trailer\n");
|
|
478
|
-
writeObject(writer, pdfDict(
|
|
479
|
-
Size: pdfNum(maxObjNum + 1),
|
|
480
|
-
Root: pdfRef(catalogNum, 0),
|
|
481
|
-
Info: pdfRef(infoNum, 0)
|
|
482
|
-
}));
|
|
926
|
+
writeObject(writer, pdfDict(trailerEntries));
|
|
483
927
|
writer.writeAscii("\nstartxref\n");
|
|
484
928
|
writer.writeAscii(`${xrefOffset}\n`);
|
|
485
929
|
writer.writeAscii("%%EOF");
|
|
486
930
|
return writer.toBytes();
|
|
487
931
|
}
|
|
488
932
|
//#endregion
|
|
489
|
-
export {
|
|
933
|
+
export { writePdf };
|
package/dist/xmp.cjs
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/xmp.ts
|
|
3
|
+
function readXmpMetadata(packet) {
|
|
4
|
+
return {
|
|
5
|
+
...field(xmpValue(packet, "dc:title"), "title"),
|
|
6
|
+
...field(xmpValue(packet, "dc:creator"), "author"),
|
|
7
|
+
...field(xmpValue(packet, "dc:description"), "subject"),
|
|
8
|
+
...field(xmpValue(packet, "xmp:CreatorTool"), "creator"),
|
|
9
|
+
...field(xmpValue(packet, "pdf:Producer"), "producer"),
|
|
10
|
+
...field(xmpValue(packet, "xmp:CreateDate"), "createdIso"),
|
|
11
|
+
...field(xmpValue(packet, "xmp:ModifyDate"), "modifiedIso"),
|
|
12
|
+
...keywordsOf(packet)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function xmpValue(packet, element) {
|
|
16
|
+
const match = new RegExp(`<${element}(?:\\s[^>]*)?>([\\s\\S]*?)</${element}>`).exec(packet);
|
|
17
|
+
if (match === null) return;
|
|
18
|
+
const inner = match[1] ?? "";
|
|
19
|
+
const items = listItems(inner);
|
|
20
|
+
if (items.length > 0) return items;
|
|
21
|
+
const text = inner.trim();
|
|
22
|
+
return text.length > 0 ? text : void 0;
|
|
23
|
+
}
|
|
24
|
+
function listItems(inner) {
|
|
25
|
+
const items = [];
|
|
26
|
+
const pattern = /<rdf:li(?:\s[^>]*)?>([\s\S]*?)<\/rdf:li>/g;
|
|
27
|
+
let match;
|
|
28
|
+
while ((match = pattern.exec(inner)) !== null) {
|
|
29
|
+
const text = (match[1] ?? "").trim();
|
|
30
|
+
if (text.length > 0) items.push(text);
|
|
31
|
+
}
|
|
32
|
+
return items;
|
|
33
|
+
}
|
|
34
|
+
function field(value, key) {
|
|
35
|
+
if (typeof value === "string") return { [key]: value };
|
|
36
|
+
if (Array.isArray(value) && value.length > 0) return { [key]: value.join(", ") };
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
function keywordsOf(packet) {
|
|
40
|
+
const match = (/* @__PURE__ */ new RegExp("<dc:subject(?:\\s[^>]*)?>([\\s\\S]*?)</dc:subject>")).exec(packet);
|
|
41
|
+
if (match === null) return {};
|
|
42
|
+
const items = listItems(match[1] ?? "");
|
|
43
|
+
return items.length > 0 ? { keywords: items } : {};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
exports.readXmpMetadata = readXmpMetadata;
|
package/dist/xmp.d.cts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/xmp.d.ts
|
|
2
|
+
interface XmpMetadata {
|
|
3
|
+
readonly title?: string;
|
|
4
|
+
readonly author?: string;
|
|
5
|
+
readonly subject?: string;
|
|
6
|
+
readonly keywords?: string[];
|
|
7
|
+
readonly creator?: string;
|
|
8
|
+
readonly producer?: string;
|
|
9
|
+
readonly createdIso?: string;
|
|
10
|
+
readonly modifiedIso?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function readXmpMetadata(packet: string): XmpMetadata;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { XmpMetadata, readXmpMetadata };
|
package/dist/xmp.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/xmp.d.ts
|
|
2
|
+
interface XmpMetadata {
|
|
3
|
+
readonly title?: string;
|
|
4
|
+
readonly author?: string;
|
|
5
|
+
readonly subject?: string;
|
|
6
|
+
readonly keywords?: string[];
|
|
7
|
+
readonly creator?: string;
|
|
8
|
+
readonly producer?: string;
|
|
9
|
+
readonly createdIso?: string;
|
|
10
|
+
readonly modifiedIso?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function readXmpMetadata(packet: string): XmpMetadata;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { XmpMetadata, readXmpMetadata };
|