Cropping PDF pages sounds like a server-side operation, but with pdf-lib and a <canvas> preview, you can do it entirely in the browser. No upload, no backend, and full control over margins.
This post walks through a minimal but production-ready implementation you can drop into a Vue 3 project.
Why client-side?
Traditional PDF croppers upload your file, crop it on a server, and send it back. That works, but it introduces latency, bandwidth costs, and privacy risk. A browser-based cropper:
- Keeps files on the user’s device
- Works offline after the app loads
- Avoids server-side processing entirely
The stack
- Vue 3 with Composition API
- pdf-lib for PDF manipulation
- PDF.js for page preview rendering
- Canvas for interactive crop region selection
- Vite for bundling
Minimal implementation
<script setup lang="ts">
import { ref } from 'vue'
import { PDFDocument, rgb } from 'pdf-lib'
import * as pdfjs from 'pdfjs-dist'
pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js'
const file = ref<File | null>(null)
const cropping = ref(false)
const margins = ref({ top: 50, bottom: 50, left: 50, right: 50 })
async function handleFileUpload(selected: File) {
file.value = selected
}
async function cropPdf() {
if (!file.value) return
cropping.value = true
try {
const arrayBuffer = await file.value.arrayBuffer()
const pdf = await PDFDocument.load(arrayBuffer)
const pages = pdf.getPages()
for (const page of pages) {
const { width, height } = page.getSize()
const m = margins.value
// Clamp margins to page dimensions
const cropLeft = Math.min(m.left, width / 2 - 1)
const cropRight = Math.min(m.right, width / 2 - 1)
const cropTop = Math.min(m.top, height / 2 - 1)
const cropBottom = Math.min(m.bottom, height / 2 - 1)
page.setCropBox(
cropLeft,
cropBottom,
width - cropLeft - cropRight,
height - cropTop - cropBottom
)
}
const croppedBytes = await pdf.save()
const blob = new Blob([croppedBytes], { type: 'application/pdf' })
downloadBlob(blob, 'cropped.pdf')
} finally {
cropping.value = false
}
}
function downloadBlob(blob: Blob, name: string) {
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = name
a.click()
URL.revokeObjectURL(url)
}
</script>
Enter fullscreen mode Exit fullscreen mode
The key method is page.setCropBox(left, bottom, width, height). It modifies the crop box — the visible area when the page is displayed. Unlike the media box (physical page size), the crop box doesn’t change the underlying content; it just hides what’s outside the visible region.
Interactive crop preview
For a better UX, render the page with PDF.js on a canvas and draw an overlay rectangle showing the crop region. Users can drag the edges of the rectangle to adjust margins visually:
function drawCropOverlay(canvas: HTMLCanvasElement, page: pdfjs.PageViewport) {
const ctx = canvas.getContext('2d')!
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Draw the page
page.draw(ctx).promise.then(() => {
// Draw semi-transparent overlay outside crop region
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
const m = margins.value
// Top strip
ctx.fillRect(0, 0, canvas.width, canvas.height * (m.top / page.height))
// Bottom strip
ctx.fillRect(0, canvas.height * ((page.height - m.bottom) / page.height), canvas.width, canvas.height * (m.bottom / page.height))
// Left strip
ctx.fillRect(0, canvas.height * (m.top / page.height), canvas.width * (m.left / page.width), canvas.height * (1 - (m.top + m.bottom) / page.height))
// Right strip
ctx.fillRect(canvas.width * ((page.width - m.right) / page.width), canvas.height * (m.top / page.height), canvas.width * (m.right / page.width), canvas.height * (1 - (m.top + m.bottom) / page.height))
})
}
Enter fullscreen mode Exit fullscreen mode
UX tips from a live tool
At en.sotool.top/crop-pdf, we learned a few things from real users:
- Provide presets. Most users just want to remove scan borders. Give them a one-click solution.
- Allow page-specific settings. Not every page in a document has the same margins.
- Show a before/after preview. Users need to see the result before downloading.
- Explain the difference between crop and trim. Crop hides content; trim destroys it.
Going further
For simple PDF cropping, pdf-lib plus a canvas preview is enough. If you need batch processing, OCR, or conversion to editable formats, you’ll want a desktop tool.
Want to see the full source? The site is built in public at github.com/sunshey/pdf-tool.
If you need desktop-grade PDF editing — OCR, batch cropping, or advanced export formats — check out Wondershare PDFelement.
답글 남기기