Adding watermarks to PDFs in the browser involves positioning, opacity control, and handling both text and image watermarks. Here's how to build a browser-based PDF watermark tool with Vue 3 and pdf-lib.
The challenge: Positioning and opacity
Watermark implementation requires:
- Drawing text or images on each page
- Controlling opacity for subtle background effects
- Supporting rotation and positioning
- Handling both text and image watermarks
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, rgb, StandardFonts } from 'pdf-lib'
const file = ref<File | null>(null)
const watermarkText = ref('CONFIDENTIAL')
const opacity = ref(0.2)
const rotation = ref(45)
const watermarking = ref(false)
const result = ref<Uint8Array | null>(null)
async function addWatermark() {
if (!file.value) return
watermarking.value = true
const arrayBuffer = await file.value.arrayBuffer()
const pdf = await PDFDocument.load(arrayBuffer)
const pages = pdf.getPages()
const font = await pdf.embedFont(StandardFonts.Helvetica)
for (const page of pages) {
const { width, height } = page.getSize()
page.drawText(watermarkText.value, {
x: width / 2 - 100,
y: height / 2,
size: 50,
font,
color: rgb(0.5, 0.5, 0.5),
opacity: opacity.value,
rotate: { type: 'degrees', angle: rotation.value },
})
}
result.value = await pdf.save()
watermarking.value = false
}
</script>
Key implementation details
1. Text watermark
Use pdf-lib's drawText with opacity and rotation:
page.drawText(text, {
x: width / 2 - textWidth / 2,
y: height / 2,
size: 50,
font,
color: rgb(0.5, 0.5, 0.5),
opacity: 0.2,
rotate: { type: 'degrees', angle: 45 },
})
2. Image watermark
For image watermarks, embed and draw the image:
const imageData = await file.arrayBuffer()
const image = await pdf.embedPng(imageData)
const { width, height } = page.getSize()
page.drawImage(image, {
x: 0,
y: 0,
width: width * 0.5,
height: height * 0.5,
opacity: opacity.value,
})
3. Multi-page application
Apply watermark to all pages or specific pages:
const pages = pdf.getPages()
for (const page of pages) {
// Apply watermark to each page
}
4. Opacity control
pdf-lib supports opacity in the 0-1 range:
opacity: Number(opacity.value) // 0.0 to 1.0
Limitations
No real-time preview
pdf-lib doesn't support real-time preview without rendering.
Solution: Show a static preview or render thumbnails separately.
Limited positioning options
Basic text positioning is supported, but complex layouts may need more.
Solution: Calculate positions based on page dimensions.
Large files
Very large PDFs may cause memory issues.
Solution: Process in smaller batches or use Web Workers.
Summary
Building a browser-based PDF watermark tool involves:
- Loading the PDF with pdf-lib
- Drawing text or images on each page
- Controlling opacity and rotation
- Saving and downloading the watermarked PDF
Try it at en.sotool.top/watermark.