unpdf 0.12.1 → 1.0.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 +147 -79
- package/dist/index.cjs +135 -75
- package/dist/index.d.cts +46 -36
- package/dist/index.d.mts +46 -36
- package/dist/index.d.ts +46 -36
- package/dist/index.mjs +134 -74
- package/dist/pdfjs.mjs +1 -1
- package/dist/types/src/display/annotation_layer.d.ts +25 -1
- package/dist/types/src/display/annotation_storage.d.ts +1 -8
- package/dist/types/src/display/api.d.ts +147 -57
- package/dist/types/src/display/canvas.d.ts +21 -28
- package/dist/types/src/display/canvas_factory.d.ts +27 -0
- package/dist/types/src/display/cmap_reader_factory.d.ts +25 -0
- package/dist/types/src/display/display_utils.d.ts +40 -60
- package/dist/types/src/display/draw_layer.d.ts +7 -19
- package/dist/types/src/display/editor/alt_text.d.ts +3 -2
- package/dist/types/src/display/editor/annotation_editor_layer.d.ts +16 -11
- package/dist/types/src/display/editor/color_picker.d.ts +1 -0
- package/dist/types/src/display/editor/draw.d.ts +121 -0
- package/dist/types/src/display/editor/drawers/contour.d.ts +3 -0
- package/dist/types/src/display/editor/drawers/freedraw.d.ts +31 -0
- package/dist/types/src/display/editor/drawers/highlight.d.ts +36 -0
- package/dist/types/src/display/editor/drawers/inkdraw.d.ts +129 -0
- package/dist/types/src/display/editor/drawers/outline.d.ts +19 -0
- package/dist/types/src/display/editor/drawers/signaturedraw.d.ts +79 -0
- package/dist/types/src/display/editor/editor.d.ts +55 -13
- package/dist/types/src/display/editor/freetext.d.ts +5 -16
- package/dist/types/src/display/editor/highlight.d.ts +8 -25
- package/dist/types/src/display/editor/ink.d.ts +21 -74
- package/dist/types/src/display/editor/signature.d.ts +80 -0
- package/dist/types/src/display/editor/stamp.d.ts +16 -22
- package/dist/types/src/display/editor/toolbar.d.ts +5 -2
- package/dist/types/src/display/editor/tools.d.ts +17 -9
- package/dist/types/src/display/fetch_stream.d.ts +6 -13
- package/dist/types/src/display/filter_factory.d.ts +29 -0
- package/dist/types/src/display/font_loader.d.ts +3 -6
- package/dist/types/src/display/metadata.d.ts +1 -2
- package/dist/types/src/display/network.d.ts +11 -7
- package/dist/types/src/display/network_utils.d.ts +7 -6
- package/dist/types/src/display/node_stream.d.ts +6 -22
- package/dist/types/src/display/node_utils.d.ts +15 -11
- package/dist/types/src/display/optional_content_config.d.ts +2 -2
- package/dist/types/src/display/pattern_helper.d.ts +4 -2
- package/dist/types/src/display/standard_fontdata_factory.d.ts +20 -0
- package/dist/types/src/display/svg_factory.d.ts +14 -0
- package/dist/types/src/display/text_layer.d.ts +12 -9
- package/dist/types/src/display/touch_manager.d.ts +18 -0
- package/dist/types/src/display/transport_stream.d.ts +1 -1
- package/dist/types/src/display/wasm_factory.d.ts +20 -0
- package/dist/types/src/display/worker_options.d.ts +2 -2
- package/dist/types/src/interfaces.d.ts +4 -0
- package/dist/types/src/pdf.d.ts +13 -5
- package/dist/types/src/shared/message_handler.d.ts +9 -4
- package/dist/types/src/shared/util.d.ts +137 -129
- package/dist/types/web/annotation_editor_layer_builder.d.ts +20 -5
- package/dist/types/web/annotation_layer_builder.d.ts +35 -4
- package/dist/types/web/app_options.d.ts +1 -1
- package/dist/types/web/autolinker.d.ts +28 -0
- package/dist/types/web/base_pdf_page_view.d.ts +27 -0
- package/dist/types/web/draw_layer_builder.d.ts +13 -2
- package/dist/types/web/event_utils.d.ts +2 -2
- package/dist/types/web/genericl10n.d.ts +5 -5
- package/dist/types/web/interfaces.d.ts +5 -5
- package/dist/types/web/l10n.d.ts +2 -2
- package/dist/types/web/pdf_find_controller.d.ts +2 -0
- package/dist/types/web/pdf_link_service.d.ts +1 -2
- package/dist/types/web/pdf_page_detail_view.d.ts +32 -0
- package/dist/types/web/pdf_page_view.d.ts +44 -23
- package/dist/types/web/pdf_rendering_queue.d.ts +2 -1
- package/dist/types/web/pdf_thumbnail_view.d.ts +23 -3
- package/dist/types/web/pdf_thumbnail_viewer.d.ts +21 -1
- package/dist/types/web/pdf_viewer.d.ts +44 -16
- package/dist/types/web/struct_tree_layer_builder.d.ts +20 -2
- package/dist/types/web/text_accessibility.d.ts +1 -1
- package/dist/types/web/text_layer_builder.d.ts +25 -17
- package/dist/types/web/ui_utils.d.ts +3 -19
- package/dist/types/web/xfa_layer_builder.d.ts +14 -3
- package/package.json +31 -28
- package/dist/types/src/display/base_factory.d.ts +0 -60
- package/dist/types/src/display/editor/outliner.d.ts +0 -70
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# unpdf
|
|
2
2
|
|
|
3
|
-
A collection of utilities
|
|
3
|
+
A collection of utilities for working with PDF files. Designed specifically for Bun, Deno, and serverless environments. However, it also works in Node.js and the browser.
|
|
4
4
|
|
|
5
5
|
`unpdf` ships with a serverless build/redistribution of Mozilla's [PDF.js](https://github.com/mozilla/pdf.js) for serverless environments. Apart from some string replacements and mocks, [`unenv`](https://github.com/unjs/unenv) does the heavy lifting by converting Node.js specific code to be platform-agnostic. See [`pdfjs.rollup.config.ts`](./pdfjs.rollup.config.ts) for all the details.
|
|
6
6
|
|
|
@@ -8,15 +8,18 @@ This library is also intended as a modern alternative to the unmaintained but st
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- 🏗️
|
|
11
|
+
- 🏗️ Made for Node.js, browser and serverless environments
|
|
12
12
|
- 🪭 Includes serverless build of PDF.js ([`unpdf/pdfjs`](./package.json#L34))
|
|
13
|
-
- 💬 Extract text and images from
|
|
13
|
+
- 💬 Extract [text](#extract-text-from-pdf) and [images](#extractimages) from PDF files
|
|
14
14
|
- 🧱 Opt-in to legacy PDF.js build
|
|
15
15
|
- 💨 Zero dependencies
|
|
16
16
|
|
|
17
17
|
## PDF.js Compatibility
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
> [!Tip]
|
|
20
|
+
> The serverless PDF.js bundle provided by `unpdf` is built from PDF.js v5.2.133.
|
|
21
|
+
|
|
22
|
+
You can use an [official PDF.js build](#use-official-or-legacy-pdfjs-build) by using the [`definePDFJSModule`](#definepdfjsmodule) method. This is useful if you want to use a specific version or a custom build of PDF.js.
|
|
20
23
|
|
|
21
24
|
## Installation
|
|
22
25
|
|
|
@@ -24,13 +27,13 @@ Run the following command to add `unpdf` to your project.
|
|
|
24
27
|
|
|
25
28
|
```bash
|
|
26
29
|
# pnpm
|
|
27
|
-
pnpm add unpdf
|
|
30
|
+
pnpm add -D unpdf
|
|
28
31
|
|
|
29
32
|
# npm
|
|
30
|
-
npm install unpdf
|
|
33
|
+
npm install -D unpdf
|
|
31
34
|
|
|
32
35
|
# yarn
|
|
33
|
-
yarn add unpdf
|
|
36
|
+
yarn add -D unpdf
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
## Usage
|
|
@@ -40,32 +43,37 @@ yarn add unpdf
|
|
|
40
43
|
```ts
|
|
41
44
|
import { extractText, getDocumentProxy } from 'unpdf'
|
|
42
45
|
|
|
43
|
-
//
|
|
44
|
-
const buffer = await fetch(
|
|
45
|
-
|
|
46
|
-
).then(res => res.arrayBuffer())
|
|
47
|
-
|
|
48
|
-
// Or load it from the filesystem
|
|
46
|
+
// Either fetch a PDF file from the web or load it from the file system
|
|
47
|
+
const buffer = await fetch('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf')
|
|
48
|
+
.then(res => res.arrayBuffer())
|
|
49
49
|
const buffer = await readFile('./dummy.pdf')
|
|
50
50
|
|
|
51
|
-
//
|
|
51
|
+
// Then, load the PDF file into a PDF.js document
|
|
52
52
|
const pdf = await getDocumentProxy(new Uint8Array(buffer))
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
// Finally, extract the text from the PDF file
|
|
54
55
|
const { totalPages, text } = await extractText(pdf, { mergePages: true })
|
|
55
56
|
|
|
56
57
|
console.log(`Total pages: ${totalPages}`)
|
|
57
58
|
console.log(text)
|
|
58
59
|
```
|
|
59
60
|
|
|
60
|
-
###
|
|
61
|
+
### PDF.js API
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
`unpdf` provides helpful [methods](#api) to work with PDF files, such as `extractText` and `extractImages`, which should cover most use cases. However, if you need more control over the PDF.js API, you can use the `getResolvedPDFJS` method to get the resolved PDF.js module.
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
- `version`
|
|
66
|
-
- … and all other methods
|
|
65
|
+
Access the PDF.js API directly by calling `getResolvedPDFJS`:
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
```ts
|
|
68
|
+
import { getResolvedPDFJS } from 'unpdf'
|
|
69
|
+
|
|
70
|
+
const { version } = await getResolvedPDFJS()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> [!NOTE]
|
|
74
|
+
> If no other PDF.js build was defined, the serverless build will always be used.
|
|
75
|
+
|
|
76
|
+
For example, you can use the `getDocument` method to load a PDF file and then use the `getPage` method to get a specific page. You can also use the `getTextContent` method to extract the text from the page.
|
|
69
77
|
|
|
70
78
|
```ts
|
|
71
79
|
import { getResolvedPDFJS } from 'unpdf'
|
|
@@ -86,55 +94,40 @@ for (let i = 1; i <= doc.numPages; i++) {
|
|
|
86
94
|
|
|
87
95
|
### Use Official or Legacy PDF.js Build
|
|
88
96
|
|
|
89
|
-
|
|
97
|
+
Usually you don't need to worry about the PDF.js build. `unpdf` ships with a serverless build of the latest PDF.js version. However, if you want to use the official PDF.js version or the legacy build, you can define a custom PDF.js module.
|
|
90
98
|
|
|
91
99
|
> [!WARNING]
|
|
92
|
-
>
|
|
100
|
+
> Later PDF.js v4.x versions uses `Promise.withResolvers`, which may not be supported in all environments, such as Node < 22. Consider to use the bundled serverless build, which includes a polyfill, or use an older version of PDF.js.
|
|
101
|
+
|
|
102
|
+
For example, if you want to use the official PDF.js build, you can do the following:
|
|
93
103
|
|
|
94
104
|
```ts
|
|
95
|
-
|
|
96
|
-
// if you need another PDF.js build
|
|
97
|
-
import { configureUnPDF } from 'unpdf'
|
|
105
|
+
import { definePDFJSModule } from 'unpdf'
|
|
98
106
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
pdfjs: () => import('pdfjs-dist'),
|
|
102
|
-
})
|
|
107
|
+
// Define the PDF.js build before using any other unpdf method
|
|
108
|
+
await definePDFJSModule(() => import('pdfjs-dist'))
|
|
103
109
|
|
|
104
|
-
// Now, you can use the
|
|
105
|
-
|
|
110
|
+
// Now, you can use all unpdf methods with the official PDF.js build
|
|
111
|
+
const { text } = await extractText(pdf)
|
|
106
112
|
```
|
|
107
113
|
|
|
108
|
-
##
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
interface UnPDFConfiguration {
|
|
112
|
-
/**
|
|
113
|
-
* By default, UnPDF will use the latest version of PDF.js compiled for
|
|
114
|
-
* serverless environments. If you want to use a different version, you can
|
|
115
|
-
* provide a custom resolver function.
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* // Use the official PDF.js build (make sure to install it first)
|
|
119
|
-
* () => import('pdfjs-dist')
|
|
120
|
-
*/
|
|
121
|
-
pdfjs?: () => Promise<PDFJS>
|
|
122
|
-
}
|
|
123
|
-
```
|
|
114
|
+
## API
|
|
124
115
|
|
|
125
|
-
|
|
116
|
+
### `definePDFJSModule`
|
|
126
117
|
|
|
127
|
-
|
|
118
|
+
Allows to define a custom PDF.js build. This method should be called before using any other method. If no custom build is defined, the serverless build will be used.
|
|
128
119
|
|
|
129
|
-
|
|
120
|
+
**Type Declaration**
|
|
130
121
|
|
|
131
122
|
```ts
|
|
132
|
-
function
|
|
123
|
+
function definePDFJSModule(pdfjs: () => Promise<PDFJS>): Promise<void>
|
|
133
124
|
```
|
|
134
125
|
|
|
135
126
|
### `getResolvedPDFJS`
|
|
136
127
|
|
|
137
|
-
Returns the resolved PDF.js module. If no build
|
|
128
|
+
Returns the resolved PDF.js module. If no other PDF.js build was defined, the serverless build will be used. This method is useful if you want to use the PDF.js API directly.
|
|
129
|
+
|
|
130
|
+
**Type Declaration**
|
|
138
131
|
|
|
139
132
|
```ts
|
|
140
133
|
function getResolvedPDFJS(): Promise<PDFJS>
|
|
@@ -142,6 +135,8 @@ function getResolvedPDFJS(): Promise<PDFJS>
|
|
|
142
135
|
|
|
143
136
|
### `getMeta`
|
|
144
137
|
|
|
138
|
+
**Type Declaration**
|
|
139
|
+
|
|
145
140
|
```ts
|
|
146
141
|
function getMeta(
|
|
147
142
|
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
@@ -155,47 +150,109 @@ function getMeta(
|
|
|
155
150
|
|
|
156
151
|
Extracts all text from a PDF. If `mergePages` is set to `true`, the text of all pages will be merged into a single string. Otherwise, an array of strings for each page will be returned.
|
|
157
152
|
|
|
153
|
+
**Type Declaration**
|
|
154
|
+
|
|
158
155
|
```ts
|
|
159
156
|
function extractText(
|
|
160
157
|
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
161
|
-
|
|
158
|
+
options?: {
|
|
159
|
+
mergePages?: false
|
|
160
|
+
}
|
|
162
161
|
): Promise<{
|
|
163
162
|
totalPages: number
|
|
164
|
-
text: string
|
|
163
|
+
text: string[]
|
|
164
|
+
}>
|
|
165
|
+
function extractText(
|
|
166
|
+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
167
|
+
options: {
|
|
168
|
+
mergePages: true
|
|
169
|
+
}
|
|
170
|
+
): Promise<{
|
|
171
|
+
totalPages: number
|
|
172
|
+
text: string
|
|
165
173
|
}>
|
|
166
174
|
```
|
|
167
175
|
|
|
168
|
-
### `
|
|
176
|
+
### `extractImages`
|
|
177
|
+
|
|
178
|
+
Extracts images from a specific page of a PDF document, including necessary metadata such as width, height, and calculated color channels.
|
|
169
179
|
|
|
170
180
|
> [!NOTE]
|
|
171
181
|
> This method will only work in Node.js and browser environments.
|
|
172
182
|
|
|
173
|
-
|
|
183
|
+
In order to use this method, make sure to meet the following requirements:
|
|
174
184
|
|
|
175
|
-
|
|
185
|
+
- Use the official PDF.js build (see below for details).
|
|
186
|
+
- Install the [`@napi-rs/canvas`](https://github.com/Brooooooklyn/canvas) package if you are using Node.js. This package is required to render the PDF page as an image.
|
|
176
187
|
|
|
177
|
-
|
|
178
|
-
|
|
188
|
+
**Type Declaration**
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
interface ExtractedImageObject {
|
|
192
|
+
data: Uint8ClampedArray
|
|
193
|
+
width: number
|
|
194
|
+
height: number
|
|
195
|
+
channels: 1 | 3 | 4
|
|
196
|
+
key: string
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function extractImages(
|
|
200
|
+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
201
|
+
pageNumber: number,
|
|
202
|
+
): Promise<ExtractedImageObject[]>
|
|
203
|
+
```
|
|
179
204
|
|
|
180
205
|
**Example**
|
|
181
206
|
|
|
207
|
+
> [!NOTE]
|
|
208
|
+
> The following example uses the [sharp](https://github.com/lovell/sharp) library to process and save the extracted images. You will need to install it with your preferred package manager.
|
|
209
|
+
|
|
182
210
|
```ts
|
|
183
|
-
import {
|
|
211
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
212
|
+
import sharp from 'sharp'
|
|
213
|
+
import { extractImages, getDocumentProxy } from 'unpdf'
|
|
214
|
+
|
|
215
|
+
async function extractPdfImages() {
|
|
216
|
+
const buffer = await readFile('./document.pdf')
|
|
217
|
+
const pdf = await getDocumentProxy(new Uint8Array(buffer))
|
|
218
|
+
|
|
219
|
+
// Extract images from page 1
|
|
220
|
+
const imagesData = await extractImages(pdf, 1)
|
|
221
|
+
console.log(`Found ${imagesData.length} images on page 1`)
|
|
222
|
+
|
|
223
|
+
// Process each image with sharp (optional)
|
|
224
|
+
let totalImagesProcessed = 0
|
|
225
|
+
for (const imgData of imagesData) {
|
|
226
|
+
const imageIndex = ++totalImagesProcessed
|
|
227
|
+
|
|
228
|
+
await sharp(imgData.data, {
|
|
229
|
+
raw: {
|
|
230
|
+
width: imgData.width,
|
|
231
|
+
height: imgData.height,
|
|
232
|
+
channels: imgData.channels
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
.png()
|
|
236
|
+
.toFile(`image-${imageIndex}.png`)
|
|
237
|
+
|
|
238
|
+
console.log(`Saved image ${imageIndex} (${imgData.width}x${imgData.height}, ${imgData.channels} channels)`)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
184
241
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
pdfjs: () => import('pdfjs-dist'),
|
|
188
|
-
})
|
|
242
|
+
extractPdfImages().catch(console.error)
|
|
243
|
+
```
|
|
189
244
|
|
|
190
|
-
|
|
191
|
-
const buffer = new Uint8Array(pdf)
|
|
192
|
-
const pageNumber = 1
|
|
245
|
+
### `renderPageAsImage`
|
|
193
246
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
247
|
+
To render a PDF page as an image, you can use the `renderPageAsImage` method. This method will return an `ArrayBuffer` of the rendered image.
|
|
248
|
+
|
|
249
|
+
> [!NOTE]
|
|
250
|
+
> This method will only work in Node.js and browser environments.
|
|
251
|
+
|
|
252
|
+
In order to use this method, make sure to meet the following requirements:
|
|
253
|
+
|
|
254
|
+
- Use the official PDF.js build (see below for details).
|
|
255
|
+
- Install the [`@napi-rs/canvas`](https://github.com/Brooooooklyn/canvas) package if you are using Node.js. This package is required to render the PDF page as an image.
|
|
199
256
|
|
|
200
257
|
**Type Declaration**
|
|
201
258
|
|
|
@@ -204,8 +261,8 @@ declare function renderPageAsImage(
|
|
|
204
261
|
data: DocumentInitParameters['data'],
|
|
205
262
|
pageNumber: number,
|
|
206
263
|
options?: {
|
|
207
|
-
|
|
208
|
-
/** @default 1 */
|
|
264
|
+
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
|
|
265
|
+
/** @default 1.0 */
|
|
209
266
|
scale?: number
|
|
210
267
|
width?: number
|
|
211
268
|
height?: number
|
|
@@ -213,13 +270,24 @@ declare function renderPageAsImage(
|
|
|
213
270
|
): Promise<ArrayBuffer>
|
|
214
271
|
```
|
|
215
272
|
|
|
216
|
-
|
|
273
|
+
**Example**
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
|
|
217
277
|
|
|
218
|
-
|
|
278
|
+
// Use the official PDF.js build
|
|
279
|
+
await definePDFJSModule(() => import('pdfjs-dist'))
|
|
219
280
|
|
|
220
|
-
|
|
281
|
+
const pdf = await readFile('./dummy.pdf')
|
|
282
|
+
const buffer = new Uint8Array(pdf)
|
|
283
|
+
const pageNumber = 1
|
|
221
284
|
|
|
222
|
-
|
|
285
|
+
const result = await renderPageAsImage(buffer, pageNumber, {
|
|
286
|
+
canvasImport: () => import('@napi-rs/canvas'),
|
|
287
|
+
scale: 2,
|
|
288
|
+
})
|
|
289
|
+
await writeFile('dummy-page-1.png', new Uint8Array(result))
|
|
290
|
+
```
|
|
223
291
|
|
|
224
292
|
## License
|
|
225
293
|
|
package/dist/index.cjs
CHANGED
|
@@ -16,24 +16,21 @@ async function getDocumentProxy(data, options = {}) {
|
|
|
16
16
|
}
|
|
17
17
|
async function getResolvedPDFJS() {
|
|
18
18
|
if (!resolvedModule) {
|
|
19
|
-
await
|
|
19
|
+
await resolvePDFJSImport();
|
|
20
20
|
}
|
|
21
21
|
return resolvedModule;
|
|
22
22
|
}
|
|
23
|
-
async function
|
|
24
|
-
if (resolvedModule && !
|
|
23
|
+
async function resolvePDFJSImport(pdfjsResolver, { reload = false } = {}) {
|
|
24
|
+
if (resolvedModule && !reload) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
if (pdfjsResolver) {
|
|
28
28
|
try {
|
|
29
29
|
resolvedModule = await interopDefault(pdfjsResolver());
|
|
30
|
-
if (resolvedModule && "resolvePDFJS" in resolvedModule) {
|
|
31
|
-
resolvedModule = await resolvedModule.resolvePDFJS();
|
|
32
|
-
}
|
|
33
30
|
return;
|
|
34
31
|
} catch (error) {
|
|
35
32
|
console.error(error);
|
|
36
|
-
throw new Error("
|
|
33
|
+
throw new Error("PDF.js could not be resolved. Please check the resolver function.");
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
36
|
try {
|
|
@@ -41,7 +38,7 @@ async function resolvePDFJSImports(pdfjsResolver, { force = false } = {}) {
|
|
|
41
38
|
resolvedModule = await resolvePDFJS();
|
|
42
39
|
} catch (error) {
|
|
43
40
|
console.error(error);
|
|
44
|
-
throw new Error("PDF.js
|
|
41
|
+
throw new Error("PDF.js package not available. Please install it first.");
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
44
|
function isPDFDocumentProxy(data) {
|
|
@@ -52,12 +49,93 @@ async function interopDefault(m) {
|
|
|
52
49
|
return resolved.default || resolved;
|
|
53
50
|
}
|
|
54
51
|
|
|
52
|
+
let canvasModule;
|
|
53
|
+
/**
|
|
54
|
+
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
55
|
+
* @see https://github.com/mozilla/pdf.js/blob/b8de9a372f9bbf7e33adb362eeae5ef1919dba73/src/display/canvas_factory.js#L18
|
|
56
|
+
* @license Apache-2.0
|
|
57
|
+
*/
|
|
58
|
+
class BaseCanvasFactory {
|
|
59
|
+
#enableHWA = false;
|
|
60
|
+
constructor({ enableHWA = false } = {}) {
|
|
61
|
+
this.#enableHWA = enableHWA;
|
|
62
|
+
}
|
|
63
|
+
create(width, height) {
|
|
64
|
+
const canvas = this._createCanvas(width, height);
|
|
65
|
+
return {
|
|
66
|
+
canvas,
|
|
67
|
+
context: canvas.getContext("2d", {
|
|
68
|
+
willReadFrequently: !this.#enableHWA
|
|
69
|
+
})
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
reset({ canvas }, width, height) {
|
|
73
|
+
if (!canvas) {
|
|
74
|
+
throw new Error("Canvas is not specified");
|
|
75
|
+
}
|
|
76
|
+
canvas.width = width;
|
|
77
|
+
canvas.height = height;
|
|
78
|
+
}
|
|
79
|
+
destroy(context) {
|
|
80
|
+
if (!context.canvas) {
|
|
81
|
+
throw new Error("Canvas is not specified");
|
|
82
|
+
}
|
|
83
|
+
context.canvas.width = 0;
|
|
84
|
+
context.canvas.height = 0;
|
|
85
|
+
context.canvas = void 0;
|
|
86
|
+
context.context = void 0;
|
|
87
|
+
}
|
|
88
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
89
|
+
_createCanvas(width, height) {
|
|
90
|
+
throw new Error("Not implemented");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
95
|
+
* @see https://github.com/mozilla/pdf.js/blob/b8de9a372f9bbf7e33adb362eeae5ef1919dba73/src/display/canvas_factory.js#L18
|
|
96
|
+
* @license Apache-2.0
|
|
97
|
+
*/
|
|
98
|
+
class DOMCanvasFactory extends BaseCanvasFactory {
|
|
99
|
+
_document;
|
|
100
|
+
constructor({ ownerDocument = globalThis.document, enableHWA = false } = {}) {
|
|
101
|
+
super({ enableHWA });
|
|
102
|
+
this._document = ownerDocument;
|
|
103
|
+
}
|
|
104
|
+
_createCanvas(width, height) {
|
|
105
|
+
const canvas = this._document.createElement("canvas");
|
|
106
|
+
canvas.width = width;
|
|
107
|
+
canvas.height = height;
|
|
108
|
+
return canvas;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
class NodeCanvasFactory extends BaseCanvasFactory {
|
|
112
|
+
constructor({ enableHWA = false } = {}) {
|
|
113
|
+
super({ enableHWA });
|
|
114
|
+
}
|
|
115
|
+
_createCanvas(width, height) {
|
|
116
|
+
if (!canvasModule) {
|
|
117
|
+
throw new Error("@napi-rs/canvas module is not resolved");
|
|
118
|
+
}
|
|
119
|
+
return canvasModule.createCanvas(width, height);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function resolveCanvasModule(canvasImport) {
|
|
123
|
+
canvasModule ??= await interopDefault(canvasImport());
|
|
124
|
+
}
|
|
125
|
+
function injectCanvasConstructors() {
|
|
126
|
+
if (!canvasModule)
|
|
127
|
+
return;
|
|
128
|
+
globalThis.DOMMatrix ??= canvasModule.DOMMatrix;
|
|
129
|
+
globalThis.ImageData ??= canvasModule.ImageData;
|
|
130
|
+
globalThis.Path2D ??= canvasModule.Path2D;
|
|
131
|
+
}
|
|
132
|
+
|
|
55
133
|
async function extractImages$1(data, pageNumber) {
|
|
56
134
|
const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
|
|
57
|
-
const page = await pdf.getPage(pageNumber);
|
|
58
135
|
if (pageNumber < 1 || pageNumber > pdf.numPages) {
|
|
59
136
|
throw new Error(`Invalid page number. Must be between 1 and ${pdf.numPages}.`);
|
|
60
137
|
}
|
|
138
|
+
const page = await pdf.getPage(pageNumber);
|
|
61
139
|
const operatorList = await page.getOperatorList();
|
|
62
140
|
const { OPS } = await getResolvedPDFJS();
|
|
63
141
|
const images = [];
|
|
@@ -68,79 +146,61 @@ async function extractImages$1(data, pageNumber) {
|
|
|
68
146
|
}
|
|
69
147
|
const imageKey = operatorList.argsArray[i][0];
|
|
70
148
|
const image = await page.objs.get(imageKey);
|
|
71
|
-
|
|
149
|
+
if (!image || !image.data || !image.width || !image.height) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const { width, height, data: data2 } = image;
|
|
153
|
+
const calculatedChannels = data2.length / (width * height);
|
|
154
|
+
if (![1, 3, 4].includes(calculatedChannels)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const channels = calculatedChannels;
|
|
158
|
+
images.push({
|
|
159
|
+
data: data2,
|
|
160
|
+
width,
|
|
161
|
+
height,
|
|
162
|
+
channels,
|
|
163
|
+
key: imageKey
|
|
164
|
+
});
|
|
72
165
|
}
|
|
73
166
|
return images;
|
|
74
167
|
}
|
|
75
168
|
async function renderPageAsImage$1(data, pageNumber, options = {}) {
|
|
76
|
-
const
|
|
77
|
-
const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data, {
|
|
169
|
+
const CanvasFactory = await createIsomorphicCanvasFactory(options.canvasImport);
|
|
170
|
+
const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data, { CanvasFactory });
|
|
78
171
|
const page = await pdf.getPage(pageNumber);
|
|
79
172
|
if (pageNumber < 1 || pageNumber > pdf.numPages) {
|
|
80
173
|
throw new Error(`Invalid page number. Must be between 1 and ${pdf.numPages}.`);
|
|
81
174
|
}
|
|
82
|
-
|
|
83
|
-
let
|
|
175
|
+
const defaultViewport = page.getViewport({ scale: 1 });
|
|
176
|
+
let scale = options.scale || 1;
|
|
84
177
|
if (options.width) {
|
|
85
|
-
|
|
178
|
+
scale = options.width / defaultViewport.width;
|
|
86
179
|
} else if (options.height) {
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
if (outputScale !== 1 && outputScale > 0) {
|
|
90
|
-
viewport = page.getViewport({ scale: outputScale });
|
|
180
|
+
scale = options.height / defaultViewport.height;
|
|
91
181
|
}
|
|
92
|
-
const
|
|
182
|
+
const viewport = page.getViewport({ scale: Math.max(0, scale) });
|
|
183
|
+
const drawingContext = new CanvasFactory().create(viewport.width, viewport.height);
|
|
93
184
|
await page.render({
|
|
94
|
-
canvasContext:
|
|
185
|
+
canvasContext: drawingContext.context,
|
|
95
186
|
viewport
|
|
96
187
|
}).promise;
|
|
97
|
-
const dataUrl =
|
|
188
|
+
const dataUrl = drawingContext.canvas.toDataURL();
|
|
98
189
|
const response = await fetch(dataUrl);
|
|
99
190
|
return await response.arrayBuffer();
|
|
100
191
|
}
|
|
101
|
-
async function createIsomorphicCanvasFactory(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
canvas2.width = width;
|
|
108
|
-
canvas2.height = height;
|
|
109
|
-
return canvas2;
|
|
110
|
-
}
|
|
111
|
-
if (isNode) {
|
|
112
|
-
if (!_canvas) {
|
|
113
|
-
throw new Error('Failed to resolve "canvas" package.');
|
|
114
|
-
}
|
|
115
|
-
return _canvas.createCanvas(width, height);
|
|
116
|
-
}
|
|
117
|
-
throw new Error("Unsupported environment for canvas creation.");
|
|
118
|
-
},
|
|
119
|
-
create(width, height) {
|
|
120
|
-
const _canvas2 = this._createCanvas(width, height);
|
|
121
|
-
const context = _canvas2.getContext(
|
|
122
|
-
"2d"
|
|
123
|
-
);
|
|
124
|
-
return {
|
|
125
|
-
canvas: _canvas2,
|
|
126
|
-
context
|
|
127
|
-
};
|
|
128
|
-
},
|
|
129
|
-
reset(ctx, width, height) {
|
|
130
|
-
if (ctx.canvas) {
|
|
131
|
-
ctx.canvas.width = width;
|
|
132
|
-
ctx.canvas.height = height;
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
destroy(ctx) {
|
|
136
|
-
if (ctx.canvas) {
|
|
137
|
-
ctx.canvas.width = 0;
|
|
138
|
-
ctx.canvas.height = 0;
|
|
139
|
-
}
|
|
140
|
-
ctx.canvas = void 0;
|
|
141
|
-
ctx.context = void 0;
|
|
192
|
+
async function createIsomorphicCanvasFactory(canvasImport) {
|
|
193
|
+
if (isBrowser)
|
|
194
|
+
return DOMCanvasFactory;
|
|
195
|
+
if (isNode) {
|
|
196
|
+
if (!canvasImport) {
|
|
197
|
+
throw new Error('Parameter "canvasImport" is required in Node.js environment.');
|
|
142
198
|
}
|
|
143
|
-
|
|
199
|
+
await resolveCanvasModule(canvasImport);
|
|
200
|
+
injectCanvasConstructors();
|
|
201
|
+
return NodeCanvasFactory;
|
|
202
|
+
}
|
|
203
|
+
throw new Error("Unsupported environment for canvas creation.");
|
|
144
204
|
}
|
|
145
205
|
|
|
146
206
|
async function getMeta$1(data) {
|
|
@@ -153,7 +213,7 @@ async function getMeta$1(data) {
|
|
|
153
213
|
}
|
|
154
214
|
|
|
155
215
|
async function extractText$1(data, options = {}) {
|
|
156
|
-
const { mergePages = false } =
|
|
216
|
+
const { mergePages = false } = options;
|
|
157
217
|
const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
|
|
158
218
|
const texts = await Promise.all(
|
|
159
219
|
Array.from({ length: pdf.numPages }, (_, i) => getPageText(pdf, i + 1))
|
|
@@ -169,36 +229,36 @@ async function getPageText(document, pageNumber) {
|
|
|
169
229
|
return content.items.filter((item) => item.str != null).map((item) => item.str + (item.hasEOL ? "\n" : "")).join("");
|
|
170
230
|
}
|
|
171
231
|
|
|
232
|
+
async function definePDFJSModule(pdfjs) {
|
|
233
|
+
await resolvePDFJSImport(pdfjs, { reload: true });
|
|
234
|
+
}
|
|
172
235
|
async function configureUnPDF(options) {
|
|
173
|
-
|
|
174
|
-
if (pdfjs) {
|
|
175
|
-
await resolvePDFJSImports(pdfjs, { force: true });
|
|
176
|
-
}
|
|
236
|
+
await resolvePDFJSImport(options.pdfjs, { reload: true });
|
|
177
237
|
}
|
|
178
238
|
|
|
179
239
|
const getMeta = async (...args) => {
|
|
180
|
-
await
|
|
240
|
+
await resolvePDFJSImport();
|
|
181
241
|
return await getMeta$1(...args);
|
|
182
242
|
};
|
|
183
243
|
const extractText = async (...args) => {
|
|
184
|
-
await
|
|
244
|
+
await resolvePDFJSImport();
|
|
185
245
|
return await extractText$1(...args);
|
|
186
246
|
};
|
|
187
247
|
const extractImages = async (...args) => {
|
|
188
|
-
await
|
|
248
|
+
await resolvePDFJSImport();
|
|
189
249
|
return await extractImages$1(...args);
|
|
190
250
|
};
|
|
191
251
|
const renderPageAsImage = async (...args) => {
|
|
192
|
-
await
|
|
252
|
+
await resolvePDFJSImport();
|
|
193
253
|
return await renderPageAsImage$1(...args);
|
|
194
254
|
};
|
|
195
255
|
|
|
196
256
|
exports.configureUnPDF = configureUnPDF;
|
|
197
|
-
exports.
|
|
257
|
+
exports.definePDFJSModule = definePDFJSModule;
|
|
198
258
|
exports.extractImages = extractImages;
|
|
199
259
|
exports.extractText = extractText;
|
|
200
260
|
exports.getDocumentProxy = getDocumentProxy;
|
|
201
261
|
exports.getMeta = getMeta;
|
|
202
262
|
exports.getResolvedPDFJS = getResolvedPDFJS;
|
|
203
263
|
exports.renderPageAsImage = renderPageAsImage;
|
|
204
|
-
exports.
|
|
264
|
+
exports.resolvePDFJSImport = resolvePDFJSImport;
|