How to integrate PDF-to-PNG conversion into your own app — entirely client-side, with no server and no API keys.
We’re developing a hosted REST API. Until it ships, the guide below shows how to do the exact same conversion this site uses — directly in the browser with the open-source PDF.js library.
Files never leave the user’s device — no upload, no storage.
No backend to run or scale; conversion uses the client’s CPU.
Just an npm install and a worker file — nothing to authenticate.
npm install pdfjs-dist
Self-host the worker file from node_modules/pdfjs-dist/build/pdf.worker.min.js so its version always matches the library and conversion keeps working offline.
import * as pdfjsLib from 'pdfjs-dist';
// Point the worker at your self-hosted copy (must match the library version)
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js';
async function pdfPageToPng(file, pageNumber = 1, dpi = 150) {
const data = new Uint8Array(await file.arrayBuffer());
const pdf = await pdfjsLib.getDocument({ data }).promise;
const page = await pdf.getPage(pageNumber);
// 72 DPI is the PDF baseline, so scale = dpi / 72
const viewport = page.getViewport({ scale: dpi / 72 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = viewport.width;
canvas.height = viewport.height;
await page.render({ canvasContext: context, viewport }).promise;
const blob = await new Promise((resolve) =>
canvas.toBlob(resolve, 'image/png')
);
page.cleanup();
await pdf.destroy();
return blob;
}async function pdfToPngBlobs(file, dpi = 150, onProgress) {
const data = new Uint8Array(await file.arrayBuffer());
const pdf = await pdfjsLib.getDocument({ data }).promise;
const blobs = [];
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
for (let n = 1; n <= pdf.numPages; n++) {
const page = await pdf.getPage(n);
const viewport = page.getViewport({ scale: dpi / 72 });
canvas.width = viewport.width;
canvas.height = viewport.height;
await page.render({ canvasContext: context, viewport }).promise;
blobs.push(await new Promise((r) => canvas.toBlob(r, 'image/png')));
page.cleanup();
onProgress?.(n, pdf.numPages);
}
await pdf.destroy();
return blobs;
}dpi / 72 gives the resolution you want (e.g. 300 DPI → scale 4.17).page.cleanup() after each page and reuse a single canvas to keep memory flat on long documents.background: 'rgba(0,0,0,0)' to page.render() and create the context with { alpha: true } for a transparent PNG.pdfjs-dist version exactly.Not yet — a hosted API is on our roadmap. Today, the recommended approach is client-side conversion with PDF.js, shown below. It is free, requires no API keys, and keeps user files private because nothing is uploaded.
Client-side conversion means user documents never leave their device, you have no file storage or bandwidth costs, and there is no server to scale. The trade-off is that conversion uses the visitor’s CPU, which is fine for typical documents.
Pin a specific version (for example pdfjs-dist 3.11.x) and make sure the worker file you load matches that exact version. A mismatch between the library and worker is the most common source of runtime errors.
PDF.js targets the browser and depends on the Canvas API. To run it server-side in Node you need a canvas polyfill such as the node-canvas package, plus the legacy build of pdfjs-dist. For most use cases, running it in the browser is simpler.
Discover other tools and guides to enhance your PDF workflow