Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ extractPdfImages().catch(console.error)

### `renderPageAsImage`

To render a PDF page as an image, you can use the `renderPageAsImage` method. This method will return an `ArrayBuffer` of the rendered image.
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`.

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

```ts
declare function renderPageAsImage(
data: DocumentInitParameters['data'],
function renderPageAsImage(
data: DocumentInitParameters['data'] | PDFDocumentProxy,
pageNumber: number,
options?: {
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
/** @default 1.0 */
scale?: number
width?: number
height?: number
toDataURL?: false
},
): Promise<ArrayBuffer>
function renderPageAsImage(
data: DocumentInitParameters['data'] | PDFDocumentProxy,
pageNumber: number,
options: {
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
/** @default 1.0 */
scale?: number
width?: number
height?: number
toDataURL: true
},
): Promise<string>
```

**Example**
**Examples**

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

```ts
import { definePDFJSModule, renderPageAsImage } from 'unpdf'

await definePDFJSModule(() => import('pdfjs-dist'))

const pdf = await readFile('./dummy.pdf')
const buffer = new Uint8Array(pdf)
const pageNumber = 1

const result = await renderPageAsImage(buffer, pageNumber, {
canvasImport: () => import('@napi-rs/canvas'),
scale: 2,
toDataURL: true,
})

const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dummy Page</title>
</head>
<body>
<img alt="Example Page" src="${result}">
</body>
</html>`

await writeFile('dummy-page-1.html', html)
```

## License

[MIT](./LICENSE) License © 2023-PRESENT [Johann Schopplich](https://github.com/johannschopplich)
30 changes: 30 additions & 0 deletions src/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,30 @@ export async function extractImages(
return images
}

export function renderPageAsImage(
data: DocumentInitParameters['data'] | PDFDocumentProxy,
pageNumber: number,
options?: {
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
/** @default 1.0 */
scale?: number
width?: number
height?: number
toDataURL?: false
}
): Promise<ArrayBuffer>
export function renderPageAsImage(
data: DocumentInitParameters['data'] | PDFDocumentProxy,
pageNumber: number,
options: {
canvasImport?: () => Promise<typeof import('@napi-rs/canvas')>
/** @default 1.0 */
scale?: number
width?: number
height?: number
toDataURL: true
}
): Promise<string>
export async function renderPageAsImage(
data: DocumentInitParameters['data'] | PDFDocumentProxy,
pageNumber: number,
Expand All @@ -97,6 +121,7 @@ export async function renderPageAsImage(
scale?: number
width?: number
height?: number
toDataURL?: boolean
} = {},
) {
const CanvasFactory = await createIsomorphicCanvasFactory(options.canvasImport)
Expand Down Expand Up @@ -133,6 +158,11 @@ export async function renderPageAsImage(
}).promise

const dataUrl = drawingContext.canvas.toDataURL()

if (options.toDataURL) {
return dataUrl
}

const response = await fetch(dataUrl)

return await response.arrayBuffer()
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const extractImages: typeof _extractImages = async (...args) => {

export const renderPageAsImage: typeof _renderPageAsImage = async (...args) => {
await resolvePDFJSImport()
return await _renderPageAsImage(...args)
return await (_renderPageAsImage as any)(...args)
}

export const extractLinks: typeof _extractLinks = async (...args) => {
Expand Down
25 changes: 25 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,31 @@ describe('unpdf', () => {
expect(Array.from(headerBytes)).toEqual([137, 80, 78, 71, 13, 10, 26, 10])
})

it('renders a PDF as data URL', async () => {
const result = await renderPageAsImage(await getPDF('pdflatex-image.pdf'), 1, {
canvasImport: () => import('@napi-rs/canvas'),
toDataURL: true,
})

const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDFLatex Image</title>
</head>
<body>
<img alt="Image" src="${result}">
</body>
</html>`
await writeFile(
new URL('artifacts/pdflatex-image.html', import.meta.url),
html,
)

expect(result.startsWith('data:image/png;base64,')).toBe(true)
})

it('supports passing PDFDocumentProxy', async () => {
const pdf = await getDocumentProxy(await getPDF())
const { info } = await getMeta(pdf)
Expand Down