unpdf 1.6.2 → 1.8.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 +61 -25
- package/dist/index.cjs +386 -353
- package/dist/index.d.cts +101 -91
- package/dist/index.d.mts +101 -91
- package/dist/index.mjs +385 -351
- package/dist/pdfjs.d.mts +1 -1
- package/dist/pdfjs.d.ts +1 -1
- package/dist/pdfjs.mjs +52 -59
- package/dist/types/external/brotli/decode.d.ts +5 -0
- package/dist/types/external/jbig2/jbig2.d.ts +2 -0
- package/dist/types/external/openjpeg/openjpeg.d.ts +2 -0
- package/dist/types/external/qcms/qcms.d.ts +92 -0
- package/dist/types/external/qcms/qcms_utils.d.ts +14 -0
- package/dist/types/src/core/ascii_85_stream.d.ts +7 -0
- package/dist/types/src/core/ascii_hex_stream.d.ts +7 -0
- package/dist/types/src/core/base_stream.d.ts +45 -0
- package/dist/types/src/core/brotli_stream.d.ts +9 -0
- package/dist/types/src/core/calculate_md5.d.ts +1 -0
- package/dist/types/src/core/calculate_sha256.d.ts +1 -0
- package/dist/types/src/core/calculate_sha_other.d.ts +2 -0
- package/dist/types/src/core/catalog.d.ts +169 -0
- package/dist/types/src/core/ccitt_stream.d.ts +18 -0
- package/dist/types/src/core/cleanup_helper.d.ts +1 -0
- package/dist/types/src/core/colorspace.d.ts +177 -0
- package/dist/types/src/core/colorspace_utils.d.ts +21 -0
- package/dist/types/src/core/core_utils.d.ts +132 -0
- package/dist/types/src/core/crypto.d.ts +136 -0
- package/dist/types/src/core/decode_stream.d.ts +32 -0
- package/dist/types/src/core/decrypt_stream.d.ts +9 -0
- package/dist/types/src/core/file_spec.d.ts +72 -0
- package/dist/types/src/core/flate_stream.d.ts +14 -0
- package/dist/types/src/core/icc_colorspace.d.ts +22 -0
- package/dist/types/src/core/image_utils.d.ts +52 -0
- package/dist/types/src/core/jbig2_ccittFax.d.ts +13 -0
- package/dist/types/src/core/jbig2_stream.d.ts +17 -0
- package/dist/types/src/core/jpeg_stream.d.ts +24 -0
- package/dist/types/src/core/jpg.d.ts +62 -0
- package/dist/types/src/core/jpx.d.ts +24 -0
- package/dist/types/src/core/jpx_stream.d.ts +15 -0
- package/dist/types/src/core/lzw_stream.d.ts +19 -0
- package/dist/types/src/core/metadata_parser.d.ts +13 -0
- package/dist/types/src/core/name_number_tree.d.ts +21 -0
- package/dist/types/src/core/parser.d.ts +121 -0
- package/dist/types/src/core/pattern.d.ts +63 -0
- package/dist/types/src/core/predictor_stream.d.ts +14 -0
- package/dist/types/src/core/primitives.d.ts +81 -0
- package/dist/types/src/core/run_length_stream.d.ts +6 -0
- package/dist/types/src/core/stream.d.ts +20 -0
- package/dist/types/src/core/string_utils.d.ts +5 -0
- package/dist/types/src/core/struct_tree.d.ts +93 -0
- package/dist/types/src/core/unicode.d.ts +5 -0
- package/dist/types/src/core/wasm_image.d.ts +21 -0
- package/dist/types/src/core/xml_parser.d.ts +79 -0
- package/dist/types/src/core/xref.d.ts +52 -0
- package/dist/types/src/display/annotation_layer.d.ts +11 -9
- package/dist/types/src/display/api.d.ts +92 -65
- package/dist/types/src/display/binary_data_factory.d.ts +0 -4
- package/dist/types/src/display/canvas.d.ts +58 -12
- package/dist/types/src/display/canvas_dependency_tracker.d.ts +2 -2
- package/dist/types/src/display/display_utils.d.ts +4 -156
- package/dist/types/src/display/draw_layer.d.ts +127 -2
- package/dist/types/src/display/editor/alt_text.d.ts +1 -1
- package/dist/types/src/display/editor/annotation_editor_layer.d.ts +3 -3
- package/dist/types/src/display/editor/color_picker.d.ts +3 -2
- package/dist/types/src/display/editor/draw.d.ts +10 -3
- package/dist/types/src/display/editor/drawers/freedraw.d.ts +3 -3
- package/dist/types/src/display/editor/drawers/highlight.d.ts +0 -1
- package/dist/types/src/display/editor/drawers/outline.d.ts +0 -1
- package/dist/types/src/display/editor/drawers/signaturedraw.d.ts +13 -13
- package/dist/types/src/display/editor/editor.d.ts +2 -1
- package/dist/types/src/display/editor/freetext.d.ts +2 -2
- package/dist/types/src/display/editor/highlight.d.ts +3 -3
- package/dist/types/src/display/editor/ink.d.ts +2 -0
- package/dist/types/src/display/editor/toolbar.d.ts +2 -2
- package/dist/types/src/display/editor/tools.d.ts +31 -14
- package/dist/types/src/display/filter_factory.d.ts +26 -0
- package/dist/types/src/display/node_utils.d.ts +2 -2
- package/dist/types/src/display/obj_bin_transform_display.d.ts +2 -6
- package/dist/types/src/display/optional_content_config.d.ts +13 -3
- package/dist/types/src/display/page_viewport.d.ts +137 -0
- package/dist/types/src/display/pattern_helper.d.ts +11 -4
- package/dist/types/src/display/text_layer.d.ts +13 -13
- package/dist/types/src/display/text_layer_images.d.ts +1 -1
- package/dist/types/src/display/webgpu.d.ts +11 -0
- package/dist/types/src/display/worker_options.d.ts +2 -2
- package/dist/types/src/display/xfa_layer.d.ts +10 -3
- package/dist/types/src/display/xfa_text.d.ts +2 -2
- package/dist/types/src/pdf.d.ts +10 -9
- package/dist/types/src/shared/image_utils.d.ts +11 -0
- package/dist/types/src/shared/internal_evt.d.ts +7 -0
- package/dist/types/src/shared/math_clamp.d.ts +1 -0
- package/dist/types/src/shared/util.d.ts +24 -13
- package/dist/types/web/annotation_editor_layer_builder.d.ts +5 -5
- package/dist/types/web/annotation_layer_builder.d.ts +14 -11
- package/dist/types/web/app_options.d.ts +1 -1
- package/dist/types/web/autolinker.d.ts +3 -3
- package/dist/types/web/base_pdf_page_view.d.ts +1 -0
- package/dist/types/web/comment_manager.d.ts +1 -1
- package/dist/types/web/draw_layer_builder.d.ts +44 -0
- package/dist/types/web/event_utils.d.ts +0 -8
- package/dist/types/web/generic_scripting.d.ts +1 -1
- package/dist/types/web/genericl10n.d.ts +5 -5
- package/dist/types/web/internal_evt.d.ts +7 -0
- package/dist/types/web/l10n.d.ts +2 -2
- package/dist/types/web/pdf_find_controller.d.ts +16 -5
- package/dist/types/web/pdf_history.d.ts +1 -1
- package/dist/types/web/pdf_link_service.d.ts +10 -2
- package/dist/types/web/pdf_page_view.d.ts +19 -12
- package/dist/types/web/pdf_rendering_queue.d.ts +3 -3
- package/dist/types/web/pdf_scripting_manager.d.ts +1 -1
- package/dist/types/web/pdf_thumbnail_view.d.ts +9 -9
- package/dist/types/web/pdf_thumbnail_viewer.d.ts +38 -19
- package/dist/types/web/pdf_viewer.d.ts +28 -14
- package/dist/types/web/renderable_view.d.ts +2 -2
- package/dist/types/web/struct_tree_layer_builder.d.ts +1 -1
- package/dist/types/web/text_accessibility.d.ts +1 -1
- package/dist/types/web/text_highlighter.d.ts +6 -6
- package/dist/types/web/text_layer_builder.d.ts +10 -10
- package/dist/types/web/xfa_layer_builder.d.ts +8 -8
- package/package.json +25 -24
- package/dist/index.d.ts +0 -182
- package/dist/types/src/display/webgpu_mesh.d.ts +0 -3
package/dist/index.mjs
CHANGED
|
@@ -1,416 +1,450 @@
|
|
|
1
|
+
//#region src/_internal/dommatrix-polyfill.ts
|
|
1
2
|
function polyfillDOMMatrix() {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.a *= sx;
|
|
35
|
-
this.b *= sx;
|
|
36
|
-
this.c *= sy;
|
|
37
|
-
this.d *= sy;
|
|
38
|
-
return this;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
3
|
+
if (typeof globalThis.DOMMatrix !== "undefined") return;
|
|
4
|
+
globalThis.DOMMatrix = class DOMMatrix {
|
|
5
|
+
constructor(init) {
|
|
6
|
+
if (Array.isArray(init) && init.length === 6) {
|
|
7
|
+
this.a = init[0];
|
|
8
|
+
this.b = init[1];
|
|
9
|
+
this.c = init[2];
|
|
10
|
+
this.d = init[3];
|
|
11
|
+
this.e = init[4];
|
|
12
|
+
this.f = init[5];
|
|
13
|
+
} else {
|
|
14
|
+
this.a = 1;
|
|
15
|
+
this.b = 0;
|
|
16
|
+
this.c = 0;
|
|
17
|
+
this.d = 1;
|
|
18
|
+
this.e = 0;
|
|
19
|
+
this.f = 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
translateSelf(tx, ty = 0) {
|
|
23
|
+
this.e = this.a * tx + this.c * ty + this.e;
|
|
24
|
+
this.f = this.b * tx + this.d * ty + this.f;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
scaleSelf(sx, sy = sx) {
|
|
28
|
+
this.a *= sx;
|
|
29
|
+
this.b *= sx;
|
|
30
|
+
this.c *= sy;
|
|
31
|
+
this.d *= sy;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
41
35
|
}
|
|
42
|
-
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/_internal/env.ts
|
|
38
|
+
/**
|
|
39
|
+
* Stubs browser globals that PDF.js expects at the module level
|
|
40
|
+
* in non-browser environments.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* Must be called before importing any PDF.js module, since PDF.js
|
|
44
|
+
* accesses these globals at parse time (top-level constants).
|
|
45
|
+
*/
|
|
43
46
|
function stubBrowserGlobals() {
|
|
44
|
-
|
|
47
|
+
polyfillDOMMatrix();
|
|
45
48
|
}
|
|
46
|
-
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils.ts
|
|
47
51
|
let resolvedModule;
|
|
48
52
|
const isNode = globalThis.process?.release?.name === "node";
|
|
49
53
|
const isBrowser = typeof window !== "undefined";
|
|
54
|
+
/**
|
|
55
|
+
* Returns a PDFDocumentProxy instance from a given binary data.
|
|
56
|
+
*
|
|
57
|
+
* Applies the following defaults:
|
|
58
|
+
* - `useSystemFonts: true`
|
|
59
|
+
*
|
|
60
|
+
* In Node.js environments, additionally applies:
|
|
61
|
+
* - `disableFontFace: true`
|
|
62
|
+
* - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
|
|
63
|
+
* - `cMapUrl` and `cMapPacked` resolved from the local `pdfjs-dist` package
|
|
64
|
+
*/
|
|
50
65
|
async function getDocumentProxy(data, options = {}) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
const { getDocument } = await getResolvedPDFJS();
|
|
67
|
+
let nodeDefaults = {};
|
|
68
|
+
if (isNode) try {
|
|
69
|
+
const base = import.meta.resolve("pdfjs-dist/package.json");
|
|
70
|
+
nodeDefaults = {
|
|
71
|
+
disableFontFace: true,
|
|
72
|
+
standardFontDataUrl: new URL("./standard_fonts/", base).href,
|
|
73
|
+
cMapUrl: new URL("./cmaps/", base).href,
|
|
74
|
+
cMapPacked: true
|
|
75
|
+
};
|
|
76
|
+
} catch {}
|
|
77
|
+
return await getDocument({
|
|
78
|
+
data,
|
|
79
|
+
useSystemFonts: true,
|
|
80
|
+
...nodeDefaults,
|
|
81
|
+
...options
|
|
82
|
+
}).promise;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Runs an operation on a `PDFDocumentProxy` resolved from either binary data
|
|
86
|
+
* or an existing proxy. Documents created here are destroyed once the
|
|
87
|
+
* operation settles – caller-supplied proxies keep their lifecycle with the
|
|
88
|
+
* caller.
|
|
89
|
+
*/
|
|
90
|
+
async function withDocument(data, operation, options) {
|
|
91
|
+
const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data, options);
|
|
92
|
+
try {
|
|
93
|
+
return await operation(pdf);
|
|
94
|
+
} finally {
|
|
95
|
+
if (pdf !== data) await pdf.loadingTask.destroy();
|
|
96
|
+
}
|
|
72
97
|
}
|
|
73
98
|
async function getResolvedPDFJS() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
return resolvedModule;
|
|
99
|
+
if (!resolvedModule) await resolvePDFJSImport();
|
|
100
|
+
return resolvedModule;
|
|
78
101
|
}
|
|
79
102
|
async function resolvePDFJSImport(pdfjsResolver, { reload = false } = {}) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
resolvedModule = await import('unpdf/pdfjs');
|
|
94
|
-
} catch (error) {
|
|
95
|
-
throw new Error(`Serverless PDF.js bundle could not be resolved: ${error}`);
|
|
96
|
-
}
|
|
103
|
+
if (resolvedModule && !reload) return;
|
|
104
|
+
stubBrowserGlobals();
|
|
105
|
+
if (pdfjsResolver) try {
|
|
106
|
+
resolvedModule = await interopDefault(pdfjsResolver());
|
|
107
|
+
return;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw new Error(`PDF.js could not be resolved: ${error}`);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
resolvedModule = await import("unpdf/pdfjs");
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new Error(`Serverless PDF.js bundle could not be resolved: ${error}`);
|
|
115
|
+
}
|
|
97
116
|
}
|
|
98
117
|
function isPDFDocumentProxy(data) {
|
|
99
|
-
|
|
118
|
+
return typeof data === "object" && data !== null && "_pdfInfo" in data;
|
|
100
119
|
}
|
|
101
120
|
async function interopDefault(m) {
|
|
102
|
-
|
|
103
|
-
|
|
121
|
+
const resolved = await m;
|
|
122
|
+
return resolved.default || resolved;
|
|
104
123
|
}
|
|
105
|
-
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/_internal/canvas.ts
|
|
106
126
|
let resolvedCanvasModule;
|
|
107
127
|
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
context.context = void 0;
|
|
141
|
-
}
|
|
142
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
143
|
-
_createCanvas(width, height) {
|
|
144
|
-
throw new Error("Not implemented");
|
|
145
|
-
}
|
|
146
|
-
}
|
|
128
|
+
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
129
|
+
* @see https://github.com/mozilla/pdf.js/blob/b8de9a372f9bbf7e33adb362eeae5ef1919dba73/src/display/canvas_factory.js#L18
|
|
130
|
+
* @license Apache-2.0
|
|
131
|
+
*/
|
|
132
|
+
var BaseCanvasFactory = class {
|
|
133
|
+
#enableHWA = false;
|
|
134
|
+
constructor({ enableHWA = false } = {}) {
|
|
135
|
+
this.#enableHWA = enableHWA;
|
|
136
|
+
}
|
|
137
|
+
create(width, height) {
|
|
138
|
+
const canvas = this._createCanvas(width, height);
|
|
139
|
+
return {
|
|
140
|
+
canvas,
|
|
141
|
+
context: canvas.getContext("2d", { willReadFrequently: !this.#enableHWA })
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
reset({ canvas }, width, height) {
|
|
145
|
+
if (!canvas) throw new Error("Canvas is not specified");
|
|
146
|
+
canvas.width = width;
|
|
147
|
+
canvas.height = height;
|
|
148
|
+
}
|
|
149
|
+
destroy(context) {
|
|
150
|
+
if (!context.canvas) throw new Error("Canvas is not specified");
|
|
151
|
+
context.canvas.width = 0;
|
|
152
|
+
context.canvas.height = 0;
|
|
153
|
+
context.canvas = void 0;
|
|
154
|
+
context.context = void 0;
|
|
155
|
+
}
|
|
156
|
+
_createCanvas(width, height) {
|
|
157
|
+
throw new Error("Not implemented");
|
|
158
|
+
}
|
|
159
|
+
};
|
|
147
160
|
/**
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return resolvedCanvasModule.createCanvas(width, height);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
161
|
+
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
162
|
+
* @see https://github.com/mozilla/pdf.js/blob/b8de9a372f9bbf7e33adb362eeae5ef1919dba73/src/display/canvas_factory.js#L18
|
|
163
|
+
* @license Apache-2.0
|
|
164
|
+
*/
|
|
165
|
+
var DOMCanvasFactory = class extends BaseCanvasFactory {
|
|
166
|
+
constructor({ ownerDocument = globalThis.document, enableHWA = false } = {}) {
|
|
167
|
+
super({ enableHWA });
|
|
168
|
+
this._document = ownerDocument;
|
|
169
|
+
}
|
|
170
|
+
_createCanvas(width, height) {
|
|
171
|
+
const canvas = this._document.createElement("canvas");
|
|
172
|
+
canvas.width = width;
|
|
173
|
+
canvas.height = height;
|
|
174
|
+
return canvas;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var NodeCanvasFactory = class extends BaseCanvasFactory {
|
|
178
|
+
constructor({ enableHWA = false } = {}) {
|
|
179
|
+
super({ enableHWA });
|
|
180
|
+
}
|
|
181
|
+
_createCanvas(width, height) {
|
|
182
|
+
if (!resolvedCanvasModule) throw new Error("@napi-rs/canvas module is not resolved");
|
|
183
|
+
return resolvedCanvasModule.createCanvas(width, height);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
176
186
|
async function resolveCanvasModule(canvasImport) {
|
|
177
|
-
|
|
187
|
+
resolvedCanvasModule ??= await interopDefault(canvasImport());
|
|
188
|
+
globalThis[Symbol.for("unpdf.canvasModule")] = resolvedCanvasModule;
|
|
178
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Injects `DOMMatrix`, `ImageData` and `Path2D` constructors from the
|
|
192
|
+
* `@napi-rs/canvas` package into the global scope. This is necessary for
|
|
193
|
+
* Node.js environments that do not support these constructors natively.
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* `DOMMatrix` is always set because {@link stubBrowserGlobals} may have
|
|
197
|
+
* installed a minimal stub to allow PDF.js to import – the real
|
|
198
|
+
* `@napi-rs/canvas` implementation must take precedence for rendering.
|
|
199
|
+
*/
|
|
179
200
|
function injectCanvasConstructors() {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
globalThis.ImageData = resolvedCanvasModule.ImageData;
|
|
185
|
-
if (typeof globalThis.Path2D === "undefined")
|
|
186
|
-
globalThis.Path2D = resolvedCanvasModule.Path2D;
|
|
201
|
+
if (!resolvedCanvasModule) return;
|
|
202
|
+
globalThis.DOMMatrix = resolvedCanvasModule.DOMMatrix;
|
|
203
|
+
if (typeof globalThis.ImageData === "undefined") globalThis.ImageData = resolvedCanvasModule.ImageData;
|
|
204
|
+
if (typeof globalThis.Path2D === "undefined") globalThis.Path2D = resolvedCanvasModule.Path2D;
|
|
187
205
|
}
|
|
188
|
-
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/image.ts
|
|
208
|
+
/**
|
|
209
|
+
* Extracts images from a specific page of a PDF document, including necessary metadata,
|
|
210
|
+
* such as width, height, and calculated color channels.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* const imagesData = await extractImages(pdf, pageNum)
|
|
214
|
+
*
|
|
215
|
+
* for (const imgData of imagesData) {
|
|
216
|
+
* const imageIndex = totalImagesProcessed + 1
|
|
217
|
+
* await sharp(imgData.data, {
|
|
218
|
+
* raw: { width: imgData.width, height: imgData.height, channels: imgData.channels }
|
|
219
|
+
* })
|
|
220
|
+
* .png()
|
|
221
|
+
* .toFile(`${imageIndex}.png`)
|
|
222
|
+
* }
|
|
223
|
+
*/
|
|
189
224
|
async function extractImages$1(data, pageNumber) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
height,
|
|
220
|
-
channels,
|
|
221
|
-
key: imageKey
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
return images;
|
|
225
|
+
return await withDocument(data, async (pdf) => {
|
|
226
|
+
if (pageNumber < 1 || pageNumber > pdf.numPages) throw new Error(`Invalid page number. Must be between 1 and ${pdf.numPages}.`);
|
|
227
|
+
const page = await pdf.getPage(pageNumber);
|
|
228
|
+
const operatorList = await page.getOperatorList();
|
|
229
|
+
const { OPS } = await getResolvedPDFJS();
|
|
230
|
+
const images = [];
|
|
231
|
+
for (let i = 0; i < operatorList.fnArray.length; i++) {
|
|
232
|
+
if (operatorList.fnArray[i] !== OPS.paintImageXObject) continue;
|
|
233
|
+
const imageKey = operatorList.argsArray[i][0];
|
|
234
|
+
const image = await new Promise((resolve) => (imageKey.startsWith("g_") ? page.commonObjs : page.objs).get(imageKey, resolve));
|
|
235
|
+
if (!image || !image.data || !image.width || !image.height) continue;
|
|
236
|
+
const { width, height, data } = image;
|
|
237
|
+
const calculatedChannels = data.length / (width * height);
|
|
238
|
+
if (![
|
|
239
|
+
1,
|
|
240
|
+
3,
|
|
241
|
+
4
|
|
242
|
+
].includes(calculatedChannels)) continue;
|
|
243
|
+
const channels = calculatedChannels;
|
|
244
|
+
images.push({
|
|
245
|
+
data,
|
|
246
|
+
width,
|
|
247
|
+
height,
|
|
248
|
+
channels,
|
|
249
|
+
key: imageKey
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return images;
|
|
253
|
+
});
|
|
225
254
|
}
|
|
226
255
|
async function renderPageAsImage$1(data, pageNumber, options = {}) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
256
|
+
const CanvasFactory = await createIsomorphicCanvasFactory(options.canvasImport);
|
|
257
|
+
return await withDocument(data, async (pdf) => {
|
|
258
|
+
if (pageNumber < 1 || pageNumber > pdf.numPages) throw new Error(`Invalid page number. Must be between 1 and ${pdf.numPages}.`);
|
|
259
|
+
const page = await pdf.getPage(pageNumber);
|
|
260
|
+
const defaultViewport = page.getViewport({ scale: 1 });
|
|
261
|
+
let scale = options.scale || 1;
|
|
262
|
+
if (options.width) scale = options.width / defaultViewport.width;
|
|
263
|
+
else if (options.height) scale = options.height / defaultViewport.height;
|
|
264
|
+
const viewport = page.getViewport({ scale: Math.max(0, scale) });
|
|
265
|
+
const canvasFactory = new CanvasFactory();
|
|
266
|
+
const drawingContext = canvasFactory.create(viewport.width, viewport.height);
|
|
267
|
+
try {
|
|
268
|
+
await page.render({
|
|
269
|
+
canvas: drawingContext.canvas,
|
|
270
|
+
canvasContext: drawingContext.context,
|
|
271
|
+
viewport
|
|
272
|
+
}).promise;
|
|
273
|
+
const { canvas } = drawingContext;
|
|
274
|
+
if (options.toDataURL) return canvas.toDataURL();
|
|
275
|
+
if ("encode" in canvas) {
|
|
276
|
+
const buffer = await canvas.encode("png");
|
|
277
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
278
|
+
}
|
|
279
|
+
const blob = await new Promise((resolve) => {
|
|
280
|
+
canvas.toBlob(resolve);
|
|
281
|
+
});
|
|
282
|
+
if (!blob) throw new Error("Failed to encode canvas to a PNG blob.");
|
|
283
|
+
return await blob.arrayBuffer();
|
|
284
|
+
} finally {
|
|
285
|
+
canvasFactory.destroy(drawingContext);
|
|
286
|
+
}
|
|
287
|
+
}, { CanvasFactory });
|
|
253
288
|
}
|
|
254
289
|
async function createIsomorphicCanvasFactory(canvasImport) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return NodeCanvasFactory;
|
|
264
|
-
}
|
|
265
|
-
throw new Error("Unsupported environment for canvas creation.");
|
|
290
|
+
if (isBrowser) return DOMCanvasFactory;
|
|
291
|
+
if (isNode) {
|
|
292
|
+
if (!canvasImport) throw new Error("Parameter \"canvasImport\" is required in Node.js environment.");
|
|
293
|
+
await resolveCanvasModule(canvasImport);
|
|
294
|
+
injectCanvasConstructors();
|
|
295
|
+
return NodeCanvasFactory;
|
|
296
|
+
}
|
|
297
|
+
throw new Error("Unsupported environment for canvas creation.");
|
|
266
298
|
}
|
|
267
|
-
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/links.ts
|
|
268
301
|
async function extractLinks$1(data) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
};
|
|
302
|
+
return await withDocument(data, async (pdf) => {
|
|
303
|
+
const pageLinks = await Promise.all(Array.from({ length: pdf.numPages }, (_, i) => getPageLinks(pdf, i + 1)));
|
|
304
|
+
return {
|
|
305
|
+
totalPages: pdf.numPages,
|
|
306
|
+
links: pageLinks.flat()
|
|
307
|
+
};
|
|
308
|
+
});
|
|
277
309
|
}
|
|
278
310
|
async function getPageLinks(document, pageNumber) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (annotation.subtype === "Link" && annotation.url) {
|
|
284
|
-
links.push(annotation.url);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return links;
|
|
311
|
+
const annotations = await (await document.getPage(pageNumber)).getAnnotations();
|
|
312
|
+
const links = [];
|
|
313
|
+
for (const annotation of annotations) if (annotation.subtype === "Link" && annotation.url) links.push(annotation.url);
|
|
314
|
+
return links;
|
|
288
315
|
}
|
|
289
|
-
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/meta.ts
|
|
290
318
|
const XMP_DATE_PROPERTIES = [
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
319
|
+
"xmp:createdate",
|
|
320
|
+
"xmp:modifydate",
|
|
321
|
+
"xmp:metadatadate",
|
|
322
|
+
"xap:createdate",
|
|
323
|
+
"xap:modifydate",
|
|
324
|
+
"xap:metadatadate"
|
|
297
325
|
];
|
|
298
326
|
async function getMeta$1(data, options = {}) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
return target[prop];
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return {
|
|
328
|
-
info,
|
|
329
|
-
metadata: meta?.metadata || {}
|
|
330
|
-
};
|
|
327
|
+
return await withDocument(data, async (pdf) => {
|
|
328
|
+
const meta = await pdf.getMetadata();
|
|
329
|
+
const info = meta?.info || {};
|
|
330
|
+
if (options.parseDates) {
|
|
331
|
+
const { PDFDateString } = await getResolvedPDFJS();
|
|
332
|
+
if (info?.CreationDate) info.CreationDate = PDFDateString.toDateObject(info?.CreationDate);
|
|
333
|
+
if (info?.ModDate) info.ModDate = PDFDateString.toDateObject(info?.ModDate);
|
|
334
|
+
if (meta.metadata) meta.metadata = new Proxy(meta.metadata, { get(target, prop) {
|
|
335
|
+
if (prop === "get") return (name) => {
|
|
336
|
+
const value = target.get(name);
|
|
337
|
+
if (XMP_DATE_PROPERTIES.includes(name) && value) return parseISODateString(value);
|
|
338
|
+
return value;
|
|
339
|
+
};
|
|
340
|
+
return target[prop];
|
|
341
|
+
} });
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
info,
|
|
345
|
+
metadata: meta?.metadata || {}
|
|
346
|
+
};
|
|
347
|
+
});
|
|
331
348
|
}
|
|
332
349
|
function parseISODateString(isoDateString) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (!Number.isNaN(parsedDate)) {
|
|
337
|
-
return new Date(parsedDate);
|
|
338
|
-
}
|
|
350
|
+
if (!isoDateString) return;
|
|
351
|
+
const parsedDate = Date.parse(isoDateString);
|
|
352
|
+
if (!Number.isNaN(parsedDate)) return new Date(parsedDate);
|
|
339
353
|
}
|
|
340
|
-
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/text.ts
|
|
341
356
|
async function extractTextItems$1(data) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
357
|
+
return await withDocument(data, async (pdf) => {
|
|
358
|
+
const items = await Promise.all(Array.from({ length: pdf.numPages }, (_, i) => getPageTextItems(pdf, i + 1)));
|
|
359
|
+
return {
|
|
360
|
+
totalPages: pdf.numPages,
|
|
361
|
+
items
|
|
362
|
+
};
|
|
363
|
+
});
|
|
347
364
|
}
|
|
348
365
|
async function getPageTextItems(document, pageNumber) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
});
|
|
366
|
+
const content = await (await document.getPage(pageNumber)).getTextContent();
|
|
367
|
+
const styles = content.styles;
|
|
368
|
+
return content.items.filter((item) => item.str != null).map((item) => {
|
|
369
|
+
const [_a, _b, c, d, e, f] = item.transform;
|
|
370
|
+
return {
|
|
371
|
+
str: item.str,
|
|
372
|
+
x: e,
|
|
373
|
+
y: f,
|
|
374
|
+
width: item.width,
|
|
375
|
+
height: item.height,
|
|
376
|
+
fontSize: Math.hypot(c, d),
|
|
377
|
+
fontFamily: styles[item.fontName]?.fontFamily ?? "",
|
|
378
|
+
dir: item.dir,
|
|
379
|
+
hasEOL: item.hasEOL
|
|
380
|
+
};
|
|
381
|
+
});
|
|
366
382
|
}
|
|
367
383
|
async function extractText$1(data, options = {}) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
};
|
|
384
|
+
const { mergePages = false } = options;
|
|
385
|
+
return await withDocument(data, async (pdf) => {
|
|
386
|
+
const texts = await Promise.all(Array.from({ length: pdf.numPages }, (_, i) => getPageText(pdf, i + 1)));
|
|
387
|
+
return {
|
|
388
|
+
totalPages: pdf.numPages,
|
|
389
|
+
text: mergePages ? normalizeMergedText(texts) : texts
|
|
390
|
+
};
|
|
391
|
+
});
|
|
377
392
|
}
|
|
378
393
|
async function getPageText(document, pageNumber) {
|
|
379
|
-
|
|
380
|
-
const content = await page.getTextContent();
|
|
381
|
-
return content.items.filter((item) => item.str != null).map((item) => item.str + (item.hasEOL ? "\n" : "")).join("");
|
|
394
|
+
return (await (await document.getPage(pageNumber)).getTextContent()).items.filter((item) => item.str != null).map((item) => item.str + (item.hasEOL ? "\n" : "")).join("");
|
|
382
395
|
}
|
|
383
|
-
|
|
396
|
+
/**
|
|
397
|
+
* Collapses whitespace without destroying the line structure: `hasEOL` and
|
|
398
|
+
* page-join line breaks survive, but at most one blank line remains.
|
|
399
|
+
*/
|
|
400
|
+
function normalizeMergedText(texts) {
|
|
401
|
+
return texts.join("\n").replace(/[^\S\n]+/g, " ").replace(/ ?\n ?/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
402
|
+
}
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/config.ts
|
|
405
|
+
/**
|
|
406
|
+
* By default, unpdf will use the latest version of PDF.js compiled for
|
|
407
|
+
* serverless environments. If you want to use a different version, you can
|
|
408
|
+
* provide a custom resolver function.
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* // Use the official PDF.js build (make sure to install it first)
|
|
412
|
+
* import { definePDFJSModule } from 'unpdf'
|
|
413
|
+
*
|
|
414
|
+
* await definePDFJSModule(() => import('pdfjs-dist'))
|
|
415
|
+
*/
|
|
384
416
|
async function definePDFJSModule(pdfjs) {
|
|
385
|
-
|
|
417
|
+
await resolvePDFJSImport(pdfjs, { reload: true });
|
|
386
418
|
}
|
|
419
|
+
/** @deprecated Use `definePDFJSModule` instead. Will be removed in v2. */
|
|
387
420
|
async function configureUnPDF(options) {
|
|
388
|
-
|
|
421
|
+
await resolvePDFJSImport(options.pdfjs, { reload: true });
|
|
389
422
|
}
|
|
390
|
-
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/index.ts
|
|
391
425
|
const getMeta = async (...args) => {
|
|
392
|
-
|
|
393
|
-
|
|
426
|
+
await resolvePDFJSImport();
|
|
427
|
+
return await getMeta$1(...args);
|
|
394
428
|
};
|
|
395
429
|
const extractText = async (...args) => {
|
|
396
|
-
|
|
397
|
-
|
|
430
|
+
await resolvePDFJSImport();
|
|
431
|
+
return await extractText$1(...args);
|
|
398
432
|
};
|
|
399
433
|
const extractTextItems = async (...args) => {
|
|
400
|
-
|
|
401
|
-
|
|
434
|
+
await resolvePDFJSImport();
|
|
435
|
+
return await extractTextItems$1(...args);
|
|
402
436
|
};
|
|
403
437
|
const extractImages = async (...args) => {
|
|
404
|
-
|
|
405
|
-
|
|
438
|
+
await resolvePDFJSImport();
|
|
439
|
+
return await extractImages$1(...args);
|
|
406
440
|
};
|
|
407
441
|
const renderPageAsImage = async (...args) => {
|
|
408
|
-
|
|
409
|
-
|
|
442
|
+
await resolvePDFJSImport();
|
|
443
|
+
return await renderPageAsImage$1(...args);
|
|
410
444
|
};
|
|
411
445
|
const extractLinks = async (...args) => {
|
|
412
|
-
|
|
413
|
-
|
|
446
|
+
await resolvePDFJSImport();
|
|
447
|
+
return await extractLinks$1(...args);
|
|
414
448
|
};
|
|
415
|
-
|
|
449
|
+
//#endregion
|
|
416
450
|
export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, extractTextItems, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
|