unpdf 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -144
- package/dist/index.cjs +17 -30
- package/dist/index.d.cts +7 -19
- package/dist/index.d.mts +7 -19
- package/dist/index.mjs +17 -30
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# unpdf
|
|
2
2
|
|
|
3
|
-
Utilities for PDF extraction and rendering across all JavaScript runtimes – Node.js,
|
|
3
|
+
Utilities for PDF extraction and rendering across all JavaScript runtimes – Node.js, Bun, the browser, and serverless environments like Cloudflare Workers. Especially useful for AI applications that need to summarize or analyze PDF documents.
|
|
4
4
|
|
|
5
5
|
Ships with a serverless build of Mozilla's [PDF.js](https://github.com/mozilla/pdf.js), optimized for edge environments. If you're coming from [`pdf-parse`](https://www.npmjs.com/package/pdf-parse), `unpdf` is a modern, actively maintained alternative with broader runtime support.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🏗️ Works in Node.js,
|
|
10
|
-
- 🪭 Includes serverless build of PDF.js ([`unpdf/pdfjs`](
|
|
11
|
-
- 💬 Extract [text](#
|
|
9
|
+
- 🏗️ Works in Node.js 22+, Bun, browsers, and serverless environments ([Cloudflare Workers example](./examples/cloudflare))
|
|
10
|
+
- 🪭 Includes serverless build of PDF.js ([`unpdf/pdfjs`](#how-it-works))
|
|
11
|
+
- 💬 Extract [text](#extracttext), [positioned text](#extracttextitems), [links](#extractlinks), [images](#extractimages), and [metadata](#getmeta) from PDF files
|
|
12
|
+
- 🖼️ [Render pages as images](#renderpageasimage)
|
|
12
13
|
- 🧠 Perfect for AI applications and PDF summarization
|
|
13
|
-
- 🧱 Opt-in to
|
|
14
|
+
- 🧱 Opt-in to a [custom PDF.js build](#custom-pdfjs-build)
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -24,8 +25,6 @@ npm install unpdf
|
|
|
24
25
|
|
|
25
26
|
## Usage
|
|
26
27
|
|
|
27
|
-
### Extract Text From PDF
|
|
28
|
-
|
|
29
28
|
```ts
|
|
30
29
|
import { extractText, getDocumentProxy } from 'unpdf'
|
|
31
30
|
|
|
@@ -40,54 +39,6 @@ console.log(`Total pages: ${totalPages}`)
|
|
|
40
39
|
console.log(text)
|
|
41
40
|
```
|
|
42
41
|
|
|
43
|
-
### Official or Legacy PDF.js Build
|
|
44
|
-
|
|
45
|
-
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.
|
|
46
|
-
|
|
47
|
-
> [!WARNING]
|
|
48
|
-
> PDF.js v5.x uses `Promise.withResolvers`, which may not be supported in all environments, such as Node < 22. Consider using the bundled serverless build, which includes a polyfill, or use an older version of PDF.js.
|
|
49
|
-
|
|
50
|
-
For example, if you want to use the official PDF.js build:
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
import { definePDFJSModule, extractText, getDocumentProxy } from 'unpdf'
|
|
54
|
-
|
|
55
|
-
// Define the PDF.js build before using any other unpdf method
|
|
56
|
-
await definePDFJSModule(() => import('pdfjs-dist'))
|
|
57
|
-
|
|
58
|
-
// Now, you can use all unpdf methods with the official PDF.js build
|
|
59
|
-
const pdf = await getDocumentProxy(/* … */)
|
|
60
|
-
const { text } = await extractText(pdf)
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### PDF.js API
|
|
64
|
-
|
|
65
|
-
`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.
|
|
66
|
-
|
|
67
|
-
Access the PDF.js API directly by calling `getResolvedPDFJS`:
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
import { getResolvedPDFJS } from 'unpdf'
|
|
71
|
-
|
|
72
|
-
const { version } = await getResolvedPDFJS()
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
> [!NOTE]
|
|
76
|
-
> If no other PDF.js build was defined, the serverless build will always be used.
|
|
77
|
-
|
|
78
|
-
For example, you can use the `getDocument` method to load a PDF file and then use the `getMetadata` method to get the metadata of the PDF file:
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
import { readFile } from 'node:fs/promises'
|
|
82
|
-
import { getResolvedPDFJS } from 'unpdf'
|
|
83
|
-
|
|
84
|
-
const { getDocument } = await getResolvedPDFJS()
|
|
85
|
-
const data = await readFile('./dummy.pdf')
|
|
86
|
-
const document = await getDocument(new Uint8Array(data)).promise
|
|
87
|
-
|
|
88
|
-
console.log(await document.getMetadata())
|
|
89
|
-
```
|
|
90
|
-
|
|
91
42
|
## How It Works
|
|
92
43
|
|
|
93
44
|
> [!NOTE]
|
|
@@ -97,13 +48,13 @@ Heart and soul of this package is the [`pdfjs.rolldown.config.ts`](./pdfjs.rolld
|
|
|
97
48
|
|
|
98
49
|
- **String replacements** strip browser-specific references from the PDF.js source.
|
|
99
50
|
- **Worker inlining** embeds the PDF.js worker directly into the main bundle, since serverless runtimes can't load separate worker files.
|
|
100
|
-
- **Global polyfills**
|
|
51
|
+
- **Global polyfills** fill in newer APIs like `Promise.try` and `Map.prototype.getOrInsert` for runtimes that lack them, plus `FinalizationRegistry` for Cloudflare Workers.
|
|
101
52
|
|
|
102
53
|
## API
|
|
103
54
|
|
|
104
55
|
### `definePDFJSModule`
|
|
105
56
|
|
|
106
|
-
|
|
57
|
+
Sets the PDF.js build every other method uses – call it before any of them. See [Custom PDF.js Build](#custom-pdfjs-build).
|
|
107
58
|
|
|
108
59
|
**Type Declaration**
|
|
109
60
|
|
|
@@ -113,7 +64,7 @@ function definePDFJSModule(pdfjs: () => Promise<PDFJS>): Promise<void>
|
|
|
113
64
|
|
|
114
65
|
### `getResolvedPDFJS`
|
|
115
66
|
|
|
116
|
-
Returns the resolved PDF.js module
|
|
67
|
+
Returns the resolved PDF.js module – the serverless build, unless `definePDFJSModule` set another. Use it to call the PDF.js API directly.
|
|
117
68
|
|
|
118
69
|
**Type Declaration**
|
|
119
70
|
|
|
@@ -121,11 +72,19 @@ Returns the resolved PDF.js module. If no other PDF.js build was defined, the se
|
|
|
121
72
|
function getResolvedPDFJS(): Promise<PDFJS>
|
|
122
73
|
```
|
|
123
74
|
|
|
75
|
+
**Example**
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { getResolvedPDFJS } from 'unpdf'
|
|
79
|
+
|
|
80
|
+
const { version } = await getResolvedPDFJS()
|
|
81
|
+
```
|
|
82
|
+
|
|
124
83
|
### `getDocumentProxy`
|
|
125
84
|
|
|
126
85
|
Creates a `PDFDocumentProxy` from binary PDF data. Every extraction method accepts either raw data or an existing proxy – use this when you want to reuse one document across multiple calls.
|
|
127
86
|
|
|
128
|
-
Applies sensible defaults: `useSystemFonts: true`; in Node.js additionally `disableFontFace: true`, plus `standardFontDataUrl` and `cMapUrl`/`cMapPacked` resolved from the local `pdfjs-dist` package for standard font and CJK character map support
|
|
87
|
+
Applies sensible defaults: `useSystemFonts: true`; in Node.js additionally `disableFontFace: true`, plus `standardFontDataUrl` and `cMapUrl`/`cMapPacked` resolved from the local `pdfjs-dist` package for standard font and CJK character map support. Without `pdfjs-dist` installed, the Node.js defaults are skipped.
|
|
129
88
|
|
|
130
89
|
**Type Declaration**
|
|
131
90
|
|
|
@@ -136,6 +95,17 @@ function getDocumentProxy(
|
|
|
136
95
|
): Promise<PDFDocumentProxy>
|
|
137
96
|
```
|
|
138
97
|
|
|
98
|
+
**Example**
|
|
99
|
+
|
|
100
|
+
Your options override the defaults:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const pdf = await getDocumentProxy(buffer, {
|
|
104
|
+
disableFontFace: false,
|
|
105
|
+
standardFontDataUrl: 'https://unpkg.com/pdfjs-dist@latest/standard_fonts/',
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
139
109
|
### `getMeta`
|
|
140
110
|
|
|
141
111
|
Extracts metadata from a PDF. If `parseDates` is set to `true`, the date properties will be parsed into `Date` objects.
|
|
@@ -238,7 +208,7 @@ for (const link of links) console.log(link)
|
|
|
238
208
|
|
|
239
209
|
### `extractImages`
|
|
240
210
|
|
|
241
|
-
Extracts images from a specific page of a PDF document, including necessary metadata such as width, height, and calculated color channels.
|
|
211
|
+
Extracts images from a specific page of a PDF document, including necessary metadata such as width, height, and calculated color channels.
|
|
242
212
|
|
|
243
213
|
**Type Declaration**
|
|
244
214
|
|
|
@@ -259,65 +229,31 @@ function extractImages(
|
|
|
259
229
|
|
|
260
230
|
**Example**
|
|
261
231
|
|
|
262
|
-
|
|
263
|
-
> 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.
|
|
232
|
+
Saves each image as PNG with [sharp](https://github.com/lovell/sharp), installed separately:
|
|
264
233
|
|
|
265
234
|
```ts
|
|
266
|
-
import { readFile
|
|
235
|
+
import { readFile } from 'node:fs/promises'
|
|
267
236
|
import sharp from 'sharp'
|
|
268
237
|
import { extractImages, getDocumentProxy } from 'unpdf'
|
|
269
238
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
for (const imgData of imagesData) {
|
|
281
|
-
const imageIndex = ++totalImagesProcessed
|
|
282
|
-
|
|
283
|
-
await sharp(imgData.data, {
|
|
284
|
-
raw: {
|
|
285
|
-
width: imgData.width,
|
|
286
|
-
height: imgData.height,
|
|
287
|
-
channels: imgData.channels
|
|
288
|
-
}
|
|
289
|
-
})
|
|
290
|
-
.png()
|
|
291
|
-
.toFile(`image-${imageIndex}.png`)
|
|
292
|
-
|
|
293
|
-
console.log(`Saved image ${imageIndex} (${imgData.width}x${imgData.height}, ${imgData.channels} channels)`)
|
|
294
|
-
}
|
|
239
|
+
const buffer = await readFile('./document.pdf')
|
|
240
|
+
const pdf = await getDocumentProxy(new Uint8Array(buffer))
|
|
241
|
+
const images = await extractImages(pdf, 1)
|
|
242
|
+
|
|
243
|
+
for (const [index, image] of images.entries()) {
|
|
244
|
+
await sharp(image.data, {
|
|
245
|
+
raw: { width: image.width, height: image.height, channels: image.channels },
|
|
246
|
+
})
|
|
247
|
+
.png()
|
|
248
|
+
.toFile(`image-${index + 1}.png`)
|
|
295
249
|
}
|
|
296
|
-
|
|
297
|
-
extractPdfImages().catch(console.error)
|
|
298
250
|
```
|
|
299
251
|
|
|
300
252
|
### `renderPageAsImage`
|
|
301
253
|
|
|
302
|
-
|
|
254
|
+
Renders a PDF page as PNG and returns its bytes as an `ArrayBuffer`, or a data URL (`string`) with `toDataURL: true`.
|
|
303
255
|
|
|
304
|
-
|
|
305
|
-
> This method will only work in Node.js and browser environments.
|
|
306
|
-
|
|
307
|
-
In order to use this method, make sure to meet the following requirements:
|
|
308
|
-
|
|
309
|
-
- Use the official PDF.js build (see [Official or Legacy PDF.js Build](#official-or-legacy-pdfjs-build)).
|
|
310
|
-
- 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.
|
|
311
|
-
|
|
312
|
-
> [!TIP]
|
|
313
|
-
> In Node.js, `getDocumentProxy` automatically sets `disableFontFace: true` and resolves `standardFontDataUrl` from your local `pdfjs-dist` package for correct font rendering. To customize this behavior, pass your own options:
|
|
314
|
-
>
|
|
315
|
-
> ```ts
|
|
316
|
-
> const pdf = await getDocumentProxy(buffer, {
|
|
317
|
-
> disableFontFace: false,
|
|
318
|
-
> standardFontDataUrl: 'https://unpkg.com/pdfjs-dist@latest/standard_fonts/',
|
|
319
|
-
> })
|
|
320
|
-
> ```
|
|
256
|
+
Rendering needs a canvas: browsers bring their own, while Node.js and Bun need the [`@napi-rs/canvas`](https://github.com/Brooooooklyn/canvas) package, passed as `canvasImport`. Serverless runtimes like Cloudflare Workers have neither.
|
|
321
257
|
|
|
322
258
|
**Type Declaration**
|
|
323
259
|
|
|
@@ -336,57 +272,36 @@ function renderPageAsImage(
|
|
|
336
272
|
): Promise<ArrayBuffer | string>
|
|
337
273
|
```
|
|
338
274
|
|
|
339
|
-
**
|
|
275
|
+
**Example**
|
|
340
276
|
|
|
341
277
|
```ts
|
|
342
278
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
343
|
-
import {
|
|
279
|
+
import { renderPageAsImage } from 'unpdf'
|
|
344
280
|
|
|
345
|
-
|
|
346
|
-
await
|
|
347
|
-
|
|
348
|
-
const pdf = await readFile('./dummy.pdf')
|
|
349
|
-
const buffer = new Uint8Array(pdf)
|
|
350
|
-
const pageNumber = 1
|
|
351
|
-
|
|
352
|
-
const result = await renderPageAsImage(buffer, pageNumber, {
|
|
281
|
+
const buffer = await readFile('./dummy.pdf')
|
|
282
|
+
const image = await renderPageAsImage(new Uint8Array(buffer), 1, {
|
|
353
283
|
canvasImport: () => import('@napi-rs/canvas'),
|
|
354
284
|
scale: 2,
|
|
355
285
|
})
|
|
356
|
-
|
|
286
|
+
|
|
287
|
+
await writeFile('dummy-page-1.png', new Uint8Array(image))
|
|
357
288
|
```
|
|
358
289
|
|
|
359
|
-
|
|
360
|
-
import { readFile, writeFile } from 'node:fs/promises'
|
|
361
|
-
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
|
|
290
|
+
## Custom PDF.js Build
|
|
362
291
|
|
|
363
|
-
|
|
292
|
+
`unpdf` uses its serverless build unless you define another one, e.g. to pin a different PDF.js version. Install `pdfjs-dist` and call `definePDFJSModule` before any other method:
|
|
364
293
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const pageNumber = 1
|
|
294
|
+
```ts
|
|
295
|
+
import { definePDFJSModule, extractText, getDocumentProxy } from 'unpdf'
|
|
368
296
|
|
|
369
|
-
|
|
370
|
-
canvasImport: () => import('@napi-rs/canvas'),
|
|
371
|
-
scale: 2,
|
|
372
|
-
toDataURL: true,
|
|
373
|
-
})
|
|
297
|
+
await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))
|
|
374
298
|
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
<head>
|
|
378
|
-
<meta charset="UTF-8">
|
|
379
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
380
|
-
<title>Dummy Page</title>
|
|
381
|
-
</head>
|
|
382
|
-
<body>
|
|
383
|
-
<img alt="Example Page" src="${result}">
|
|
384
|
-
</body>
|
|
385
|
-
</html>`
|
|
386
|
-
|
|
387
|
-
await writeFile('dummy-page-1.html', html)
|
|
299
|
+
const pdf = await getDocumentProxy(/* … */)
|
|
300
|
+
const { text } = await extractText(pdf)
|
|
388
301
|
```
|
|
389
302
|
|
|
303
|
+
In Node.js, import the legacy build as shown. The default `pdfjs-dist` entry targets current browsers – it fails on Node.js 24 and older and warns on newer versions.
|
|
304
|
+
|
|
390
305
|
## Processing Untrusted PDFs
|
|
391
306
|
|
|
392
307
|
PDF.js does not execute scripts embedded in PDFs, but resource limits are your job:
|
package/dist/index.cjs
CHANGED
|
@@ -53,7 +53,7 @@ let resolvedModule;
|
|
|
53
53
|
const isNode = globalThis.process?.release?.name === "node";
|
|
54
54
|
const isBrowser = typeof window !== "undefined";
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
56
|
+
* Creates a `PDFDocumentProxy` from binary PDF data.
|
|
57
57
|
*
|
|
58
58
|
* Applies the following defaults:
|
|
59
59
|
* - `useSystemFonts: true`
|
|
@@ -209,18 +209,6 @@ function injectCanvasConstructors() {
|
|
|
209
209
|
/**
|
|
210
210
|
* Extracts images from a specific page of a PDF document, including necessary metadata,
|
|
211
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
212
|
*/
|
|
225
213
|
async function extractImages$1(data, pageNumber) {
|
|
226
214
|
return await withDocument(data, async (pdf) => {
|
|
@@ -327,23 +315,23 @@ const XMP_DATE_PROPERTIES = [
|
|
|
327
315
|
async function getMeta$1(data, options = {}) {
|
|
328
316
|
return await withDocument(data, async (pdf) => {
|
|
329
317
|
const meta = await pdf.getMetadata();
|
|
330
|
-
const info = meta
|
|
318
|
+
const info = { ...meta.info };
|
|
319
|
+
let metadata = meta.metadata;
|
|
331
320
|
if (options.parseDates) {
|
|
332
321
|
const { PDFDateString } = await getResolvedPDFJS();
|
|
333
|
-
if (info
|
|
334
|
-
if (info
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
} });
|
|
322
|
+
if (info.CreationDate) info.CreationDate = PDFDateString.toDateObject(info.CreationDate);
|
|
323
|
+
if (info.ModDate) info.ModDate = PDFDateString.toDateObject(info.ModDate);
|
|
324
|
+
if (metadata) {
|
|
325
|
+
const Metadata = metadata.constructor;
|
|
326
|
+
metadata = new Metadata({
|
|
327
|
+
parsedData: new Map(Array.from(metadata, ([name, value]) => [name, XMP_DATE_PROPERTIES.includes(name) && value ? parseISODateString(value) : value])),
|
|
328
|
+
rawData: metadata.getRaw()
|
|
329
|
+
});
|
|
330
|
+
}
|
|
343
331
|
}
|
|
344
332
|
return {
|
|
345
333
|
info,
|
|
346
|
-
metadata:
|
|
334
|
+
metadata: metadata || {}
|
|
347
335
|
};
|
|
348
336
|
});
|
|
349
337
|
}
|
|
@@ -404,15 +392,14 @@ function normalizeMergedText(texts) {
|
|
|
404
392
|
//#endregion
|
|
405
393
|
//#region src/config.ts
|
|
406
394
|
/**
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
* provide a custom resolver function.
|
|
395
|
+
* Sets the PDF.js build every other method uses – call it before any of them.
|
|
396
|
+
* Without it, the serverless build is used.
|
|
410
397
|
*
|
|
411
398
|
* @example
|
|
412
|
-
* //
|
|
399
|
+
* // In Node.js, the legacy build of `pdfjs-dist` (install it first)
|
|
413
400
|
* import { definePDFJSModule } from 'unpdf'
|
|
414
401
|
*
|
|
415
|
-
* await definePDFJSModule(() => import('pdfjs-dist'))
|
|
402
|
+
* await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))
|
|
416
403
|
*/
|
|
417
404
|
async function definePDFJSModule(pdfjs) {
|
|
418
405
|
await resolvePDFJSImport(pdfjs, { reload: true });
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DocumentInitParameters, PDFDocumentProxy } from "./types/src/display/api.js";
|
|
2
2
|
import { Canvas, SKRSContext2D } from "@napi-rs/canvas";
|
|
3
|
+
import { Metadata } from "./types/src/display/metadata.js";
|
|
3
4
|
import * as PDFJS from "./types/src/pdf.js";
|
|
4
5
|
//#region src/_internal/canvas.d.ts
|
|
5
6
|
interface CanvasFactoryContext {
|
|
@@ -55,18 +56,6 @@ interface ExtractedImageObject {
|
|
|
55
56
|
/**
|
|
56
57
|
* Extracts images from a specific page of a PDF document, including necessary metadata,
|
|
57
58
|
* such as width, height, and calculated color channels.
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* const imagesData = await extractImages(pdf, pageNum)
|
|
61
|
-
*
|
|
62
|
-
* for (const imgData of imagesData) {
|
|
63
|
-
* const imageIndex = totalImagesProcessed + 1
|
|
64
|
-
* await sharp(imgData.data, {
|
|
65
|
-
* raw: { width: imgData.width, height: imgData.height, channels: imgData.channels }
|
|
66
|
-
* })
|
|
67
|
-
* .png()
|
|
68
|
-
* .toFile(`${imageIndex}.png`)
|
|
69
|
-
* }
|
|
70
59
|
*/
|
|
71
60
|
declare function extractImages$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, pageNumber: number): Promise<ExtractedImageObject[]>;
|
|
72
61
|
declare function renderPageAsImage$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, pageNumber: number, options?: {
|
|
@@ -98,7 +87,7 @@ declare function getMeta$1(data: DocumentInitParameters['data'] | PDFDocumentPro
|
|
|
98
87
|
parseDates?: boolean;
|
|
99
88
|
}): Promise<{
|
|
100
89
|
info: Record<string, any>;
|
|
101
|
-
metadata:
|
|
90
|
+
metadata: Metadata;
|
|
102
91
|
}>;
|
|
103
92
|
//#endregion
|
|
104
93
|
//#region src/text.d.ts
|
|
@@ -147,15 +136,14 @@ declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumen
|
|
|
147
136
|
//#endregion
|
|
148
137
|
//#region src/config.d.ts
|
|
149
138
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* provide a custom resolver function.
|
|
139
|
+
* Sets the PDF.js build every other method uses – call it before any of them.
|
|
140
|
+
* Without it, the serverless build is used.
|
|
153
141
|
*
|
|
154
142
|
* @example
|
|
155
|
-
* //
|
|
143
|
+
* // In Node.js, the legacy build of `pdfjs-dist` (install it first)
|
|
156
144
|
* import { definePDFJSModule } from 'unpdf'
|
|
157
145
|
*
|
|
158
|
-
* await definePDFJSModule(() => import('pdfjs-dist'))
|
|
146
|
+
* await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))
|
|
159
147
|
*/
|
|
160
148
|
export declare function definePDFJSModule(pdfjs: () => Promise<any>): Promise<void>;
|
|
161
149
|
/** @deprecated Use `definePDFJSModule` instead. Will be removed in v2. */
|
|
@@ -165,7 +153,7 @@ export declare function configureUnPDF(options: {
|
|
|
165
153
|
//#endregion
|
|
166
154
|
//#region src/utils.d.ts
|
|
167
155
|
/**
|
|
168
|
-
*
|
|
156
|
+
* Creates a `PDFDocumentProxy` from binary PDF data.
|
|
169
157
|
*
|
|
170
158
|
* Applies the following defaults:
|
|
171
159
|
* - `useSystemFonts: true`
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DocumentInitParameters, PDFDocumentProxy } from "./types/src/display/api.js";
|
|
2
2
|
import { Canvas, SKRSContext2D } from "@napi-rs/canvas";
|
|
3
|
+
import { Metadata } from "./types/src/display/metadata.js";
|
|
3
4
|
import * as PDFJS from "./types/src/pdf.js";
|
|
4
5
|
//#region src/_internal/canvas.d.ts
|
|
5
6
|
interface CanvasFactoryContext {
|
|
@@ -55,18 +56,6 @@ interface ExtractedImageObject {
|
|
|
55
56
|
/**
|
|
56
57
|
* Extracts images from a specific page of a PDF document, including necessary metadata,
|
|
57
58
|
* such as width, height, and calculated color channels.
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* const imagesData = await extractImages(pdf, pageNum)
|
|
61
|
-
*
|
|
62
|
-
* for (const imgData of imagesData) {
|
|
63
|
-
* const imageIndex = totalImagesProcessed + 1
|
|
64
|
-
* await sharp(imgData.data, {
|
|
65
|
-
* raw: { width: imgData.width, height: imgData.height, channels: imgData.channels }
|
|
66
|
-
* })
|
|
67
|
-
* .png()
|
|
68
|
-
* .toFile(`${imageIndex}.png`)
|
|
69
|
-
* }
|
|
70
59
|
*/
|
|
71
60
|
declare function extractImages$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, pageNumber: number): Promise<ExtractedImageObject[]>;
|
|
72
61
|
declare function renderPageAsImage$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, pageNumber: number, options?: {
|
|
@@ -98,7 +87,7 @@ declare function getMeta$1(data: DocumentInitParameters['data'] | PDFDocumentPro
|
|
|
98
87
|
parseDates?: boolean;
|
|
99
88
|
}): Promise<{
|
|
100
89
|
info: Record<string, any>;
|
|
101
|
-
metadata:
|
|
90
|
+
metadata: Metadata;
|
|
102
91
|
}>;
|
|
103
92
|
//#endregion
|
|
104
93
|
//#region src/text.d.ts
|
|
@@ -147,15 +136,14 @@ declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumen
|
|
|
147
136
|
//#endregion
|
|
148
137
|
//#region src/config.d.ts
|
|
149
138
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* provide a custom resolver function.
|
|
139
|
+
* Sets the PDF.js build every other method uses – call it before any of them.
|
|
140
|
+
* Without it, the serverless build is used.
|
|
153
141
|
*
|
|
154
142
|
* @example
|
|
155
|
-
* //
|
|
143
|
+
* // In Node.js, the legacy build of `pdfjs-dist` (install it first)
|
|
156
144
|
* import { definePDFJSModule } from 'unpdf'
|
|
157
145
|
*
|
|
158
|
-
* await definePDFJSModule(() => import('pdfjs-dist'))
|
|
146
|
+
* await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))
|
|
159
147
|
*/
|
|
160
148
|
export declare function definePDFJSModule(pdfjs: () => Promise<any>): Promise<void>;
|
|
161
149
|
/** @deprecated Use `definePDFJSModule` instead. Will be removed in v2. */
|
|
@@ -165,7 +153,7 @@ export declare function configureUnPDF(options: {
|
|
|
165
153
|
//#endregion
|
|
166
154
|
//#region src/utils.d.ts
|
|
167
155
|
/**
|
|
168
|
-
*
|
|
156
|
+
* Creates a `PDFDocumentProxy` from binary PDF data.
|
|
169
157
|
*
|
|
170
158
|
* Applies the following defaults:
|
|
171
159
|
* - `useSystemFonts: true`
|
package/dist/index.mjs
CHANGED
|
@@ -52,7 +52,7 @@ let resolvedModule;
|
|
|
52
52
|
const isNode = globalThis.process?.release?.name === "node";
|
|
53
53
|
const isBrowser = typeof window !== "undefined";
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* Creates a `PDFDocumentProxy` from binary PDF data.
|
|
56
56
|
*
|
|
57
57
|
* Applies the following defaults:
|
|
58
58
|
* - `useSystemFonts: true`
|
|
@@ -208,18 +208,6 @@ function injectCanvasConstructors() {
|
|
|
208
208
|
/**
|
|
209
209
|
* Extracts images from a specific page of a PDF document, including necessary metadata,
|
|
210
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
211
|
*/
|
|
224
212
|
async function extractImages$1(data, pageNumber) {
|
|
225
213
|
return await withDocument(data, async (pdf) => {
|
|
@@ -326,23 +314,23 @@ const XMP_DATE_PROPERTIES = [
|
|
|
326
314
|
async function getMeta$1(data, options = {}) {
|
|
327
315
|
return await withDocument(data, async (pdf) => {
|
|
328
316
|
const meta = await pdf.getMetadata();
|
|
329
|
-
const info = meta
|
|
317
|
+
const info = { ...meta.info };
|
|
318
|
+
let metadata = meta.metadata;
|
|
330
319
|
if (options.parseDates) {
|
|
331
320
|
const { PDFDateString } = await getResolvedPDFJS();
|
|
332
|
-
if (info
|
|
333
|
-
if (info
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
} });
|
|
321
|
+
if (info.CreationDate) info.CreationDate = PDFDateString.toDateObject(info.CreationDate);
|
|
322
|
+
if (info.ModDate) info.ModDate = PDFDateString.toDateObject(info.ModDate);
|
|
323
|
+
if (metadata) {
|
|
324
|
+
const Metadata = metadata.constructor;
|
|
325
|
+
metadata = new Metadata({
|
|
326
|
+
parsedData: new Map(Array.from(metadata, ([name, value]) => [name, XMP_DATE_PROPERTIES.includes(name) && value ? parseISODateString(value) : value])),
|
|
327
|
+
rawData: metadata.getRaw()
|
|
328
|
+
});
|
|
329
|
+
}
|
|
342
330
|
}
|
|
343
331
|
return {
|
|
344
332
|
info,
|
|
345
|
-
metadata:
|
|
333
|
+
metadata: metadata || {}
|
|
346
334
|
};
|
|
347
335
|
});
|
|
348
336
|
}
|
|
@@ -403,15 +391,14 @@ function normalizeMergedText(texts) {
|
|
|
403
391
|
//#endregion
|
|
404
392
|
//#region src/config.ts
|
|
405
393
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* provide a custom resolver function.
|
|
394
|
+
* Sets the PDF.js build every other method uses – call it before any of them.
|
|
395
|
+
* Without it, the serverless build is used.
|
|
409
396
|
*
|
|
410
397
|
* @example
|
|
411
|
-
* //
|
|
398
|
+
* // In Node.js, the legacy build of `pdfjs-dist` (install it first)
|
|
412
399
|
* import { definePDFJSModule } from 'unpdf'
|
|
413
400
|
*
|
|
414
|
-
* await definePDFJSModule(() => import('pdfjs-dist'))
|
|
401
|
+
* await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))
|
|
415
402
|
*/
|
|
416
403
|
async function definePDFJSModule(pdfjs) {
|
|
417
404
|
await resolvePDFJSImport(pdfjs, { reload: true });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unpdf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.1",
|
|
5
5
|
"packageManager": "pnpm@12.11.2",
|
|
6
6
|
"description": "PDF extraction and rendering across all JavaScript runtimes",
|
|
7
7
|
"author": "Johann Schopplich <hello@johannschopplich.com>",
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@antfu/eslint-config": "^9.5.1",
|
|
86
86
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
87
|
+
"@cloudflare/vitest-plugin": "^1.4.3",
|
|
87
88
|
"@napi-rs/canvas": "^1.0.11",
|
|
88
89
|
"@types/node": "^26.6.5",
|
|
89
90
|
"bumpp": "^12.3.0",
|