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