DEV Community

jack smith 0909
jack smith 0909

Posted on

How to Convert Images to PDF Entirely in the Browser (No Upload Required)

Most “image to PDF” tools ask you to upload files to a server.

That is fine for a meme screenshot. It is a bad idea for:

  • ID photos
  • contracts
  • invoices
  • school or visa paperwork

If the conversion can happen in the browser, the original images never need to leave the device. This post shows a practical approach using pdf-lib.

Why browser-side conversion?

Pros:

  • Better privacy for sensitive documents
  • Works offline after the page loads
  • No waiting for upload/download round trips
  • Easier to support “one image per page” layouts

Cons:

  • Very large batches can stress low-end phones
  • You depend on the browser’s image decoder (JPG/PNG/WEBP are usually fine)

For many personal and admin workflows, local conversion is the better default.

Core idea

  1. Read each image as bytes in the browser
  2. Embed it into a PDF page with pdf-lib
  3. Export a Blob and trigger download

Install:

npm install pdf-lib
Enter fullscreen mode Exit fullscreen mode

Minimal example: one image → one PDF page

import { PDFDocument } from 'pdf-lib'

async function imageFileToPdf(file) {
  const bytes = new Uint8Array(await file.arrayBuffer())
  const pdf = await PDFDocument.create()

  let image
  if (file.type === 'image/png') {
    image = await pdf.embedPng(bytes)
  } else {
    // jpg/jpeg (and many cameras)
    image = await pdf.embedJpg(bytes)
  }

  // Use the image's own size (in PDF points)
  const page = pdf.addPage([image.width, image.height])
  page.drawImage(image, {
    x: 0,
    y: 0,
    width: image.width,
    height: image.height,
  })

  const pdfBytes = await pdf.save()
  return new Blob([pdfBytes], { type: 'application/pdf' })
}
Enter fullscreen mode Exit fullscreen mode

This already covers a common case: turn a photo into a single-page PDF.

Better UX: multiple images, one image per page

Paperwork almost always needs page order.

async function imagesToPdf(files) {
  const pdf = await PDFDocument.create()

  for (const file of files) {
    const bytes = new Uint8Array(await file.arrayBuffer())

    let image
    if (file.type === 'image/png') {
      image = await pdf.embedPng(bytes)
    } else if (file.type === 'image/jpeg') {
      image = await pdf.embedJpg(bytes)
    } else {
      // For webp/gif/bmp, draw to canvas first, then export PNG/JPEG bytes
      continue
    }

    const page = pdf.addPage([image.width, image.height])
    page.drawImage(image, {
      x: 0,
      y: 0,
      width: image.width,
      height: image.height,
    })
  }

  return new Blob([await pdf.save()], { type: 'application/pdf' })
}
Enter fullscreen mode Exit fullscreen mode

Tip: let users drag to reorder before conversion. Page order matters more than fancy settings.

Optional: fit images onto A4

If the destination is a government form or printer, A4 is often expected.

const A4 = { width: 595.28, height: 841.89 } // points

function fitContain(imgW, imgH, boxW, boxH, margin = 24) {
  const maxW = boxW - margin * 2
  const maxH = boxH - margin * 2
  const scale = Math.min(maxW / imgW, maxH / imgH)
  const width = imgW * scale
  const height = imgH * scale
  return {
    width,
    height,
    x: (boxW - width) / 2,
    y: (boxH - height) / 2,
  }
}
Enter fullscreen mode Exit fullscreen mode

Then draw with those coordinates on an A4 page instead of using the raw pixel size.

Handling WEBP (and other formats)

pdf-lib embeds JPG/PNG directly. For WEBP:

  1. Draw the image onto a <canvas>
  2. Export with canvas.toBlob('image/jpeg') or 'image/png'
  3. Embed the result

That keeps everything client-side.

Product note

I work on OpenPicBox, a set of browser-based image tools. The image-to-PDF flow follows the same idea:

  • mix JPG / PNG / WEBP
  • reorder pages
  • export one image per page
  • choose A4 / Letter / original size
  • conversion stays in the browser

Direct format landings:

If you are building your own tool, start with the snippets above. If you just need the workflow today, try the pages and keep the files on your device.

Top comments (0)