unpdf 1.6.1 → 1.7.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 +60 -24
- package/dist/index.cjs +145 -110
- package/dist/index.d.cts +13 -6
- package/dist/index.d.mts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.mjs +145 -110
- package/dist/pdfjs.d.mts +1 -1
- package/dist/pdfjs.d.ts +1 -1
- package/dist/pdfjs.mjs +24 -24
- package/dist/types/src/display/annotation_layer.d.ts +2 -2
- package/dist/types/src/display/text_layer.d.ts +4 -4
- package/dist/types/src/display/xfa_layer.d.ts +3 -3
- package/dist/types/src/display/xfa_text.d.ts +2 -2
- package/dist/types/src/pdf.d.ts +6 -6
- package/dist/types/web/annotation_editor_layer_builder.d.ts +5 -5
- package/dist/types/web/annotation_layer_builder.d.ts +9 -9
- package/dist/types/web/pdf_find_controller.d.ts +4 -4
- package/dist/types/web/pdf_history.d.ts +1 -1
- package/dist/types/web/pdf_link_service.d.ts +2 -2
- package/dist/types/web/pdf_page_view.d.ts +12 -12
- package/dist/types/web/pdf_rendering_queue.d.ts +3 -3
- package/dist/types/web/pdf_scripting_manager.d.ts +1 -1
- package/dist/types/web/pdf_thumbnail_view.d.ts +9 -9
- package/dist/types/web/pdf_thumbnail_viewer.d.ts +7 -7
- package/dist/types/web/pdf_viewer.d.ts +14 -14
- package/dist/types/web/renderable_view.d.ts +2 -2
- package/dist/types/web/struct_tree_layer_builder.d.ts +1 -1
- package/dist/types/web/text_highlighter.d.ts +6 -6
- package/dist/types/web/text_layer_builder.d.ts +6 -6
- package/dist/types/web/xfa_layer_builder.d.ts +6 -6
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Ships with a serverless build of Mozilla's [PDF.js](https://github.com/mozilla/p
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- 🏗️ Works in Node.js, browser and serverless environments
|
|
10
|
-
- 🪭 Includes serverless build of PDF.js ([`unpdf/pdfjs`](./package.json
|
|
10
|
+
- 🪭 Includes serverless build of PDF.js ([`unpdf/pdfjs`](./package.json))
|
|
11
11
|
- 💬 Extract [text](#extract-text-from-pdf), [links](#extractlinks), and [images](#extractimages) from PDF files
|
|
12
12
|
- 🧠 Perfect for AI applications and PDF summarization
|
|
13
13
|
- 🧱 Opt-in to official or legacy PDF.js build
|
|
@@ -97,7 +97,7 @@ Heart and soul of this package is the [`pdfjs.rollup.config.ts`](./pdfjs.rollup.
|
|
|
97
97
|
|
|
98
98
|
- **String replacements** strip browser-specific references from the PDF.js source.
|
|
99
99
|
- **Worker inlining** embeds the PDF.js worker directly into the main bundle, since serverless runtimes can't load separate worker files.
|
|
100
|
-
- **Global polyfills** provide missing APIs like `FinalizationRegistry` (unavailable in Cloudflare Workers).
|
|
100
|
+
- **Global polyfills** provide missing APIs like `Promise.withResolvers` and `FinalizationRegistry` (unavailable in Node.js < 22 and Cloudflare Workers, respectively).
|
|
101
101
|
|
|
102
102
|
## API
|
|
103
103
|
|
|
@@ -121,6 +121,21 @@ Returns the resolved PDF.js module. If no other PDF.js build was defined, the se
|
|
|
121
121
|
function getResolvedPDFJS(): Promise<PDFJS>
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
### `getDocumentProxy`
|
|
125
|
+
|
|
126
|
+
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
|
+
|
|
128
|
+
Applies sensible defaults: `isEvalSupported: false` and `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 (see the font rendering tip in [`renderPageAsImage`](#renderpageasimage)).
|
|
129
|
+
|
|
130
|
+
**Type Declaration**
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
function getDocumentProxy(
|
|
134
|
+
data: DocumentInitParameters['data'],
|
|
135
|
+
options?: DocumentInitParameters,
|
|
136
|
+
): Promise<PDFDocumentProxy>
|
|
137
|
+
```
|
|
138
|
+
|
|
124
139
|
### `getMeta`
|
|
125
140
|
|
|
126
141
|
Extracts metadata from a PDF. If `parseDates` is set to `true`, the date properties will be parsed into `Date` objects.
|
|
@@ -141,7 +156,7 @@ function getMeta(
|
|
|
141
156
|
|
|
142
157
|
### `extractText`
|
|
143
158
|
|
|
144
|
-
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.
|
|
159
|
+
Extracts all text from a PDF. If `mergePages` is set to `true`, the text of all pages will be merged into a single string with line breaks preserved and at most one blank line in a row. Otherwise, an array of strings for each page will be returned.
|
|
145
160
|
|
|
146
161
|
**Type Declaration**
|
|
147
162
|
|
|
@@ -149,20 +164,42 @@ Extracts all text from a PDF. If `mergePages` is set to `true`, the text of all
|
|
|
149
164
|
function extractText(
|
|
150
165
|
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
151
166
|
options?: {
|
|
152
|
-
mergePages?:
|
|
167
|
+
mergePages?: boolean
|
|
153
168
|
}
|
|
154
169
|
): Promise<{
|
|
155
170
|
totalPages: number
|
|
156
|
-
text: string[]
|
|
171
|
+
text: string | string[]
|
|
157
172
|
}>
|
|
158
|
-
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `extractTextItems`
|
|
176
|
+
|
|
177
|
+
Extracts text with layout information – one array of positioned items per page. Useful when plain text is not enough and you need coordinates, font sizes, or reading direction, e.g. for table detection or positional parsing.
|
|
178
|
+
|
|
179
|
+
**Type Declaration**
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
interface StructuredTextItem {
|
|
183
|
+
str: string
|
|
184
|
+
/** X position in PDF coordinate space (origin: bottom-left). */
|
|
185
|
+
x: number
|
|
186
|
+
/** Y position in PDF coordinate space (origin: bottom-left). */
|
|
187
|
+
y: number
|
|
188
|
+
width: number
|
|
189
|
+
height: number
|
|
190
|
+
fontSize: number
|
|
191
|
+
fontFamily: string
|
|
192
|
+
/** Text direction: `"ltr"`, `"rtl"`, or `"ttb"`. */
|
|
193
|
+
dir: string
|
|
194
|
+
/** Whether the text item is followed by a line break. */
|
|
195
|
+
hasEOL: boolean
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function extractTextItems(
|
|
159
199
|
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
160
|
-
options: {
|
|
161
|
-
mergePages: true
|
|
162
|
-
}
|
|
163
200
|
): Promise<{
|
|
164
201
|
totalPages: number
|
|
165
|
-
|
|
202
|
+
items: StructuredTextItem[][]
|
|
166
203
|
}>
|
|
167
204
|
```
|
|
168
205
|
|
|
@@ -294,26 +331,15 @@ function renderPageAsImage(
|
|
|
294
331
|
scale?: number
|
|
295
332
|
width?: number
|
|
296
333
|
height?: number
|
|
297
|
-
toDataURL?:
|
|
334
|
+
toDataURL?: boolean
|
|
298
335
|
},
|
|
299
|
-
): Promise<ArrayBuffer>
|
|
300
|
-
function renderPageAsImage(
|
|
301
|
-
data: DocumentInitParameters['data'] | PDFDocumentProxy,
|
|
302
|
-
pageNumber: number,
|
|
303
|
-
options: {
|
|
304
|
-
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
|
|
305
|
-
/** @default 1.0 */
|
|
306
|
-
scale?: number
|
|
307
|
-
width?: number
|
|
308
|
-
height?: number
|
|
309
|
-
toDataURL: true
|
|
310
|
-
},
|
|
311
|
-
): Promise<string>
|
|
336
|
+
): Promise<ArrayBuffer | string>
|
|
312
337
|
```
|
|
313
338
|
|
|
314
339
|
**Examples**
|
|
315
340
|
|
|
316
341
|
```ts
|
|
342
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
317
343
|
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
|
|
318
344
|
|
|
319
345
|
// Use the official PDF.js build
|
|
@@ -331,6 +357,7 @@ await writeFile('dummy-page-1.png', new Uint8Array(result))
|
|
|
331
357
|
```
|
|
332
358
|
|
|
333
359
|
```ts
|
|
360
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
334
361
|
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
|
|
335
362
|
|
|
336
363
|
await definePDFJSModule(() => import('pdfjs-dist'))
|
|
@@ -360,6 +387,15 @@ const html = `<!DOCTYPE html>
|
|
|
360
387
|
await writeFile('dummy-page-1.html', html)
|
|
361
388
|
```
|
|
362
389
|
|
|
390
|
+
## Processing Untrusted PDFs
|
|
391
|
+
|
|
392
|
+
The `getDocumentProxy` defaults are safe against script execution (`isEvalSupported: false`), but resource limits are your job:
|
|
393
|
+
|
|
394
|
+
- **Image decoding:** `maxImageSize` is unlimited by default – pass e.g. `maxImageSize: 16_777_216` (~16 MP) so a single declared image can't allocate gigabytes.
|
|
395
|
+
- **Page fan-out:** `extractText`, `extractTextItems`, and `extractLinks` process all pages in one call – check `pdf.numPages` against a limit first.
|
|
396
|
+
- **Timeouts:** with the serverless build, parsing runs on your event loop (no worker) – race extraction calls against a timeout.
|
|
397
|
+
- The raw `getDocument` from `unpdf/pdfjs` applies none of these defaults.
|
|
398
|
+
|
|
363
399
|
## License
|
|
364
400
|
|
|
365
401
|
[MIT](./LICENSE) License © 2023-PRESENT [Johann Schopplich](https://github.com/johannschopplich)
|
package/dist/index.cjs
CHANGED
|
@@ -57,7 +57,9 @@ async function getDocumentProxy(data, options = {}) {
|
|
|
57
57
|
const base = undefined("pdfjs-dist/package.json");
|
|
58
58
|
nodeDefaults = {
|
|
59
59
|
disableFontFace: true,
|
|
60
|
-
standardFontDataUrl: new URL("./standard_fonts/", base).href
|
|
60
|
+
standardFontDataUrl: new URL("./standard_fonts/", base).href,
|
|
61
|
+
cMapUrl: new URL("./cmaps/", base).href,
|
|
62
|
+
cMapPacked: true
|
|
61
63
|
};
|
|
62
64
|
} catch {
|
|
63
65
|
}
|
|
@@ -72,6 +74,15 @@ async function getDocumentProxy(data, options = {}) {
|
|
|
72
74
|
}).promise;
|
|
73
75
|
return pdf;
|
|
74
76
|
}
|
|
77
|
+
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
|
+
}
|
|
85
|
+
}
|
|
75
86
|
async function getResolvedPDFJS() {
|
|
76
87
|
if (!resolvedModule) {
|
|
77
88
|
await resolvePDFJSImport();
|
|
@@ -177,6 +188,7 @@ class NodeCanvasFactory extends BaseCanvasFactory {
|
|
|
177
188
|
}
|
|
178
189
|
async function resolveCanvasModule(canvasImport) {
|
|
179
190
|
resolvedCanvasModule ??= await interopDefault(canvasImport());
|
|
191
|
+
globalThis[Symbol.for("unpdf.canvasModule")] = resolvedCanvasModule;
|
|
180
192
|
}
|
|
181
193
|
function injectCanvasConstructors() {
|
|
182
194
|
if (!resolvedCanvasModule)
|
|
@@ -189,69 +201,85 @@ function injectCanvasConstructors() {
|
|
|
189
201
|
}
|
|
190
202
|
|
|
191
203
|
async function extractImages$1(data, pageNumber) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
const page = await pdf.getPage(pageNumber);
|
|
197
|
-
const operatorList = await page.getOperatorList();
|
|
198
|
-
const { OPS } = await getResolvedPDFJS();
|
|
199
|
-
const images = [];
|
|
200
|
-
for (let i = 0; i < operatorList.fnArray.length; i++) {
|
|
201
|
-
const op = operatorList.fnArray[i];
|
|
202
|
-
if (op !== OPS.paintImageXObject) {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const imageKey = operatorList.argsArray[i][0];
|
|
206
|
-
const image = await new Promise(
|
|
207
|
-
(resolve) => (imageKey.startsWith("g_") ? page.commonObjs : page.objs).get(imageKey, resolve)
|
|
208
|
-
);
|
|
209
|
-
if (!image || !image.data || !image.width || !image.height) {
|
|
210
|
-
continue;
|
|
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}.`);
|
|
211
207
|
}
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
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
|
+
});
|
|
216
237
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
data: data2,
|
|
220
|
-
width,
|
|
221
|
-
height,
|
|
222
|
-
channels,
|
|
223
|
-
key: imageKey
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
return images;
|
|
238
|
+
return images;
|
|
239
|
+
});
|
|
227
240
|
}
|
|
228
241
|
async function renderPageAsImage$1(data, pageNumber, options = {}) {
|
|
229
242
|
const CanvasFactory = await createIsomorphicCanvasFactory(options.canvasImport);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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 });
|
|
255
283
|
}
|
|
256
284
|
async function createIsomorphicCanvasFactory(canvasImport) {
|
|
257
285
|
if (isBrowser)
|
|
@@ -268,14 +296,15 @@ async function createIsomorphicCanvasFactory(canvasImport) {
|
|
|
268
296
|
}
|
|
269
297
|
|
|
270
298
|
async function extractLinks$1(data) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
+
});
|
|
279
308
|
}
|
|
280
309
|
async function getPageLinks(document, pageNumber) {
|
|
281
310
|
const page = await document.getPage(pageNumber);
|
|
@@ -298,38 +327,39 @@ const XMP_DATE_PROPERTIES = [
|
|
|
298
327
|
"xap:metadatadate"
|
|
299
328
|
];
|
|
300
329
|
async function getMeta$1(data, options = {}) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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];
|
|
323
354
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
});
|
|
355
|
+
});
|
|
356
|
+
}
|
|
327
357
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
};
|
|
358
|
+
return {
|
|
359
|
+
info,
|
|
360
|
+
metadata: meta?.metadata || {}
|
|
361
|
+
};
|
|
362
|
+
});
|
|
333
363
|
}
|
|
334
364
|
function parseISODateString(isoDateString) {
|
|
335
365
|
if (!isoDateString)
|
|
@@ -341,11 +371,12 @@ function parseISODateString(isoDateString) {
|
|
|
341
371
|
}
|
|
342
372
|
|
|
343
373
|
async function extractTextItems$1(data) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
+
});
|
|
349
380
|
}
|
|
350
381
|
async function getPageTextItems(document, pageNumber) {
|
|
351
382
|
const page = await document.getPage(pageNumber);
|
|
@@ -368,20 +399,24 @@ async function getPageTextItems(document, pageNumber) {
|
|
|
368
399
|
}
|
|
369
400
|
async function extractText$1(data, options = {}) {
|
|
370
401
|
const { mergePages = false } = options;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
+
});
|
|
379
411
|
}
|
|
380
412
|
async function getPageText(document, pageNumber) {
|
|
381
413
|
const page = await document.getPage(pageNumber);
|
|
382
414
|
const content = await page.getTextContent();
|
|
383
415
|
return content.items.filter((item) => item.str != null).map((item) => item.str + (item.hasEOL ? "\n" : "")).join("");
|
|
384
416
|
}
|
|
417
|
+
function normalizeMergedText(texts) {
|
|
418
|
+
return texts.join("\n").replace(/[^\S\n]+/g, " ").replace(/ ?\n ?/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
419
|
+
}
|
|
385
420
|
|
|
386
421
|
async function definePDFJSModule(pdfjs) {
|
|
387
422
|
await resolvePDFJSImport(pdfjs, { reload: true });
|
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as _napi_rs_canvas from '@napi-rs/canvas';
|
|
2
|
-
import { Canvas,
|
|
3
|
-
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api';
|
|
4
|
-
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata';
|
|
5
|
-
import * as PDFJS from './types/src/pdf';
|
|
2
|
+
import { Canvas, SKRSContext2D } from '@napi-rs/canvas';
|
|
3
|
+
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api.js';
|
|
4
|
+
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata.js';
|
|
5
|
+
import * as PDFJS from './types/src/pdf.js';
|
|
6
6
|
|
|
7
7
|
interface CanvasFactoryContext {
|
|
8
8
|
canvas?: HTMLCanvasElement | Canvas;
|
|
9
|
-
context?: CanvasRenderingContext2D |
|
|
9
|
+
context?: CanvasRenderingContext2D | SKRSContext2D | null;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
@@ -20,7 +20,7 @@ declare class BaseCanvasFactory {
|
|
|
20
20
|
});
|
|
21
21
|
create(width: number, height: number): {
|
|
22
22
|
canvas: Canvas | HTMLCanvasElement;
|
|
23
|
-
context:
|
|
23
|
+
context: SKRSContext2D | CanvasRenderingContext2D | null;
|
|
24
24
|
};
|
|
25
25
|
reset({ canvas }: CanvasFactoryContext, width: number, height: number): void;
|
|
26
26
|
destroy(context: CanvasFactoryContext): void;
|
|
@@ -136,6 +136,12 @@ declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumen
|
|
|
136
136
|
totalPages: number;
|
|
137
137
|
text: string;
|
|
138
138
|
}>;
|
|
139
|
+
declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
|
|
140
|
+
mergePages?: boolean;
|
|
141
|
+
}): Promise<{
|
|
142
|
+
totalPages: number;
|
|
143
|
+
text: string | string[];
|
|
144
|
+
}>;
|
|
139
145
|
|
|
140
146
|
/**
|
|
141
147
|
* By default, unpdf will use the latest version of PDF.js compiled for
|
|
@@ -164,6 +170,7 @@ declare function configureUnPDF(options: {
|
|
|
164
170
|
* In Node.js environments, additionally applies:
|
|
165
171
|
* - `disableFontFace: true`
|
|
166
172
|
* - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
|
|
173
|
+
* - `cMapUrl` and `cMapPacked` resolved from the local `pdfjs-dist` package
|
|
167
174
|
*/
|
|
168
175
|
declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
|
|
169
176
|
declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as _napi_rs_canvas from '@napi-rs/canvas';
|
|
2
|
-
import { Canvas,
|
|
3
|
-
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api';
|
|
4
|
-
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata';
|
|
5
|
-
import * as PDFJS from './types/src/pdf';
|
|
2
|
+
import { Canvas, SKRSContext2D } from '@napi-rs/canvas';
|
|
3
|
+
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api.js';
|
|
4
|
+
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata.js';
|
|
5
|
+
import * as PDFJS from './types/src/pdf.js';
|
|
6
6
|
|
|
7
7
|
interface CanvasFactoryContext {
|
|
8
8
|
canvas?: HTMLCanvasElement | Canvas;
|
|
9
|
-
context?: CanvasRenderingContext2D |
|
|
9
|
+
context?: CanvasRenderingContext2D | SKRSContext2D | null;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
@@ -20,7 +20,7 @@ declare class BaseCanvasFactory {
|
|
|
20
20
|
});
|
|
21
21
|
create(width: number, height: number): {
|
|
22
22
|
canvas: Canvas | HTMLCanvasElement;
|
|
23
|
-
context:
|
|
23
|
+
context: SKRSContext2D | CanvasRenderingContext2D | null;
|
|
24
24
|
};
|
|
25
25
|
reset({ canvas }: CanvasFactoryContext, width: number, height: number): void;
|
|
26
26
|
destroy(context: CanvasFactoryContext): void;
|
|
@@ -136,6 +136,12 @@ declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumen
|
|
|
136
136
|
totalPages: number;
|
|
137
137
|
text: string;
|
|
138
138
|
}>;
|
|
139
|
+
declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
|
|
140
|
+
mergePages?: boolean;
|
|
141
|
+
}): Promise<{
|
|
142
|
+
totalPages: number;
|
|
143
|
+
text: string | string[];
|
|
144
|
+
}>;
|
|
139
145
|
|
|
140
146
|
/**
|
|
141
147
|
* By default, unpdf will use the latest version of PDF.js compiled for
|
|
@@ -164,6 +170,7 @@ declare function configureUnPDF(options: {
|
|
|
164
170
|
* In Node.js environments, additionally applies:
|
|
165
171
|
* - `disableFontFace: true`
|
|
166
172
|
* - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
|
|
173
|
+
* - `cMapUrl` and `cMapPacked` resolved from the local `pdfjs-dist` package
|
|
167
174
|
*/
|
|
168
175
|
declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
|
|
169
176
|
declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as _napi_rs_canvas from '@napi-rs/canvas';
|
|
2
|
-
import { Canvas,
|
|
3
|
-
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api';
|
|
4
|
-
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata';
|
|
5
|
-
import * as PDFJS from './types/src/pdf';
|
|
2
|
+
import { Canvas, SKRSContext2D } from '@napi-rs/canvas';
|
|
3
|
+
import { DocumentInitParameters, PDFDocumentProxy } from './types/src/display/api.js';
|
|
4
|
+
import * as pdfjs_dist_types_src_display_metadata from './types/src/display/metadata.js';
|
|
5
|
+
import * as PDFJS from './types/src/pdf.js';
|
|
6
6
|
|
|
7
7
|
interface CanvasFactoryContext {
|
|
8
8
|
canvas?: HTMLCanvasElement | Canvas;
|
|
9
|
-
context?: CanvasRenderingContext2D |
|
|
9
|
+
context?: CanvasRenderingContext2D | SKRSContext2D | null;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Derived from the PDF.js project by the Mozilla Foundation.
|
|
@@ -20,7 +20,7 @@ declare class BaseCanvasFactory {
|
|
|
20
20
|
});
|
|
21
21
|
create(width: number, height: number): {
|
|
22
22
|
canvas: Canvas | HTMLCanvasElement;
|
|
23
|
-
context:
|
|
23
|
+
context: SKRSContext2D | CanvasRenderingContext2D | null;
|
|
24
24
|
};
|
|
25
25
|
reset({ canvas }: CanvasFactoryContext, width: number, height: number): void;
|
|
26
26
|
destroy(context: CanvasFactoryContext): void;
|
|
@@ -136,6 +136,12 @@ declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumen
|
|
|
136
136
|
totalPages: number;
|
|
137
137
|
text: string;
|
|
138
138
|
}>;
|
|
139
|
+
declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
|
|
140
|
+
mergePages?: boolean;
|
|
141
|
+
}): Promise<{
|
|
142
|
+
totalPages: number;
|
|
143
|
+
text: string | string[];
|
|
144
|
+
}>;
|
|
139
145
|
|
|
140
146
|
/**
|
|
141
147
|
* By default, unpdf will use the latest version of PDF.js compiled for
|
|
@@ -164,6 +170,7 @@ declare function configureUnPDF(options: {
|
|
|
164
170
|
* In Node.js environments, additionally applies:
|
|
165
171
|
* - `disableFontFace: true`
|
|
166
172
|
* - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
|
|
173
|
+
* - `cMapUrl` and `cMapPacked` resolved from the local `pdfjs-dist` package
|
|
167
174
|
*/
|
|
168
175
|
declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
|
|
169
176
|
declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
|