name: pdf
description: Process PDF files with Bun-friendly tools: extract text, create PDFs, merge documents, or inspect metadata.
PDF Processing Skill
Prefer command-line PDF tools when available. For programmatic work, use TypeScript packages installed with Bun.
Reading PDFs
Quick Text Extraction
pdftotext input.pdf -
pdftotext input.pdf output.txt
Programmatic Extraction
bun add pdf-parse
import pdf from "pdf-parse";
const data = await pdf(await Bun.file("input.pdf").arrayBuffer());
console.log(`Pages: ${data.numpages}`);
console.log(data.text);
Creating PDFs
From Markdown
pandoc input.md -o output.pdf
pandoc input.md -o output.pdf --pdf-engine=xelatex -V geometry:margin=1in
Programmatically
bun add pdf-lib
import { PDFDocument, StandardFonts } from "pdf-lib";
const doc = await PDFDocument.create();
const page = doc.addPage([612, 792]);
const font = await doc.embedFont(StandardFonts.Helvetica);
page.drawText("Hello, PDF!", { x: 72, y: 720, size: 16, font });
await Bun.write("output.pdf", await doc.save());
Merging PDFs
import { PDFDocument } from "pdf-lib";
const merged = await PDFDocument.create();
for (const path of ["a.pdf", "b.pdf", "c.pdf"]) {
const source = await PDFDocument.load(await Bun.file(path).arrayBuffer());
const pages = await merged.copyPages(source, source.getPageIndices());
pages.forEach((page) => merged.addPage(page));
}
await Bun.write("merged.pdf", await merged.save());
Splitting PDFs
import { PDFDocument } from "pdf-lib";
const source = await PDFDocument.load(await Bun.file("input.pdf").arrayBuffer());
for (const index of source.getPageIndices()) {
const single = await PDFDocument.create();
const [page] = await single.copyPages(source, [index]);
single.addPage(page);
await Bun.write(`page_${index + 1}.pdf`, await single.save());
}
Best Practices
- Use
pdftotext first for plain extraction; it is fast and reliable.
- Use
pdf-lib for create/merge/split workflows.
- Process large PDFs page-by-page when possible.
- Treat scanned PDFs as images; use OCR tooling outside the core Bun harness when text extraction is empty.
- Keep generated PDFs out of commits unless they are intentional fixtures.