DEV Community

sunshey
sunshey

Posted on

How to Convert PDF to Image in the Browser with Vue 3

Converting PDF pages to images requires careful rendering to balance quality, memory usage, and speed.

Here's how to build a browser-based PDF to image converter with Vue 3.

The challenge: Quality vs performance

PDF to image conversion involves:

  1. Parsing PDF structure
  2. Rendering each page to a canvas
  3. Extracting image data at the desired DPI
  4. Managing memory for large documents

The stack

  • Vue 3 with Composition API
  • pdf.js for PDF parsing and rendering
  • Canvas API for image extraction
  • JSZip for ZIP bundle downloads
  • Vite for bundling

The core implementation

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

pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsLib.version}/pdf.worker.min.js`

const file = ref<File | null>(null)
const pages = ref<any[]>([])
const converting = ref(false)
const progress = ref(0)
const dpi = ref(200)
const format = ref<'png' | 'jpeg'>('png')

async function convertPdfToImages() {
  if (!file.value) return
  converting.value = true
  progress.value = 0

  const arrayBuffer = await file.value.arrayBuffer()
  const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise
  pages.value = []

  const scale = dpi.value / 72
  const total = pdf.numPages

  for (let i = 1; i <= total; i++) {
    const page = await pdf.getPage(i)
    const viewport = page.getViewport({ scale })

    const canvas = document.createElement('canvas')
    canvas.width = viewport.width
    canvas.height = viewport.height
    const ctx = canvas.getContext('2d')!

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

    const mimeType = format.value === 'png' ? 'image/png' : 'image/jpeg'
    const dataUrl = canvas.toDataURL(mimeType, 0.92)
    pages.value.push({ index: i, dataUrl, width: viewport.width, height: viewport.height })

    progress.value = Math.round((i / total) * 100)
  }

  converting.value = false
}

async function downloadZip() {
  const zip = new JSZip()
  pages.value.forEach((page, i) => {
    const ext = format.value === 'png' ? 'png' : 'jpg'
    zip.file(`page-${String(i + 1).padStart(3, '0')}.${ext}`, 
      atob(page.dataUrl.split(',')[1]), { 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()
}
</script>
Enter fullscreen mode Exit fullscreen mode

Key implementation details

1. DPI calculation

PDF.js uses a default scale of 1.0 (72 DPI). To get higher resolution:

const scale = dpi / 72
const viewport = page.getViewport({ scale })
Enter fullscreen mode Exit fullscreen mode

2. Canvas rendering

Render each page sequentially to avoid memory overload:

await page.render({ canvasContext: ctx, viewport }).promise
Enter fullscreen mode Exit fullscreen mode

3. Memory management

Process pages one at a time, not in parallel:

for (let i = 1; i <= total; i++) {
  // render one page
  // then move to next
}
Enter fullscreen mode Exit fullscreen mode

4. ZIP bundling

Use JSZip to bundle all pages into a single download:

const zip = new JSZip()
pages.forEach((page) => {
  zip.file(`page-${index}.${ext}`, base64Data)
})
Enter fullscreen mode Exit fullscreen mode

Limitations

Large files

PDFs with 100+ high-resolution pages may cause memory issues.

Solution: Add a progress bar and process in batches.

Complex PDFs

Some PDFs with custom fonts or encrypted content may not render correctly.

Solution: Show a warning and suggest using desktop software.

Mobile performance

Mobile browsers have less memory and may struggle with large PDFs.

Solution: Limit max DPI or page count on mobile devices.

Summary

Building a browser-based PDF to image converter involves:

  1. Using pdf.js for rendering
  2. Calculating scale for desired DPI
  3. Processing pages sequentially
  4. Bundling results with JSZip

Try it at en.sotool.top/pdf-to-image.

Top comments (0)