unpdf 1.5.0 → 1.6.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 CHANGED
@@ -272,6 +272,16 @@ In order to use this method, make sure to meet the following requirements:
272
272
  - Use the official PDF.js build (see [Official or Legacy PDF.js Build](#official-or-legacy-pdfjs-build)).
273
273
  - 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.
274
274
 
275
+ > [!TIP]
276
+ > 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:
277
+ >
278
+ > ```ts
279
+ > const pdf = await getDocumentProxy(buffer, {
280
+ > disableFontFace: false,
281
+ > standardFontDataUrl: 'https://unpkg.com/pdfjs-dist@latest/standard_fonts/',
282
+ > })
283
+ > ```
284
+
275
285
  **Type Declaration**
276
286
 
277
287
  ```ts
package/dist/index.cjs CHANGED
@@ -1,15 +1,73 @@
1
1
  'use strict';
2
2
 
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
+ };
43
+ }
44
+
45
+ function stubBrowserGlobals() {
46
+ polyfillDOMMatrix();
47
+ }
48
+
3
49
  let resolvedModule;
4
50
  const isNode = globalThis.process?.release?.name === "node";
5
51
  const isBrowser = typeof window !== "undefined";
6
52
  async function getDocumentProxy(data, options = {}) {
7
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
+ };
62
+ } catch {
63
+ }
64
+ }
8
65
  const pdf = await getDocument({
9
66
  data,
10
67
  isEvalSupported: false,
11
68
  // See: https://github.com/mozilla/pdf.js/issues/4244#issuecomment-1479534301
12
69
  useSystemFonts: true,
70
+ ...nodeDefaults,
13
71
  ...options
14
72
  }).promise;
15
73
  return pdf;
@@ -24,6 +82,7 @@ async function resolvePDFJSImport(pdfjsResolver, { reload = false } = {}) {
24
82
  if (resolvedModule && !reload) {
25
83
  return;
26
84
  }
85
+ stubBrowserGlobals();
27
86
  if (pdfjsResolver) {
28
87
  try {
29
88
  resolvedModule = await interopDefault(pdfjsResolver());
@@ -122,8 +181,7 @@ async function resolveCanvasModule(canvasImport) {
122
181
  function injectCanvasConstructors() {
123
182
  if (!resolvedCanvasModule)
124
183
  return;
125
- if (typeof globalThis.DOMMatrix === "undefined")
126
- globalThis.DOMMatrix = resolvedCanvasModule.DOMMatrix;
184
+ globalThis.DOMMatrix = resolvedCanvasModule.DOMMatrix;
127
185
  if (typeof globalThis.ImageData === "undefined")
128
186
  globalThis.ImageData = resolvedCanvasModule.ImageData;
129
187
  if (typeof globalThis.Path2D === "undefined")
@@ -282,6 +340,32 @@ function parseISODateString(isoDateString) {
282
340
  }
283
341
  }
284
342
 
343
+ async function extractTextItems$1(data) {
344
+ const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
345
+ const items = await Promise.all(
346
+ Array.from({ length: pdf.numPages }, (_, i) => getPageTextItems(pdf, i + 1))
347
+ );
348
+ return { totalPages: pdf.numPages, items };
349
+ }
350
+ async function getPageTextItems(document, pageNumber) {
351
+ const page = await document.getPage(pageNumber);
352
+ const content = await page.getTextContent();
353
+ const styles = content.styles;
354
+ return content.items.filter((item) => item.str != null).map((item) => {
355
+ const [_a, _b, c, d, e, f] = item.transform;
356
+ return {
357
+ str: item.str,
358
+ x: e,
359
+ y: f,
360
+ width: item.width,
361
+ height: item.height,
362
+ fontSize: Math.hypot(c, d),
363
+ fontFamily: styles[item.fontName]?.fontFamily ?? "",
364
+ dir: item.dir,
365
+ hasEOL: item.hasEOL
366
+ };
367
+ });
368
+ }
285
369
  async function extractText$1(data, options = {}) {
286
370
  const { mergePages = false } = options;
287
371
  const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
@@ -314,6 +398,10 @@ const extractText = async (...args) => {
314
398
  await resolvePDFJSImport();
315
399
  return await extractText$1(...args);
316
400
  };
401
+ const extractTextItems = async (...args) => {
402
+ await resolvePDFJSImport();
403
+ return await extractTextItems$1(...args);
404
+ };
317
405
  const extractImages = async (...args) => {
318
406
  await resolvePDFJSImport();
319
407
  return await extractImages$1(...args);
@@ -333,6 +421,7 @@ exports.definePDFJSModule = definePDFJSModule;
333
421
  exports.extractImages = extractImages;
334
422
  exports.extractLinks = extractLinks;
335
423
  exports.extractText = extractText;
424
+ exports.extractTextItems = extractTextItems;
336
425
  exports.getDocumentProxy = getDocumentProxy;
337
426
  exports.getMeta = getMeta;
338
427
  exports.getResolvedPDFJS = getResolvedPDFJS;
package/dist/index.d.cts CHANGED
@@ -100,6 +100,30 @@ declare function getMeta$1(data: DocumentInitParameters['data'] | PDFDocumentPro
100
100
  metadata: pdfjs_dist_types_src_display_metadata.Metadata;
101
101
  }>;
102
102
 
103
+ interface StructuredTextItem {
104
+ /** Text content. */
105
+ str: string;
106
+ /** X position in PDF coordinate space (origin: bottom-left). */
107
+ x: number;
108
+ /** Y position in PDF coordinate space (origin: bottom-left). */
109
+ y: number;
110
+ /** Width in device space. */
111
+ width: number;
112
+ /** Height in device space. */
113
+ height: number;
114
+ /** Font size derived from the transformation matrix. */
115
+ fontSize: number;
116
+ /** Font family name. */
117
+ fontFamily: string;
118
+ /** Text direction: `"ltr"`, `"rtl"`, or `"ttb"`. */
119
+ dir: string;
120
+ /** Whether the text item is followed by a line break. */
121
+ hasEOL: boolean;
122
+ }
123
+ declare function extractTextItems$1(data: DocumentInitParameters['data'] | PDFDocumentProxy): Promise<{
124
+ totalPages: number;
125
+ items: StructuredTextItem[][];
126
+ }>;
103
127
  declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
104
128
  mergePages?: false;
105
129
  }): Promise<{
@@ -136,6 +160,10 @@ declare function configureUnPDF(options: {
136
160
  * Applies the following defaults:
137
161
  * - `isEvalSupported: false`
138
162
  * - `useSystemFonts: true`
163
+ *
164
+ * In Node.js environments, additionally applies:
165
+ * - `disableFontFace: true`
166
+ * - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
139
167
  */
140
168
  declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
141
169
  declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
@@ -145,8 +173,10 @@ declare function resolvePDFJSImport(pdfjsResolver?: () => Promise<any>, { reload
145
173
 
146
174
  declare const getMeta: typeof getMeta$1;
147
175
  declare const extractText: typeof extractText$1;
176
+ declare const extractTextItems: typeof extractTextItems$1;
148
177
  declare const extractImages: typeof extractImages$1;
149
178
  declare const renderPageAsImage: typeof renderPageAsImage$1;
150
179
  declare const extractLinks: typeof extractLinks$1;
151
180
 
152
- export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
181
+ export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, extractTextItems, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
182
+ export type { StructuredTextItem };
package/dist/index.d.mts CHANGED
@@ -100,6 +100,30 @@ declare function getMeta$1(data: DocumentInitParameters['data'] | PDFDocumentPro
100
100
  metadata: pdfjs_dist_types_src_display_metadata.Metadata;
101
101
  }>;
102
102
 
103
+ interface StructuredTextItem {
104
+ /** Text content. */
105
+ str: string;
106
+ /** X position in PDF coordinate space (origin: bottom-left). */
107
+ x: number;
108
+ /** Y position in PDF coordinate space (origin: bottom-left). */
109
+ y: number;
110
+ /** Width in device space. */
111
+ width: number;
112
+ /** Height in device space. */
113
+ height: number;
114
+ /** Font size derived from the transformation matrix. */
115
+ fontSize: number;
116
+ /** Font family name. */
117
+ fontFamily: string;
118
+ /** Text direction: `"ltr"`, `"rtl"`, or `"ttb"`. */
119
+ dir: string;
120
+ /** Whether the text item is followed by a line break. */
121
+ hasEOL: boolean;
122
+ }
123
+ declare function extractTextItems$1(data: DocumentInitParameters['data'] | PDFDocumentProxy): Promise<{
124
+ totalPages: number;
125
+ items: StructuredTextItem[][];
126
+ }>;
103
127
  declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
104
128
  mergePages?: false;
105
129
  }): Promise<{
@@ -136,6 +160,10 @@ declare function configureUnPDF(options: {
136
160
  * Applies the following defaults:
137
161
  * - `isEvalSupported: false`
138
162
  * - `useSystemFonts: true`
163
+ *
164
+ * In Node.js environments, additionally applies:
165
+ * - `disableFontFace: true`
166
+ * - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
139
167
  */
140
168
  declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
141
169
  declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
@@ -145,8 +173,10 @@ declare function resolvePDFJSImport(pdfjsResolver?: () => Promise<any>, { reload
145
173
 
146
174
  declare const getMeta: typeof getMeta$1;
147
175
  declare const extractText: typeof extractText$1;
176
+ declare const extractTextItems: typeof extractTextItems$1;
148
177
  declare const extractImages: typeof extractImages$1;
149
178
  declare const renderPageAsImage: typeof renderPageAsImage$1;
150
179
  declare const extractLinks: typeof extractLinks$1;
151
180
 
152
- export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
181
+ export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, extractTextItems, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
182
+ export type { StructuredTextItem };
package/dist/index.d.ts CHANGED
@@ -100,6 +100,30 @@ declare function getMeta$1(data: DocumentInitParameters['data'] | PDFDocumentPro
100
100
  metadata: pdfjs_dist_types_src_display_metadata.Metadata;
101
101
  }>;
102
102
 
103
+ interface StructuredTextItem {
104
+ /** Text content. */
105
+ str: string;
106
+ /** X position in PDF coordinate space (origin: bottom-left). */
107
+ x: number;
108
+ /** Y position in PDF coordinate space (origin: bottom-left). */
109
+ y: number;
110
+ /** Width in device space. */
111
+ width: number;
112
+ /** Height in device space. */
113
+ height: number;
114
+ /** Font size derived from the transformation matrix. */
115
+ fontSize: number;
116
+ /** Font family name. */
117
+ fontFamily: string;
118
+ /** Text direction: `"ltr"`, `"rtl"`, or `"ttb"`. */
119
+ dir: string;
120
+ /** Whether the text item is followed by a line break. */
121
+ hasEOL: boolean;
122
+ }
123
+ declare function extractTextItems$1(data: DocumentInitParameters['data'] | PDFDocumentProxy): Promise<{
124
+ totalPages: number;
125
+ items: StructuredTextItem[][];
126
+ }>;
103
127
  declare function extractText$1(data: DocumentInitParameters['data'] | PDFDocumentProxy, options?: {
104
128
  mergePages?: false;
105
129
  }): Promise<{
@@ -136,6 +160,10 @@ declare function configureUnPDF(options: {
136
160
  * Applies the following defaults:
137
161
  * - `isEvalSupported: false`
138
162
  * - `useSystemFonts: true`
163
+ *
164
+ * In Node.js environments, additionally applies:
165
+ * - `disableFontFace: true`
166
+ * - `standardFontDataUrl` resolved from the local `pdfjs-dist` package
139
167
  */
140
168
  declare function getDocumentProxy(data: DocumentInitParameters['data'], options?: DocumentInitParameters): Promise<PDFDocumentProxy>;
141
169
  declare function getResolvedPDFJS(): Promise<typeof PDFJS>;
@@ -145,8 +173,10 @@ declare function resolvePDFJSImport(pdfjsResolver?: () => Promise<any>, { reload
145
173
 
146
174
  declare const getMeta: typeof getMeta$1;
147
175
  declare const extractText: typeof extractText$1;
176
+ declare const extractTextItems: typeof extractTextItems$1;
148
177
  declare const extractImages: typeof extractImages$1;
149
178
  declare const renderPageAsImage: typeof renderPageAsImage$1;
150
179
  declare const extractLinks: typeof extractLinks$1;
151
180
 
152
- export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
181
+ export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, extractTextItems, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
182
+ export type { StructuredTextItem };
package/dist/index.mjs CHANGED
@@ -1,13 +1,71 @@
1
+ function polyfillDOMMatrix() {
2
+ if (typeof globalThis.DOMMatrix !== "undefined")
3
+ return;
4
+ globalThis.DOMMatrix = class DOMMatrix {
5
+ a;
6
+ b;
7
+ c;
8
+ d;
9
+ e;
10
+ f;
11
+ constructor(init) {
12
+ if (Array.isArray(init) && init.length === 6) {
13
+ this.a = init[0];
14
+ this.b = init[1];
15
+ this.c = init[2];
16
+ this.d = init[3];
17
+ this.e = init[4];
18
+ this.f = init[5];
19
+ } else {
20
+ this.a = 1;
21
+ this.b = 0;
22
+ this.c = 0;
23
+ this.d = 1;
24
+ this.e = 0;
25
+ this.f = 0;
26
+ }
27
+ }
28
+ translateSelf(tx, ty = 0) {
29
+ this.e = this.a * tx + this.c * ty + this.e;
30
+ this.f = this.b * tx + this.d * ty + this.f;
31
+ return this;
32
+ }
33
+ scaleSelf(sx, sy = sx) {
34
+ this.a *= sx;
35
+ this.b *= sx;
36
+ this.c *= sy;
37
+ this.d *= sy;
38
+ return this;
39
+ }
40
+ };
41
+ }
42
+
43
+ function stubBrowserGlobals() {
44
+ polyfillDOMMatrix();
45
+ }
46
+
1
47
  let resolvedModule;
2
48
  const isNode = globalThis.process?.release?.name === "node";
3
49
  const isBrowser = typeof window !== "undefined";
4
50
  async function getDocumentProxy(data, options = {}) {
5
51
  const { getDocument } = await getResolvedPDFJS();
52
+ let nodeDefaults = {};
53
+ if (isNode) {
54
+ try {
55
+ const base = import.meta.resolve("pdfjs-dist/package.json");
56
+ nodeDefaults = {
57
+ disableFontFace: true,
58
+ standardFontDataUrl: new URL("./standard_fonts/", base).href
59
+ };
60
+ } catch {
61
+ }
62
+ }
6
63
  const pdf = await getDocument({
7
64
  data,
8
65
  isEvalSupported: false,
9
66
  // See: https://github.com/mozilla/pdf.js/issues/4244#issuecomment-1479534301
10
67
  useSystemFonts: true,
68
+ ...nodeDefaults,
11
69
  ...options
12
70
  }).promise;
13
71
  return pdf;
@@ -22,6 +80,7 @@ async function resolvePDFJSImport(pdfjsResolver, { reload = false } = {}) {
22
80
  if (resolvedModule && !reload) {
23
81
  return;
24
82
  }
83
+ stubBrowserGlobals();
25
84
  if (pdfjsResolver) {
26
85
  try {
27
86
  resolvedModule = await interopDefault(pdfjsResolver());
@@ -120,8 +179,7 @@ async function resolveCanvasModule(canvasImport) {
120
179
  function injectCanvasConstructors() {
121
180
  if (!resolvedCanvasModule)
122
181
  return;
123
- if (typeof globalThis.DOMMatrix === "undefined")
124
- globalThis.DOMMatrix = resolvedCanvasModule.DOMMatrix;
182
+ globalThis.DOMMatrix = resolvedCanvasModule.DOMMatrix;
125
183
  if (typeof globalThis.ImageData === "undefined")
126
184
  globalThis.ImageData = resolvedCanvasModule.ImageData;
127
185
  if (typeof globalThis.Path2D === "undefined")
@@ -280,6 +338,32 @@ function parseISODateString(isoDateString) {
280
338
  }
281
339
  }
282
340
 
341
+ async function extractTextItems$1(data) {
342
+ const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
343
+ const items = await Promise.all(
344
+ Array.from({ length: pdf.numPages }, (_, i) => getPageTextItems(pdf, i + 1))
345
+ );
346
+ return { totalPages: pdf.numPages, items };
347
+ }
348
+ async function getPageTextItems(document, pageNumber) {
349
+ const page = await document.getPage(pageNumber);
350
+ const content = await page.getTextContent();
351
+ const styles = content.styles;
352
+ return content.items.filter((item) => item.str != null).map((item) => {
353
+ const [_a, _b, c, d, e, f] = item.transform;
354
+ return {
355
+ str: item.str,
356
+ x: e,
357
+ y: f,
358
+ width: item.width,
359
+ height: item.height,
360
+ fontSize: Math.hypot(c, d),
361
+ fontFamily: styles[item.fontName]?.fontFamily ?? "",
362
+ dir: item.dir,
363
+ hasEOL: item.hasEOL
364
+ };
365
+ });
366
+ }
283
367
  async function extractText$1(data, options = {}) {
284
368
  const { mergePages = false } = options;
285
369
  const pdf = isPDFDocumentProxy(data) ? data : await getDocumentProxy(data);
@@ -312,6 +396,10 @@ const extractText = async (...args) => {
312
396
  await resolvePDFJSImport();
313
397
  return await extractText$1(...args);
314
398
  };
399
+ const extractTextItems = async (...args) => {
400
+ await resolvePDFJSImport();
401
+ return await extractTextItems$1(...args);
402
+ };
315
403
  const extractImages = async (...args) => {
316
404
  await resolvePDFJSImport();
317
405
  return await extractImages$1(...args);
@@ -325,4 +413,4 @@ const extractLinks = async (...args) => {
325
413
  return await extractLinks$1(...args);
326
414
  };
327
415
 
328
- export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };
416
+ export { configureUnPDF, createIsomorphicCanvasFactory, definePDFJSModule, extractImages, extractLinks, extractText, extractTextItems, getDocumentProxy, getMeta, getResolvedPDFJS, renderPageAsImage, resolvePDFJSImport };