Skip to content

Commit b9f5ca7

Browse files
authored
feat: add toDataURL option to renderPageAsImage function (#41)
* feat: add `toDataURL` option to `renderPageAsImage` function * test: add unit test for rendering PDF as data URL * docs(readme): add `renderPageAsImage` usage examples for `toDataURL` option * docs(readme): update type for `data` parameter in `renderPageAsImage` function to include `PDFDocumentProxy`
1 parent 0629814 commit b9f5ca7

File tree

4 files changed

+103
-5
lines changed

4 files changed

+103
-5
lines changed

README.md

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ extractPdfImages().catch(console.error)
273273

274274
### `renderPageAsImage`
275275

276-
To render a PDF page as an image, you can use the `renderPageAsImage` method. This method will return an `ArrayBuffer` of the rendered image.
276+
To render a PDF page as an image, you can use the `renderPageAsImage` method. This method will return an `ArrayBuffer` of the rendered image. It can also return a data URL (`string`) if `toDataURL` option is set to `true`.
277277

278278
> [!NOTE]
279279
> This method will only work in Node.js and browser environments.
@@ -286,20 +286,33 @@ In order to use this method, make sure to meet the following requirements:
286286
**Type Declaration**
287287

288288
```ts
289-
declare function renderPageAsImage(
290-
data: DocumentInitParameters['data'],
289+
function renderPageAsImage(
290+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
291291
pageNumber: number,
292292
options?: {
293293
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
294294
/** @default 1.0 */
295295
scale?: number
296296
width?: number
297297
height?: number
298+
toDataURL?: false
298299
},
299300
): Promise<ArrayBuffer>
301+
function renderPageAsImage(
302+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
303+
pageNumber: number,
304+
options: {
305+
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
306+
/** @default 1.0 */
307+
scale?: number
308+
width?: number
309+
height?: number
310+
toDataURL: true
311+
},
312+
): Promise<string>
300313
```
301314

302-
**Example**
315+
**Examples**
303316

304317
```ts
305318
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
@@ -318,6 +331,36 @@ const result = await renderPageAsImage(buffer, pageNumber, {
318331
await writeFile('dummy-page-1.png', new Uint8Array(result))
319332
```
320333

334+
```ts
335+
import { definePDFJSModule, renderPageAsImage } from 'unpdf'
336+
337+
await definePDFJSModule(() => import('pdfjs-dist'))
338+
339+
const pdf = await readFile('./dummy.pdf')
340+
const buffer = new Uint8Array(pdf)
341+
const pageNumber = 1
342+
343+
const result = await renderPageAsImage(buffer, pageNumber, {
344+
canvasImport: () => import('@napi-rs/canvas'),
345+
scale: 2,
346+
toDataURL: true,
347+
})
348+
349+
const html = `<!DOCTYPE html>
350+
<html lang="en">
351+
<head>
352+
<meta charset="UTF-8">
353+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
354+
<title>Dummy Page</title>
355+
</head>
356+
<body>
357+
<img alt="Example Page" src="${result}">
358+
</body>
359+
</html>`
360+
361+
await writeFile('dummy-page-1.html', html)
362+
```
363+
321364
## License
322365

323366
[MIT](./LICENSE) License © 2023-PRESENT [Johann Schopplich](https://github.com/johannschopplich)

src/image.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,30 @@ export async function extractImages(
8888
return images
8989
}
9090

91+
export function renderPageAsImage(
92+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
93+
pageNumber: number,
94+
options?: {
95+
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
96+
/** @default 1.0 */
97+
scale?: number
98+
width?: number
99+
height?: number
100+
toDataURL?: false
101+
}
102+
): Promise<ArrayBuffer>
103+
export function renderPageAsImage(
104+
data: DocumentInitParameters['data'] | PDFDocumentProxy,
105+
pageNumber: number,
106+
options: {
107+
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
108+
/** @default 1.0 */
109+
scale?: number
110+
width?: number
111+
height?: number
112+
toDataURL: true
113+
}
114+
): Promise<string>
91115
export async function renderPageAsImage(
92116
data: DocumentInitParameters['data'] | PDFDocumentProxy,
93117
pageNumber: number,
@@ -97,6 +121,7 @@ export async function renderPageAsImage(
97121
scale?: number
98122
width?: number
99123
height?: number
124+
toDataURL?: boolean
100125
} = {},
101126
) {
102127
const CanvasFactory = await createIsomorphicCanvasFactory(options.canvasImport)
@@ -133,6 +158,11 @@ export async function renderPageAsImage(
133158
}).promise
134159

135160
const dataUrl = drawingContext.canvas.toDataURL()
161+
162+
if (options.toDataURL) {
163+
return dataUrl
164+
}
165+
136166
const response = await fetch(dataUrl)
137167

138168
return await response.arrayBuffer()

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const extractImages: typeof _extractImages = async (...args) => {
3030

3131
export const renderPageAsImage: typeof _renderPageAsImage = async (...args) => {
3232
await resolvePDFJSImport()
33-
return await _renderPageAsImage(...args)
33+
return await (_renderPageAsImage as any)(...args)
3434
}
3535

3636
export const extractLinks: typeof _extractLinks = async (...args) => {

test/index.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,31 @@ describe('unpdf', () => {
8888
expect(Array.from(headerBytes)).toEqual([137, 80, 78, 71, 13, 10, 26, 10])
8989
})
9090

91+
it('renders a PDF as data URL', async () => {
92+
const result = await renderPageAsImage(await getPDF('pdflatex-image.pdf'), 1, {
93+
canvasImport: () => import('@napi-rs/canvas'),
94+
toDataURL: true,
95+
})
96+
97+
const html = `<!DOCTYPE html>
98+
<html lang="en">
99+
<head>
100+
<meta charset="UTF-8">
101+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
102+
<title>PDFLatex Image</title>
103+
</head>
104+
<body>
105+
<img alt="Image" src="${result}">
106+
</body>
107+
</html>`
108+
await writeFile(
109+
new URL('artifacts/pdflatex-image.html', import.meta.url),
110+
html,
111+
)
112+
113+
expect(result.startsWith('data:image/png;base64,')).toBe(true)
114+
})
115+
91116
it('supports passing PDFDocumentProxy', async () => {
92117
const pdf = await getDocumentProxy(await getPDF())
93118
const { info } = await getMeta(pdf)

0 commit comments

Comments
 (0)