Skip to main content

PDF to PNG API & Developer Guide

How to integrate PDF-to-PNG conversion into your own app — entirely client-side, with no server and no API keys.

Hosted API Coming Soon

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.

Why Client-Side Conversion?

Private by design

Files never leave the user’s device — no upload, no storage.

Zero server cost

No backend to run or scale; conversion uses the client’s CPU.

No API keys

Just an npm install and a worker file — nothing to authenticate.

1. Install PDF.js

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.

2. Render One Page to PNG

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;
}

3. Convert Every Page

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;
}

Implementation Notes

  • DPI to scale: PDFs are defined at 72 DPI, so a scale of dpi / 72 gives the resolution you want (e.g. 300 DPI → scale 4.17).
  • Memory: call page.cleanup() after each page and reuse a single canvas to keep memory flat on long documents.
  • Transparency: pass background: 'rgba(0,0,0,0)' to page.render() and create the context with { alpha: true } for a transparent PNG.
  • Version pinning: the worker file must match the installed pdfjs-dist version exactly.

Documentation Resources

Developer FAQ

Is there a hosted REST API I can call?

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.

Why convert on the client instead of a server?

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.

Which PDF.js version should I pin?

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.

Can I run this in Node.js?

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.