DEV Community

sunshey
sunshey

Posted on

How to Check if Your PDF is Ready to Upload in the Browser with Vue 3 and pdf-lib

Every day, thousands of people upload PDFs to websites — job applications, academic submissions, government forms, business proposals. And every day, some of those uploads fail. Not because the PDF is wrong, but because the uploader didn't know the PDF had issues.

Building a browser-based PDF upload checker lets users validate their files locally before submitting them anywhere. Here's how to build one with Vue 3 and pdf-lib.

The problem with post-upload validation

Most platforms validate PDFs after you've already uploaded them. The workflow is:

  1. Upload PDF
  2. Wait for server processing
  3. Get error: "File too large" or "Invalid PDF structure"
  4. Fix the issue
  5. Re-upload
  6. Repeat

This is slow, frustrating, and wastes bandwidth. A client-side checker lets you validate before the upload, eliminating the retry loop.

The stack

  • Vue 3 with Composition API
  • pdf-lib for PDF parsing and analysis
  • 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 analysis = ref<UploadCheckResult | null>(null)
const checking = ref(false)
const error = ref<string | null>(null)

interface UploadCheckResult {
  fileName: string
  fileSize: number
  fileSizeFormatted: string
  pageCount: number
  isEncrypted: boolean
  hasPassword: boolean
  hasBlankPages: boolean
  blankPageIndices: number[]
  hasCorruptedPages: boolean
  corruptedPageIndices: number[]
  hasUnsupportedFonts: boolean
  isReady: boolean
  issues: string[]
}

async function checkPdf() {
  if (!file.value) return
  checking.value = true
  error.value = null

  try {
    const arrayBuffer = await file.value.arrayBuffer()
    const pdf = await PDFDocument.load(arrayBuffer, {
      ignoreEncryption: true,
      updateMetadata: false,
    })

    const pageCount = pdf.getPageCount()
    const isEncrypted = pdf.isEncrypted()
    const hasPassword = false // pdf-lib can't detect password requirement directly

    let blankPages: number[] = []
    let corruptedPages: number[] = []

    for (let i = 0; i < pageCount; i++) {
      try {
        const page = pdf.getPage(i)
        // Check if page has any content
        const content = page.getTextContent?.() ?? []
        if (content.length === 0) {
          // Page might be blank — verify by checking size
          const { width, height } = page.getSize()
          if (width === 0 || height === 0) {
            corruptedPages.push(i + 1)
          } else {
            blankPages.push(i + 1)
          }
        }
      } catch {
        corruptedPages.push(i + 1)
      }
    }

    const issues: string[] = []
    if (isEncrypted) issues.push('PDF is encrypted')
    if (blankPages.length > 0) issues.push(`${blankPages.length} blank page(s): ${blankPages.join(', ')}`)
    if (corruptedPages.length > 0) issues.push(`${corruptedPages.length} corrupted page(s): ${corruptedPages.join(', ')}`)

    analysis.value = {
      fileName: file.value.name,
      fileSize: file.value.size,
      fileSizeFormatted: formatFileSize(file.value.size),
      pageCount,
      isEncrypted,
      hasPassword,
      hasBlankPages: blankPages.length > 0,
      blankPageIndices: blankPages,
      hasCorruptedPages: corruptedPages.length > 0,
      corruptedPageIndices: corruptedPages,
      hasUnsupportedFonts: false, // Would need font analysis for this
      isReady: issues.length === 0,
      issues,
    }
  } catch (e) {
    error.value = e instanceof Error ? e.message : 'Failed to analyze PDF'
  } finally {
    checking.value = false
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Key implementation details

1. ignoreEncryption: true

When loading a potentially problematic PDF, we set ignoreEncryption: true to prevent the loader from failing on encryption metadata. If the PDF is encrypted, we detect this separately via pdf.isEncrypted() rather than letting the load fail.

2. Blank page detection

pdf-lib doesn't have a built-in "is this page blank?" method. We approximate by checking if a page has any text content and has non-zero dimensions:

const content = page.getTextContent?.() ?? []
if (content.length === 0) {
  const { width, height } = page.getSize()
  if (width === 0 || height === 0) {
    corruptedPages.push(i + 1)
  } else {
    blankPages.push(i + 1)
  }
}
Enter fullscreen mode Exit fullscreen mode

This isn't perfect — a page could have images but no text and still appear blank to this check. For production use, rendering to canvas and checking pixel content is more accurate but more expensive.

3. Corrupted page detection

If getPage(i) throws an exception, that page is corrupted or unreadable. We catch these individually so one bad page doesn't prevent analysis of the rest:

for (let i = 0; i < pageCount; i++) {
  try {
    const page = pdf.getPage(i)
    // ... check page content
  } catch {
    corruptedPages.push(i + 1)
  }
}
Enter fullscreen mode Exit fullscreen mode

4. File size formatting

Human-readable file sizes are important for the report:

function formatFileSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`
}
Enter fullscreen mode Exit fullscreen mode

5. What we can't check client-side

Some validation requires server-side analysis:

  • Exact page count limits (we can count pages, but the platform's limit is unknown)
  • Font compatibility (requires deep font analysis)
  • PDF/A compliance (requires professional validation)
  • Platform-specific rules (each platform has different requirements)

The tool should communicate these limitations clearly to the user.


Summary

Building a browser-based PDF upload checker involves:

  1. Loading the PDF with error-tolerant settings
  2. Analyzing file size, page count, encryption status
  3. Checking each page for blank or corrupted content
  4. Generating a clear issue report
  5. Presenting a readiness verdict

The result: users can validate their PDFs locally before uploading, saving time and avoiding submission errors. Try it at en.sotool.top/pdf-upload-checker.

Top comments (0)