pdf-codec 3.1.4 → 3.3.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 -2
- 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/bytes/flate.cjs +1 -1
- package/dist/bytes/flate.js +1 -1
- package/dist/codec.d.cts +109 -0
- package/dist/codec.d.ts +109 -0
- package/dist/content-read.cjs +1 -1
- package/dist/content-read.js +1 -1
- package/dist/content-write.cjs +2 -2
- package/dist/content-write.js +2 -2
- package/dist/document.cjs +12 -3
- package/dist/document.d.cts +2 -0
- package/dist/document.d.ts +2 -0
- package/dist/document.js +12 -3
- package/dist/embedded-font-write.cjs +1 -1
- package/dist/embedded-font-write.js +1 -1
- package/dist/encrypt.cjs +1 -1
- package/dist/encrypt.js +1 -1
- package/dist/filters.cjs +1 -1
- package/dist/filters.js +1 -1
- package/dist/font-read.cjs +1 -1
- package/dist/font-read.js +1 -1
- package/dist/font-registry.cjs +1 -1
- package/dist/font-registry.js +1 -1
- 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/image/png-decode.cjs +1 -1
- package/dist/image/png-decode.js +1 -1
- package/dist/image/png-encode.cjs +1 -1
- package/dist/image/png-encode.js +1 -1
- package/dist/index.cjs +12 -2
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/interpret.cjs +70 -10
- package/dist/interpret.d.cts +9 -1
- package/dist/interpret.d.ts +9 -1
- package/dist/interpret.js +70 -10
- package/dist/layout.cjs +132 -2
- package/dist/layout.d.cts +335 -1
- package/dist/layout.d.ts +335 -1
- package/dist/layout.js +124 -4
- package/dist/math-content-write.cjs +1 -1
- package/dist/math-content-write.js +1 -1
- package/dist/math-font.cjs +1 -1
- package/dist/math-font.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/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 +1 -1
- package/dist/parse.d.ts +1 -1
- 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/read.cjs +272 -72
- package/dist/read.d.cts +2 -4
- package/dist/read.d.ts +2 -4
- package/dist/read.js +269 -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/write.cjs +51 -5
- package/dist/write.js +51 -5
- 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.js +2 -2
- package/package.json +2 -2
package/dist/read.js
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
|
+
import "./notes-annotation-author.js";
|
|
2
|
+
import { asArray, asName, asNumber, dictGet, pdfArray, pdfDict, pdfNull, pdfNum } from "./objects.js";
|
|
3
|
+
import { decodePdfString, parsePdfDate } from "./pdf-text.js";
|
|
4
|
+
import { concatBytes } from "./bytes/writer.js";
|
|
5
|
+
import { serializeObjectToText } from "./serialize.js";
|
|
6
|
+
import { applyMatrix, matrixRotationDegrees, matrixScaleX, matrixScaleY, multiplyMatrices, rotatePointAboutCenter, translationMatrix } from "./matrix.js";
|
|
7
|
+
import { readPageAnnotations } from "./annotations.js";
|
|
8
|
+
import { decodeStream } from "./filters.js";
|
|
1
9
|
import { bytesToBase64 } from "./util/base64.js";
|
|
10
|
+
import { readAttachments } from "./attachments.js";
|
|
2
11
|
import { crc32 } from "./bytes/crc32.js";
|
|
3
|
-
import {
|
|
12
|
+
import { readAcroForm } from "./form.js";
|
|
13
|
+
import { readXmpMetadata } from "./xmp.js";
|
|
14
|
+
import { readOptionalContent } from "./optional-content.js";
|
|
4
15
|
import "./layout.js";
|
|
5
16
|
import { NOOP_DIAGNOSTIC_SINK, PdfParseError } from "./diagnostics.js";
|
|
6
|
-
import { asArray, asName, asNumber, dictGet } from "./objects.js";
|
|
7
|
-
import { decodeStream } from "./filters.js";
|
|
8
17
|
import { openPdfDocument } from "./document.js";
|
|
9
18
|
import { throwIfAborted } from "./util/abort.js";
|
|
10
19
|
import { createFontResolver } from "./font-read.js";
|
|
11
20
|
import { readImageXObject } from "./images-read.js";
|
|
12
|
-
import { applyMatrix, matrixRotationDegrees, matrixScaleX, matrixScaleY, multiplyMatrices, translationMatrix } from "./matrix.js";
|
|
13
21
|
import { interpretContentStream } from "./interpret.js";
|
|
14
|
-
import "./
|
|
22
|
+
import { createDestinationRegistry, readOutline } from "./navigation.js";
|
|
15
23
|
//#region src/read.ts
|
|
16
24
|
const PDF_HEADER_BYTES = new TextEncoder().encode("%PDF-");
|
|
17
25
|
const HEADER_SEARCH_WINDOW = 1024;
|
|
@@ -37,29 +45,42 @@ function readPdf(bytes, options) {
|
|
|
37
45
|
});
|
|
38
46
|
const images = {};
|
|
39
47
|
const imageIdCache = /* @__PURE__ */ new Map();
|
|
40
|
-
const
|
|
48
|
+
const pageDicts = doc.pages();
|
|
49
|
+
const destinationRegistry = createDestinationRegistry(doc.catalog, doc, (obj) => doc.pageIndex(obj), sink);
|
|
50
|
+
const outline = readOutline(doc.catalog, destinationRegistry, doc, sink);
|
|
51
|
+
const attachments = readAttachments(doc.catalog, pageDicts, doc, sink);
|
|
52
|
+
const optionalContent = readOptionalContent(doc.catalog, doc, sink);
|
|
53
|
+
const form = readAcroForm(doc.catalog, doc, (obj) => doc.pageIndex(obj), sink);
|
|
54
|
+
const source = readDocumentResidue(doc, sink);
|
|
55
|
+
const pageBoxRows = [];
|
|
56
|
+
const pages = pageDicts.map((pageDict, index) => {
|
|
41
57
|
throwIfAborted(signal);
|
|
42
|
-
return readPage(pageDict, doc, fontResolver, images, imageIdCache, sink);
|
|
58
|
+
return readPage(index, pageDict, doc, fontResolver, images, imageIdCache, destinationRegistry, optionalContent.layerNameOf, pageBoxRows, sink);
|
|
43
59
|
});
|
|
60
|
+
if (pageBoxRows.length > 0) source["page-boxes"] = {
|
|
61
|
+
format: "pdf",
|
|
62
|
+
xml: serializeObjectToText(pdfArray(pageBoxRows))
|
|
63
|
+
};
|
|
44
64
|
return {
|
|
45
65
|
formatVersion: 1,
|
|
46
|
-
metadata: readMetadata(doc.trailer, doc),
|
|
66
|
+
metadata: readMetadata(doc.trailer, doc, doc.catalog, sink),
|
|
47
67
|
pages,
|
|
48
|
-
images
|
|
68
|
+
images,
|
|
69
|
+
...destinationRegistry.entries.length > 0 ? { destinations: [...destinationRegistry.entries] } : {},
|
|
70
|
+
...outline.length > 0 ? { outline } : {},
|
|
71
|
+
...attachments.length > 0 ? { attachments } : {},
|
|
72
|
+
...optionalContent.layers.length > 0 ? { layers: [...optionalContent.layers] } : {},
|
|
73
|
+
...form.length > 0 ? { form } : {},
|
|
74
|
+
...Object.keys(source).length > 0 ? { source } : {}
|
|
49
75
|
};
|
|
50
76
|
}
|
|
51
|
-
function
|
|
52
|
-
const arr = asArray(dictGet(page,
|
|
53
|
-
if (arr === void 0) return
|
|
54
|
-
llx: 0,
|
|
55
|
-
lly: 0,
|
|
56
|
-
urx: DEFAULT_PAGE_WIDTH_PT,
|
|
57
|
-
ury: DEFAULT_PAGE_HEIGHT_PT
|
|
58
|
-
};
|
|
77
|
+
function readDeclaredPageBox(page, key) {
|
|
78
|
+
const arr = asArray(dictGet(page, key));
|
|
79
|
+
if (arr === void 0) return;
|
|
59
80
|
const a = asNumber(arr[0]) ?? 0;
|
|
60
81
|
const b = asNumber(arr[1]) ?? 0;
|
|
61
|
-
const c = asNumber(arr[2]) ??
|
|
62
|
-
const d = asNumber(arr[3]) ??
|
|
82
|
+
const c = asNumber(arr[2]) ?? 0;
|
|
83
|
+
const d = asNumber(arr[3]) ?? 0;
|
|
63
84
|
return {
|
|
64
85
|
llx: Math.min(a, c),
|
|
65
86
|
lly: Math.min(b, d),
|
|
@@ -67,6 +88,33 @@ function readMediaBox(page) {
|
|
|
67
88
|
ury: Math.max(b, d)
|
|
68
89
|
};
|
|
69
90
|
}
|
|
91
|
+
function readMediaBox(page) {
|
|
92
|
+
return readDeclaredPageBox(page, "MediaBox") ?? {
|
|
93
|
+
llx: 0,
|
|
94
|
+
lly: 0,
|
|
95
|
+
urx: DEFAULT_PAGE_WIDTH_PT,
|
|
96
|
+
ury: DEFAULT_PAGE_HEIGHT_PT
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function rotatedRectBounds(rect, matrix) {
|
|
100
|
+
const transformed = [
|
|
101
|
+
[rect.llx, rect.lly],
|
|
102
|
+
[rect.urx, rect.lly],
|
|
103
|
+
[rect.llx, rect.ury],
|
|
104
|
+
[rect.urx, rect.ury]
|
|
105
|
+
].map(([x, y]) => applyMatrix(matrix, {
|
|
106
|
+
x,
|
|
107
|
+
y
|
|
108
|
+
}));
|
|
109
|
+
const xs = transformed.map((point) => point.x);
|
|
110
|
+
const ys = transformed.map((point) => point.y);
|
|
111
|
+
return {
|
|
112
|
+
minX: Math.min(...xs),
|
|
113
|
+
minY: Math.min(...ys),
|
|
114
|
+
maxX: Math.max(...xs),
|
|
115
|
+
maxY: Math.max(...ys)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
70
118
|
function normalizeRotation(rotate) {
|
|
71
119
|
if (rotate === void 0) return 0;
|
|
72
120
|
const normalized = (Math.round(rotate / 90) * 90 % 360 + 360) % 360;
|
|
@@ -135,35 +183,141 @@ function readPageContentBytes(page, resolver, sink) {
|
|
|
135
183
|
}
|
|
136
184
|
return /* @__PURE__ */ new Uint8Array(0);
|
|
137
185
|
}
|
|
138
|
-
function
|
|
186
|
+
function contentItemBounds(item) {
|
|
187
|
+
if (item.kind === "link" || item.kind === "internalLink") return;
|
|
188
|
+
const frameBounds = (xPt, yPt, widthPt, heightPt) => ({
|
|
189
|
+
minX: xPt,
|
|
190
|
+
minY: yPt,
|
|
191
|
+
maxX: xPt + widthPt,
|
|
192
|
+
maxY: yPt + heightPt
|
|
193
|
+
});
|
|
194
|
+
if (item.kind === "text" || item.kind === "image" || item.kind === "rect" || item.kind === "ellipse") {
|
|
195
|
+
if (item.kind !== "text" || item.rotationDeg === void 0 || item.rotationDeg % 180 === 0) return frameBounds(item.xPt, item.yPt, item.widthPt ?? 0, item.kind === "text" ? item.sizePt : item.heightPt);
|
|
196
|
+
const rotationDeg = item.rotationDeg;
|
|
197
|
+
const anchorX = item.xPt;
|
|
198
|
+
const anchorY = item.yPt;
|
|
199
|
+
const rotated = [
|
|
200
|
+
[0, 0],
|
|
201
|
+
[item.widthPt ?? 0, 0],
|
|
202
|
+
[0, item.sizePt],
|
|
203
|
+
[item.widthPt ?? 0, item.sizePt]
|
|
204
|
+
].map(([dx, dy]) => rotatePointAboutCenter({
|
|
205
|
+
x: anchorX + dx,
|
|
206
|
+
y: anchorY + dy
|
|
207
|
+
}, {
|
|
208
|
+
x: anchorX,
|
|
209
|
+
y: anchorY
|
|
210
|
+
}, rotationDeg));
|
|
211
|
+
const xs = rotated.map((point) => point.x);
|
|
212
|
+
const ys = rotated.map((point) => point.y);
|
|
213
|
+
return {
|
|
214
|
+
minX: Math.min(...xs),
|
|
215
|
+
minY: Math.min(...ys),
|
|
216
|
+
maxX: Math.max(...xs),
|
|
217
|
+
maxY: Math.max(...ys)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (item.kind === "line") return {
|
|
221
|
+
minX: Math.min(item.x1Pt, item.x2Pt),
|
|
222
|
+
minY: Math.min(item.y1Pt, item.y2Pt),
|
|
223
|
+
maxX: Math.max(item.x1Pt, item.x2Pt),
|
|
224
|
+
maxY: Math.max(item.y1Pt, item.y2Pt)
|
|
225
|
+
};
|
|
226
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
227
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
228
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
229
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
230
|
+
const include = (x, y) => {
|
|
231
|
+
minX = Math.min(minX, x);
|
|
232
|
+
minY = Math.min(minY, y);
|
|
233
|
+
maxX = Math.max(maxX, x);
|
|
234
|
+
maxY = Math.max(maxY, y);
|
|
235
|
+
};
|
|
236
|
+
for (const subpath of item.subpaths) {
|
|
237
|
+
include(subpath.startXPt, subpath.startYPt);
|
|
238
|
+
for (const segment of subpath.segments) {
|
|
239
|
+
include(segment.xPt, segment.yPt);
|
|
240
|
+
if (segment.kind === "cubic") {
|
|
241
|
+
include(segment.c1xPt, segment.c1yPt);
|
|
242
|
+
include(segment.c2xPt, segment.c2yPt);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
minX,
|
|
248
|
+
minY,
|
|
249
|
+
maxX,
|
|
250
|
+
maxY
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function itemIntersectsVisibleRegion(item, widthPt, heightPt) {
|
|
254
|
+
if (item.kind === "link" || item.kind === "internalLink") return true;
|
|
255
|
+
const bounds = contentItemBounds(item);
|
|
256
|
+
if (bounds === void 0) return true;
|
|
257
|
+
return bounds.maxX >= 0 && bounds.minX <= widthPt && bounds.maxY >= 0 && bounds.minY <= heightPt;
|
|
258
|
+
}
|
|
259
|
+
function pageBoxResidueEntry(pageIndex, page, mediaBox, cropBox) {
|
|
260
|
+
const declaredBoxes = [
|
|
261
|
+
["MediaBox", dictGet(page, "MediaBox")],
|
|
262
|
+
["CropBox", dictGet(page, "CropBox")],
|
|
263
|
+
["BleedBox", dictGet(page, "BleedBox")],
|
|
264
|
+
["TrimBox", dictGet(page, "TrimBox")],
|
|
265
|
+
["ArtBox", dictGet(page, "ArtBox")]
|
|
266
|
+
];
|
|
267
|
+
const cropDeclared = dictGet(page, "CropBox") !== void 0;
|
|
268
|
+
const productionBoxDeclared = declaredBoxes.slice(2).some(([, value]) => value !== void 0);
|
|
269
|
+
if (!(cropDeclared && (cropBox.llx !== mediaBox.llx || cropBox.lly !== mediaBox.lly || cropBox.urx !== mediaBox.urx || cropBox.ury !== mediaBox.ury)) && !productionBoxDeclared) return;
|
|
270
|
+
const entries = { Page: pdfNum(pageIndex) };
|
|
271
|
+
for (const [key, value] of declaredBoxes) if (value !== void 0) entries[key] = value;
|
|
272
|
+
return pdfDict(entries);
|
|
273
|
+
}
|
|
274
|
+
function readPage(pageIndex, page, resolver, fontResolver, images, imageIdCache, destinationRegistry, layerNameOf, pageBoxRows, sink) {
|
|
139
275
|
const resources = resolver.resolveDict(dictGet(page, "Resources"));
|
|
140
276
|
const mediaBox = readMediaBox(page);
|
|
277
|
+
let cropBox = readDeclaredPageBox(page, "CropBox") ?? mediaBox;
|
|
278
|
+
if (cropBox.urx - cropBox.llx <= 0 || cropBox.ury - cropBox.lly <= 0) {
|
|
279
|
+
sink({
|
|
280
|
+
code: "pdf/invalid-crop-box",
|
|
281
|
+
severity: "warning",
|
|
282
|
+
pageIndex,
|
|
283
|
+
message: "page /CropBox is degenerate (zero width or height); falling back to the /MediaBox as the visible region"
|
|
284
|
+
});
|
|
285
|
+
cropBox = mediaBox;
|
|
286
|
+
}
|
|
141
287
|
const rotationResult = pageRotationTransform(normalizeRotation(asNumber(dictGet(page, "Rotate"))), mediaBox.urx - mediaBox.llx, mediaBox.ury - mediaBox.lly);
|
|
142
|
-
const
|
|
288
|
+
const visibleRect = rotatedRectBounds(cropBox, rotationResult.matrix);
|
|
289
|
+
const widthPt = visibleRect.maxX - visibleRect.minX;
|
|
290
|
+
const heightPt = visibleRect.maxY - visibleRect.minY;
|
|
291
|
+
const pageMatrix = multiplyMatrices(rotationResult.matrix, translationMatrix(-visibleRect.minX, -visibleRect.minY));
|
|
292
|
+
const boxRow = pageBoxResidueEntry(pageIndex, page, mediaBox, cropBox);
|
|
293
|
+
if (boxRow !== void 0) pageBoxRows.push(boxRow);
|
|
143
294
|
const items = [];
|
|
144
295
|
if (resources !== void 0) {
|
|
145
296
|
const contentBytes = readPageContentBytes(page, resolver, sink);
|
|
146
297
|
const extracted = interpretContentStream(contentBytes, resources, {
|
|
147
298
|
fontMetrics: fontResolver.metrics,
|
|
148
299
|
resolver,
|
|
149
|
-
sink
|
|
300
|
+
sink,
|
|
301
|
+
layerNameOf
|
|
150
302
|
});
|
|
151
303
|
for (const item of extracted) {
|
|
152
304
|
const converted = convertExtractedItem(item, pageMatrix, fontResolver, images, imageIdCache, resolver, sink);
|
|
153
|
-
if (converted !== void 0) items.push(converted);
|
|
305
|
+
if (converted !== void 0 && itemIntersectsVisibleRegion(converted, widthPt, heightPt)) items.push(converted);
|
|
154
306
|
}
|
|
155
307
|
} else sink({
|
|
156
308
|
code: "pdf/object-missing-value",
|
|
157
309
|
severity: "warning",
|
|
158
310
|
message: "page has no /Resources dict; its content stream cannot be interpreted"
|
|
159
311
|
});
|
|
160
|
-
items.push(...readLinkAnnotations(page, pageMatrix, resolver));
|
|
312
|
+
items.push(...readLinkAnnotations(page, pageMatrix, resolver, destinationRegistry));
|
|
161
313
|
const notes = readPageNotes(page, resolver);
|
|
314
|
+
const annotations = readPageAnnotations(page, pageMatrix, resolver, sink);
|
|
162
315
|
return {
|
|
163
|
-
widthPt
|
|
164
|
-
heightPt
|
|
316
|
+
widthPt,
|
|
317
|
+
heightPt,
|
|
165
318
|
items,
|
|
166
|
-
...notes !== void 0 ? { notes } : {}
|
|
319
|
+
...notes !== void 0 ? { notes } : {},
|
|
320
|
+
...annotations.length > 0 ? { annotations } : {}
|
|
167
321
|
};
|
|
168
322
|
}
|
|
169
323
|
function convertExtractedItem(item, pageMatrix, fontResolver, images, imageIdCache, resolver, sink) {
|
|
@@ -198,7 +352,10 @@ function convertText(item, pageMatrix, fontResolver) {
|
|
|
198
352
|
sizePt: sizePt > 0 ? sizePt : item.sizePt,
|
|
199
353
|
color: item.color,
|
|
200
354
|
widthPt,
|
|
201
|
-
rotationDeg: rotationDeg !== 0 ? rotationDeg : void 0
|
|
355
|
+
rotationDeg: rotationDeg !== 0 ? rotationDeg : void 0,
|
|
356
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {},
|
|
357
|
+
...item.actualText !== void 0 ? { actualText: item.actualText } : {},
|
|
358
|
+
...item.alt !== void 0 ? { alt: item.alt } : {}
|
|
202
359
|
};
|
|
203
360
|
}
|
|
204
361
|
function paintFields(paint) {
|
|
@@ -227,14 +384,16 @@ function convertRect(item, pageMatrix) {
|
|
|
227
384
|
return {
|
|
228
385
|
kind: "rect",
|
|
229
386
|
...transformBox(item, pageMatrix),
|
|
230
|
-
...paintFields(item)
|
|
387
|
+
...paintFields(item),
|
|
388
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
231
389
|
};
|
|
232
390
|
}
|
|
233
391
|
function convertEllipse(item, pageMatrix) {
|
|
234
392
|
return {
|
|
235
393
|
kind: "ellipse",
|
|
236
394
|
...transformBox(item, pageMatrix),
|
|
237
|
-
...paintFields(item)
|
|
395
|
+
...paintFields(item),
|
|
396
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
238
397
|
};
|
|
239
398
|
}
|
|
240
399
|
function convertLine(item, pageMatrix) {
|
|
@@ -253,7 +412,8 @@ function convertLine(item, pageMatrix) {
|
|
|
253
412
|
x2Pt: p2.x,
|
|
254
413
|
y2Pt: p2.y,
|
|
255
414
|
color: item.color,
|
|
256
|
-
widthPt: item.widthPt
|
|
415
|
+
widthPt: item.widthPt,
|
|
416
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
257
417
|
};
|
|
258
418
|
}
|
|
259
419
|
function transformSubpath(subpath, pageMatrix) {
|
|
@@ -308,7 +468,8 @@ function convertPath(item, pageMatrix) {
|
|
|
308
468
|
subpaths: item.subpaths.map((subpath) => transformSubpath(subpath, pageMatrix)),
|
|
309
469
|
...item.fill !== void 0 ? { fill: item.fill } : {},
|
|
310
470
|
...item.fill !== void 0 && item.fillRule === "evenodd" ? { fillRule: "evenodd" } : {},
|
|
311
|
-
...item.stroke !== void 0 ? { stroke: item.stroke } : {}
|
|
471
|
+
...item.stroke !== void 0 ? { stroke: item.stroke } : {},
|
|
472
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
312
473
|
};
|
|
313
474
|
}
|
|
314
475
|
function imagePlacementFrom(matrix) {
|
|
@@ -351,7 +512,8 @@ function convertImage(item, pageMatrix, images, cache, resolver, sink) {
|
|
|
351
512
|
return {
|
|
352
513
|
kind: "image",
|
|
353
514
|
imageId,
|
|
354
|
-
...imagePlacementFrom(multiplyMatrices(item.matrix, pageMatrix))
|
|
515
|
+
...imagePlacementFrom(multiplyMatrices(item.matrix, pageMatrix)),
|
|
516
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
355
517
|
};
|
|
356
518
|
}
|
|
357
519
|
function convertInlineImage(item, pageMatrix, images, resolver, sink) {
|
|
@@ -360,19 +522,22 @@ function convertInlineImage(item, pageMatrix, images, resolver, sink) {
|
|
|
360
522
|
return {
|
|
361
523
|
kind: "image",
|
|
362
524
|
imageId: registerExtractedImage(decoded.format, decoded.bytes, decoded.widthPx, decoded.heightPx, images),
|
|
363
|
-
...imagePlacementFrom(multiplyMatrices(item.matrix, pageMatrix))
|
|
525
|
+
...imagePlacementFrom(multiplyMatrices(item.matrix, pageMatrix)),
|
|
526
|
+
...item.layerName !== void 0 ? { layer: item.layerName } : {}
|
|
364
527
|
};
|
|
365
528
|
}
|
|
366
|
-
function readLinkAnnotations(page, pageMatrix, resolver) {
|
|
529
|
+
function readLinkAnnotations(page, pageMatrix, resolver, destinationRegistry) {
|
|
367
530
|
const annotsArr = asArray(dictGet(page, "Annots"));
|
|
368
531
|
if (annotsArr === void 0) return [];
|
|
369
532
|
const links = [];
|
|
370
533
|
for (const annotRef of annotsArr) {
|
|
371
534
|
const annot = resolver.resolveDict(annotRef);
|
|
372
535
|
if (annot === void 0 || asName(dictGet(annot, "Subtype")) !== "Link") continue;
|
|
373
|
-
const uri = readLinkUri(annot, resolver);
|
|
374
536
|
const rectArr = asArray(dictGet(annot, "Rect"));
|
|
375
|
-
if (
|
|
537
|
+
if (rectArr === void 0) continue;
|
|
538
|
+
const uri = readLinkUri(annot, resolver);
|
|
539
|
+
const destination = uri === void 0 ? readInternalDestination(annot, resolver, destinationRegistry) : void 0;
|
|
540
|
+
if (uri === void 0 && destination === void 0) continue;
|
|
376
541
|
const x1 = asNumber(rectArr[0]) ?? 0;
|
|
377
542
|
const y1 = asNumber(rectArr[1]) ?? 0;
|
|
378
543
|
const x2 = asNumber(rectArr[2]) ?? 0;
|
|
@@ -385,13 +550,24 @@ function readLinkAnnotations(page, pageMatrix, resolver) {
|
|
|
385
550
|
x: Math.max(x1, x2),
|
|
386
551
|
y: Math.max(y1, y2)
|
|
387
552
|
});
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
553
|
+
const contentsObj = dictGet(annot, "Contents");
|
|
554
|
+
const title = contentsObj?.kind === "string" ? decodePdfString(contentsObj.bytes) : void 0;
|
|
555
|
+
const box = {
|
|
391
556
|
xPt: Math.min(p1.x, p2.x),
|
|
392
557
|
yPt: Math.min(p1.y, p2.y),
|
|
393
558
|
widthPt: Math.abs(p2.x - p1.x),
|
|
394
|
-
heightPt: Math.abs(p2.y - p1.y)
|
|
559
|
+
heightPt: Math.abs(p2.y - p1.y),
|
|
560
|
+
...title !== void 0 ? { title } : {}
|
|
561
|
+
};
|
|
562
|
+
if (uri !== void 0) links.push({
|
|
563
|
+
kind: "link",
|
|
564
|
+
uri,
|
|
565
|
+
...box
|
|
566
|
+
});
|
|
567
|
+
else if (destination !== void 0) links.push({
|
|
568
|
+
kind: "internalLink",
|
|
569
|
+
destination,
|
|
570
|
+
...box
|
|
395
571
|
});
|
|
396
572
|
}
|
|
397
573
|
return links;
|
|
@@ -402,6 +578,12 @@ function readLinkUri(annot, resolver) {
|
|
|
402
578
|
const uriObj = dictGet(action, "URI");
|
|
403
579
|
return uriObj?.kind === "string" ? decodePdfString(uriObj.bytes) : void 0;
|
|
404
580
|
}
|
|
581
|
+
function readInternalDestination(annot, resolver, destinationRegistry) {
|
|
582
|
+
const dest = dictGet(annot, "Dest");
|
|
583
|
+
if (dest !== void 0) return destinationRegistry.intern(dest);
|
|
584
|
+
const action = resolver.resolveDict(dictGet(annot, "A"));
|
|
585
|
+
if (action !== void 0 && asName(dictGet(action, "S")) === "GoTo") return destinationRegistry.intern(dictGet(action, "D"));
|
|
586
|
+
}
|
|
405
587
|
function readPageNotes(page, resolver) {
|
|
406
588
|
const annotsArr = asArray(dictGet(page, "Annots"));
|
|
407
589
|
if (annotsArr === void 0) return;
|
|
@@ -414,23 +596,7 @@ function readPageNotes(page, resolver) {
|
|
|
414
596
|
if (contentsObj?.kind === "string") return decodePdfString(contentsObj.bytes);
|
|
415
597
|
}
|
|
416
598
|
}
|
|
417
|
-
function
|
|
418
|
-
if (bytes.length >= 2 && bytes[0] === 254 && bytes[1] === 255) {
|
|
419
|
-
let out = "";
|
|
420
|
-
for (let i = 2; i + 1 < bytes.length; i += 2) out += String.fromCharCode((bytes[i] ?? 0) << 8 | (bytes[i + 1] ?? 0));
|
|
421
|
-
return out;
|
|
422
|
-
}
|
|
423
|
-
return Array.from(bytes, (b) => String.fromCharCode(b)).join("");
|
|
424
|
-
}
|
|
425
|
-
const PDF_DATE_PATTERN = /^D:(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([+\-Z])?(\d{2})?'?(\d{2})?'?$/;
|
|
426
|
-
function parsePdfDate(raw) {
|
|
427
|
-
if (raw === void 0) return;
|
|
428
|
-
const match = PDF_DATE_PATTERN.exec(raw);
|
|
429
|
-
if (match === null) return;
|
|
430
|
-
const [, year, month = "01", day = "01", hour = "00", minute = "00", second = "00", tzSign, tzHour = "00", tzMinute = "00"] = match;
|
|
431
|
-
return `${year}-${month}-${day}T${hour}:${minute}:${second}${tzSign === void 0 || tzSign === "Z" ? "Z" : `${tzSign}${tzHour}:${tzMinute}`}`;
|
|
432
|
-
}
|
|
433
|
-
function readMetadata(trailer, resolver) {
|
|
599
|
+
function readMetadata(trailer, resolver, catalog, sink) {
|
|
434
600
|
const info = resolver.resolveDict(dictGet(trailer, "Info"));
|
|
435
601
|
if (info === void 0) return {};
|
|
436
602
|
const stringField = (key) => {
|
|
@@ -438,16 +604,52 @@ function readMetadata(trailer, resolver) {
|
|
|
438
604
|
return obj?.kind === "string" ? decodePdfString(obj.bytes) : void 0;
|
|
439
605
|
};
|
|
440
606
|
const keywords = stringField("Keywords")?.split(",").map((k) => k.trim()).filter((k) => k.length > 0);
|
|
607
|
+
const langObj = dictGet(catalog, "Lang");
|
|
608
|
+
const xmp = xmpPacket(catalog, resolver, sink);
|
|
609
|
+
const mirrored = readXmpMetadata(xmp ?? "");
|
|
441
610
|
return {
|
|
442
|
-
title: stringField("Title"),
|
|
443
|
-
author: stringField("Author"),
|
|
444
|
-
subject: stringField("Subject"),
|
|
445
|
-
keywords: keywords !== void 0 && keywords.length > 0 ? keywords : void 0,
|
|
446
|
-
creator: stringField("Creator"),
|
|
447
|
-
producer: stringField("Producer"),
|
|
448
|
-
createdIso: parsePdfDate(stringField("CreationDate")),
|
|
449
|
-
modifiedIso: parsePdfDate(stringField("ModDate"))
|
|
611
|
+
title: stringField("Title") ?? mirrored.title,
|
|
612
|
+
author: stringField("Author") ?? mirrored.author,
|
|
613
|
+
subject: stringField("Subject") ?? mirrored.subject,
|
|
614
|
+
keywords: (keywords !== void 0 && keywords.length > 0 ? keywords : void 0) ?? mirrored.keywords,
|
|
615
|
+
creator: stringField("Creator") ?? mirrored.creator,
|
|
616
|
+
producer: stringField("Producer") ?? mirrored.producer,
|
|
617
|
+
createdIso: parsePdfDate(stringField("CreationDate")) ?? mirrored.createdIso,
|
|
618
|
+
modifiedIso: parsePdfDate(stringField("ModDate")) ?? mirrored.modifiedIso,
|
|
619
|
+
...langObj?.kind === "string" ? { language: decodePdfString(langObj.bytes) } : {}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function xmpPacket(catalog, resolver, sink) {
|
|
623
|
+
const metadataObj = resolver.resolve(dictGet(catalog, "Metadata"));
|
|
624
|
+
if (metadataObj?.kind !== "stream") return;
|
|
625
|
+
const decoded = decodeStream(metadataObj.raw, metadataObj.dict, sink);
|
|
626
|
+
return new TextDecoder().decode(decoded.bytes);
|
|
627
|
+
}
|
|
628
|
+
function readDocumentResidue(doc, sink) {
|
|
629
|
+
const source = {};
|
|
630
|
+
const residue = (key, obj) => {
|
|
631
|
+
if (obj !== void 0) source[key] = {
|
|
632
|
+
format: "pdf",
|
|
633
|
+
xml: serializeObjectToText(obj)
|
|
634
|
+
};
|
|
635
|
+
};
|
|
636
|
+
const catalog = doc.catalog;
|
|
637
|
+
const packet = xmpPacket(catalog, doc, sink);
|
|
638
|
+
if (packet !== void 0) source.xmp = {
|
|
639
|
+
format: "pdf",
|
|
640
|
+
xml: packet
|
|
450
641
|
};
|
|
642
|
+
residue("viewer-preferences", dictGet(catalog, "ViewerPreferences"));
|
|
643
|
+
residue("page-mode", dictGet(catalog, "PageMode"));
|
|
644
|
+
residue("page-layout", dictGet(catalog, "PageLayout"));
|
|
645
|
+
residue("open-action", dictGet(catalog, "OpenAction"));
|
|
646
|
+
const outputIntents = asArray(dictGet(catalog, "OutputIntents"));
|
|
647
|
+
if (outputIntents !== void 0) residue("output-intents", pdfArray(outputIntents.map((intent) => doc.resolve(intent) ?? pdfNull())));
|
|
648
|
+
residue("piece-info", dictGet(catalog, "PieceInfo"));
|
|
649
|
+
residue("legal", dictGet(catalog, "Legal"));
|
|
650
|
+
residue("collection", dictGet(catalog, "Collection"));
|
|
651
|
+
residue("trailer-id", dictGet(doc.trailer, "ID"));
|
|
652
|
+
return source;
|
|
451
653
|
}
|
|
452
654
|
//#endregion
|
|
453
|
-
export {
|
|
655
|
+
export { normalizeRotation, pageRotationTransform, readPdf };
|
package/dist/serialize.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_bytes_writer = require("./bytes/writer.cjs");
|
|
3
2
|
const require_objects = require("./objects.cjs");
|
|
3
|
+
const require_bytes_writer = require("./bytes/writer.cjs");
|
|
4
4
|
//#region src/serialize.ts
|
|
5
5
|
const NUMBER_DECIMAL_PLACES = 4;
|
|
6
6
|
const NUMBER_EPSILON = 10 ** -4;
|
|
@@ -63,7 +63,11 @@ function serializeObject(obj) {
|
|
|
63
63
|
writeObject(writer, obj);
|
|
64
64
|
return writer.toBytes();
|
|
65
65
|
}
|
|
66
|
+
function serializeObjectToText(obj) {
|
|
67
|
+
return new TextDecoder().decode(serializeObject(obj));
|
|
68
|
+
}
|
|
66
69
|
//#endregion
|
|
67
70
|
exports.formatNumber = formatNumber;
|
|
68
71
|
exports.serializeObject = serializeObject;
|
|
72
|
+
exports.serializeObjectToText = serializeObjectToText;
|
|
69
73
|
exports.writeObject = writeObject;
|
package/dist/serialize.d.cts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { ByteWriter } from "./bytes/writer.cjs";
|
|
2
1
|
import { PdfObject } from "./objects.cjs";
|
|
2
|
+
import { ByteWriter } from "./bytes/writer.cjs";
|
|
3
3
|
//#region src/serialize.d.ts
|
|
4
4
|
declare function formatNumber(n: number): string;
|
|
5
5
|
declare function writeObject(writer: ByteWriter, obj: PdfObject): void;
|
|
6
6
|
declare function serializeObject(obj: PdfObject): Uint8Array<ArrayBuffer>;
|
|
7
|
+
declare function serializeObjectToText(obj: PdfObject): string;
|
|
7
8
|
//#endregion
|
|
8
|
-
export { formatNumber, serializeObject, writeObject };
|
|
9
|
+
export { formatNumber, serializeObject, serializeObjectToText, writeObject };
|
package/dist/serialize.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { ByteWriter } from "./bytes/writer.js";
|
|
2
1
|
import { PdfObject } from "./objects.js";
|
|
2
|
+
import { ByteWriter } from "./bytes/writer.js";
|
|
3
3
|
//#region src/serialize.d.ts
|
|
4
4
|
declare function formatNumber(n: number): string;
|
|
5
5
|
declare function writeObject(writer: ByteWriter, obj: PdfObject): void;
|
|
6
6
|
declare function serializeObject(obj: PdfObject): Uint8Array<ArrayBuffer>;
|
|
7
|
+
declare function serializeObjectToText(obj: PdfObject): string;
|
|
7
8
|
//#endregion
|
|
8
|
-
export { formatNumber, serializeObject, writeObject };
|
|
9
|
+
export { formatNumber, serializeObject, serializeObjectToText, writeObject };
|
package/dist/serialize.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ByteWriter } from "./bytes/writer.js";
|
|
2
1
|
import { pdfNum } from "./objects.js";
|
|
2
|
+
import { ByteWriter } from "./bytes/writer.js";
|
|
3
3
|
//#region src/serialize.ts
|
|
4
4
|
const NUMBER_DECIMAL_PLACES = 4;
|
|
5
5
|
const NUMBER_EPSILON = 10 ** -4;
|
|
@@ -62,5 +62,8 @@ function serializeObject(obj) {
|
|
|
62
62
|
writeObject(writer, obj);
|
|
63
63
|
return writer.toBytes();
|
|
64
64
|
}
|
|
65
|
+
function serializeObjectToText(obj) {
|
|
66
|
+
return new TextDecoder().decode(serializeObject(obj));
|
|
67
|
+
}
|
|
65
68
|
//#endregion
|
|
66
|
-
export { formatNumber, serializeObject, writeObject };
|
|
69
|
+
export { formatNumber, serializeObject, serializeObjectToText, writeObject };
|
package/dist/write.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_afm_widths = require("./afm-widths-BoeTOK2r.cjs");
|
|
3
|
-
const
|
|
4
|
-
const require_bytes_writer = require("./bytes/writer.cjs");
|
|
3
|
+
const require_notes_annotation_author = require("./notes-annotation-author.cjs");
|
|
5
4
|
const require_objects = require("./objects.cjs");
|
|
5
|
+
const require_bytes_writer = require("./bytes/writer.cjs");
|
|
6
|
+
const require_serialize = require("./serialize.cjs");
|
|
6
7
|
const require_bytes_flate = require("./bytes/flate.cjs");
|
|
8
|
+
const require_util_base64 = require("./util/base64.cjs");
|
|
7
9
|
const require_util_abort = require("./util/abort.cjs");
|
|
8
10
|
const require_image_jpeg_info = require("./image/jpeg-info.cjs");
|
|
9
|
-
const require_notes_annotation_author = require("./notes-annotation-author.cjs");
|
|
10
11
|
const require_image_png_decode = require("./image/png-decode.cjs");
|
|
11
12
|
const require_embedded_font = require("./embedded-font.cjs");
|
|
12
|
-
const require_serialize = require("./serialize.cjs");
|
|
13
13
|
const require_content_write = require("./content-write.cjs");
|
|
14
14
|
const require_embedded_font_write = require("./embedded-font-write.cjs");
|
|
15
15
|
const require_font_registry = require("./font-registry.cjs");
|
|
@@ -178,9 +178,55 @@ function buildLinkAnnotDict(link) {
|
|
|
178
178
|
})
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
|
+
function destinationViewArray(target) {
|
|
182
|
+
const n = (value) => value === void 0 ? require_objects.pdfNull() : require_objects.pdfNum(value);
|
|
183
|
+
if (target.kind === "xyz") return [
|
|
184
|
+
require_objects.pdfName("XYZ"),
|
|
185
|
+
n(target.leftPt),
|
|
186
|
+
n(target.topPt),
|
|
187
|
+
n(target.zoom)
|
|
188
|
+
];
|
|
189
|
+
if (target.kind === "fitH") return [require_objects.pdfName("FitH"), n(target.topPt)];
|
|
190
|
+
if (target.kind === "fitV") return [require_objects.pdfName("FitV"), n(target.leftPt)];
|
|
191
|
+
if (target.kind === "fitR") return [
|
|
192
|
+
require_objects.pdfName("FitR"),
|
|
193
|
+
n(target.leftPt),
|
|
194
|
+
n(target.bottomPt),
|
|
195
|
+
n(target.rightPt),
|
|
196
|
+
n(target.topPt)
|
|
197
|
+
];
|
|
198
|
+
if (target.kind === "fitBH") return [require_objects.pdfName("FitBH"), n(target.topPt)];
|
|
199
|
+
if (target.kind === "fitBV") return [require_objects.pdfName("FitBV"), n(target.leftPt)];
|
|
200
|
+
return [require_objects.pdfName(target.kind === "fitB" ? "FitB" : "Fit")];
|
|
201
|
+
}
|
|
202
|
+
function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
|
|
203
|
+
const destination = doc.destinations?.find((d) => d.name === link.destination);
|
|
204
|
+
if (destination === void 0) throw new Error(`internal link names destination "${link.destination}", which the document's destinations table does not carry -- this is a caller-invariant violation`);
|
|
205
|
+
const targetPage = pageAllocs[destination.pageIndex];
|
|
206
|
+
if (targetPage === void 0) throw new Error(`destination "${link.destination}" names page index ${destination.pageIndex}, which is beyond the document's own pages -- this is a caller-invariant violation`);
|
|
207
|
+
return require_objects.pdfDict({
|
|
208
|
+
Type: require_objects.pdfName("Annot"),
|
|
209
|
+
Subtype: require_objects.pdfName("Link"),
|
|
210
|
+
Rect: require_objects.pdfArray([
|
|
211
|
+
link.xPt,
|
|
212
|
+
link.yPt,
|
|
213
|
+
link.xPt + link.widthPt,
|
|
214
|
+
link.yPt + link.heightPt
|
|
215
|
+
].map((v) => require_objects.pdfNum(v))),
|
|
216
|
+
Border: require_objects.pdfArray([
|
|
217
|
+
0,
|
|
218
|
+
0,
|
|
219
|
+
0
|
|
220
|
+
].map((v) => require_objects.pdfNum(v))),
|
|
221
|
+
Dest: require_objects.pdfArray([require_objects.pdfRef(targetPage.pageNum, 0), ...destinationViewArray(destination.target)])
|
|
222
|
+
});
|
|
223
|
+
}
|
|
181
224
|
function isLinkItem(item) {
|
|
182
225
|
return item.kind === "link";
|
|
183
226
|
}
|
|
227
|
+
function isInternalLinkItem(item) {
|
|
228
|
+
return item.kind === "internalLink";
|
|
229
|
+
}
|
|
184
230
|
const NOTES_ANNOTATION_HIDDEN_FLAG = 2;
|
|
185
231
|
function buildNotesAnnotDict(notes) {
|
|
186
232
|
return require_objects.pdfDict({
|
|
@@ -436,7 +482,7 @@ function writePdf(doc, options = {}) {
|
|
|
436
482
|
num: contentsNum,
|
|
437
483
|
value: require_objects.pdfStream(contentsDict, finalContentBytes)
|
|
438
484
|
});
|
|
439
|
-
const annots = page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link));
|
|
485
|
+
const annots = [...page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link)), ...page.items.filter(isInternalLinkItem).map((link) => buildInternalLinkAnnotDict(link, doc, pageAllocs))];
|
|
440
486
|
if (page.notes !== void 0 && page.notes.length > 0) annots.push(buildNotesAnnotDict(page.notes));
|
|
441
487
|
const pageEntries = /* @__PURE__ */ new Map([
|
|
442
488
|
["Type", require_objects.pdfName("Page")],
|