DEV Community

sunshey
sunshey

Posted on

How to Convert PDF Pages to Images with Vue 3 and PDF.js

Rendering PDF pages as images in the browser sounds like a server-side job, but it is not. With PDF.js and a <canvas> element, you can convert each page to a PNG or JPEG entirely on the client side. No upload, no backend processing, and full control over resolution.

This post walks through a minimal but production-ready implementation you can drop into a Vue 3 project.

Why client-side?

Traditional PDF-to-image services upload your file, render it on a server, and send back images. That works, but it introduces latency, bandwidth costs, and privacy risk. A browser-based converter:

  • Keeps files on the user's device
  • Works offline after the app loads
  • Avoids server-side rendering entirely

The stack

  • Vue 3 with Composition API
  • PDF.js (pdfjs-dist) for rendering
  • HTML5 Canvas for image generation
  • JSZip for packaging multiple images
  • Vite for bundling

Minimal implementation

<script setup lang="ts">
import { ref } from 'vue'
import * as pdfjs from 'pdfjs-dist'
import JSZip from 'jszip'

pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js'

const file = ref<File | null>(null)
const converting = ref(false)
const images = ref<string[]>([])
const format = ref<'png' | 'jpeg'>('png')
const dpi = ref(150)

async function handleFileUpload(selected: File) {
  file.value = selected
}

async function convertToImages() {
  if (!file.value) return

  converting.value = true
  images.value = []

  try {
    const arrayBuffer = await file.value.arrayBuffer()
    const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise

    for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
      const page = await pdf.getPage(pageNum)
      const viewport = page.getViewport({ scale: dpi.value / 72 })

      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      if (!ctx) continue

      canvas.width = viewport.width
      canvas.height = viewport.height

      await page.render({ canvasContext: ctx, viewport }).promise

      const dataUrl = canvas.toDataURL(
        format.value === 'png' ? 'image/png' : 'image/jpeg',
        0.92
      )
      images.value.push(dataUrl)
    }
  } finally {
    converting.value = false
  }
}

async function downloadZip() {
  const zip = new JSZip()
  images.value.forEach((dataUrl, i) => {
    const base64 = dataUrl.split(',')[1]
    zip.file(`page-${i + 1}.${format.value}`, base64, { base64: true })
  })

  const blob = await zip.generateAsync({ type: 'blob' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'pdf-pages.zip'
  a.click()
  URL.revokeObjectURL(url)
}
</script>
Enter fullscreen mode Exit fullscreen mode

The key is page.getViewport({ scale: dpi.value / 72 }). PDF.js uses 72 DPI as its base scale, so dividing your target DPI by 72 gives the correct canvas size for the resolution you want.

Handling large files

Browser memory is the main constraint. For a production tool, add two limits:

const MAX_SIZE = 100 * 1024 * 1024 // 100 MB
const MAX_PAGES = 200
Enter fullscreen mode Exit fullscreen mode

Validate before loading into PDF.js. High-DPI rendering of large pages can produce very large canvases, so you may also want to cap the maximum pixel dimensions.

UX tips from a live tool

At en.sotool.top/pdf-to-image, we learned a few things from real users:

  1. Let users choose format and DPI. Some want PNG transparency, others want small JPEGs. Some need 300 DPI for print.
  2. Show page previews. Users want to confirm the conversion looks right before downloading.
  3. Offer a ZIP download. Individual image downloads are tedious for multi-page documents.
  4. Separate "completed" from "downloaded." Track both events separately so you can measure drop-off between processing success and the actual save.

Tracking the funnel

We use GA4 custom events:

onFileUpload(file)
onActionClick('convert-to-image')
onCompleted({ output_format: format.value, dpi: dpi.value })
onDownload({ file_count: images.value.length })
Enter fullscreen mode Exit fullscreen mode

This lets us see exactly where users drop off: upload, action click, completion, or download.

Going further

For simple PDF-to-image conversion, PDF.js plus Canvas is enough. If you need OCR, batch automation, or direct editable text export, you'll want a server-side component or a desktop tool.

Want to see the full source? The site is built in public at github.com/sunshey/pdf-tool (replace with your actual repo if different).


If you need desktop-grade PDF editing — OCR, batch conversion, or advanced export formats — check out Wondershare PDFelement.

Top comments (0)