DEV Community

sunshey
sunshey

Posted on

How to Split PDF Files in the Browser with Vue 3 and pdf-lib

Splitting PDF files in the browser requires careful handling of page ranges and memory management. Here's how to build a browser-based PDF split tool with Vue 3 and pdf-lib.

The challenge: Managing page ranges

When splitting PDFs, you need to:

  1. Support multiple split modes (by range, by count, by selection)
  2. Handle large PDFs without memory issues
  3. Provide clear preview of split results
  4. Preserve document structure where possible

The stack

  • Vue 3 with Composition API
  • pdf-lib for PDF manipulation
  • Vite for bundling

The core implementation

<script setup lang="ts">
import { ref } from 'vue'
import { PDFDocument } from 'pdf-lib'

const file = ref<File | null>(null)
const splitMode = ref<'range' | 'count' | 'custom'>('range')
const splitRanges = ref<{ start: number; end: number }[]>([])
const splitting = ref(false)
const results = ref<Array<{ name: string; data: Uint8Array }>>([])

async function splitPdf() {
  if (!file.value) return
  splitting.value = true

  const arrayBuffer = await file.value.arrayBuffer()
  const sourcePdf = await PDFDocument.load(arrayBuffer)
  const totalPages = sourcePdf.getPageCount()
  results.value = []

  for (const range of splitRanges.value) {
    const newPdf = await PDFDocument.create()
    const indices = Array.from(
      { length: range.end - range.start + 1 },
      (_, i) => range.start + i
    )
    const pages = await newPdf.copyPages(sourcePdf, indices)
    pages.forEach(page => newPdf.addPage(page))

    results.value.push({
      name: `split_${range.start + 1}-${range.end + 1}.pdf`,
      data: await newPdf.save(),
    })
  }

  splitting.value = false
}
</script>
Enter fullscreen mode Exit fullscreen mode

Key implementation details

1. Page index conversion

pdf-lib uses 0-based indexing, but users think in 1-based:

const indices = Array.from(
  { length: range.end - range.start + 1 },
  (_, i) => range.start + i  // Convert 1-based to 0-based
)
Enter fullscreen mode Exit fullscreen mode

2. Copying pages between PDFs

const pages = await newPdf.copyPages(sourcePdf, indices)
pages.forEach(page => newPdf.addPage(page))
Enter fullscreen mode Exit fullscreen mode

3. Multiple output files

Store results as named Uint8Array pairs:

results.value.push({
  name: `split_${start}-${end}.pdf`,
  data: await newPdf.save(),
})
Enter fullscreen mode Exit fullscreen mode

4. Memory management

Process pages sequentially to avoid memory issues:

for (const range of splitRanges.value) {
  const newPdf = await PDFDocument.create()
  // ... process range ...
  results.value.push({ name, data })
}
Enter fullscreen mode Exit fullscreen mode

Limitations

No undo

Once split, original pages are distributed across files.

Solution: Always keep the original PDF.

Large files

Very large PDFs may cause memory issues when loading all pages.

Solution: Process in smaller batches.

Password-protected PDFs

Encrypted PDFs cannot be split without the password.

Solution: Remove encryption first.

Summary

Building a browser-based PDF split tool involves:

  1. Loading the source PDF with pdf-lib
  2. Validating page ranges (1-based to 0-based)
  3. Copying pages to new PDFDocument instances
  4. Returning multiple download links

Try it at en.sotool.top/split.

Top comments (0)