| name | pdf-manipulation |
| description | Manipulate PDF files including merge, split, extract, redact, convert, and secure workflows. |
PDF Manipulation Skill
Merge, split, extract, redact, and transform PDF files using free command-line tools and libraries. Covers common PDF operations for document automation workflows.
When to use
- Merge multiple PDFs into one document
- Split large PDFs into separate files or page ranges
- Extract text, images, or specific pages
- Redact sensitive information
- Add watermarks, passwords, or metadata
- Convert PDFs to images or other formats
Required tools
- pdftk — Swiss Army knife for PDF manipulation (merge, split, rotate, encrypt)
- qpdf — PDF transformation and encryption (linearize, decrypt, repair)
- pdftotext / pdfimages — Part of poppler-utils (extract text and images)
- ghostscript (gs) — Advanced PDF processing, compression, and conversion
Installation
sudo apt-get install pdftk qpdf poppler-utils ghostscript
brew install pdftk-java qpdf poppler ghostscript
Skills
Merge PDFs
pdftk file1.pdf file2.pdf file3.pdf cat output merged.pdf
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=merged.pdf file1.pdf file2.pdf file3.pdf
qpdf --empty --pages file1.pdf file2.pdf file3.pdf -- merged.pdf
Node.js (pdf-lib):
const { PDFDocument } = require('pdf-lib');
const fs = require('fs');
async function mergePDFs(files, output) {
const mergedPdf = await PDFDocument.create();
for (const file of files) {
const pdfBytes = fs.readFileSync(file);
const pdf = await PDFDocument.load(pdfBytes);
const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
pages.forEach(page => mergedPdf.addPage(page));
}
const mergedBytes = await mergedPdf.save();
fs.writeFileSync(output, mergedBytes);
}
Split PDF (by page or range)
pdftk input.pdf burst output page_%02d.pdf
pdftk input.pdf cat 1-5 10 output subset.pdf
qpdf input.pdf --pages . 1-5 -- output.pdf
pdftk input.pdf burst
Node.js (pdf-lib):
const { PDFDocument } = require('pdf-lib');
const fs = require('fs');
async function extractPages(inputPath, pages, outputPath) {
const pdfBytes = fs.readFileSync(inputPath);
const pdfDoc = await PDFDocument.load(pdfBytes);
const newPdf = await PDFDocument.create();
for (const pageNum of pages) {
const [page] = await newPdf.copyPages(pdfDoc, [pageNum - 1]);
newPdf.addPage(page);
}
const newBytes = await newPdf.save();
fs.writeFileSync(outputPath, newBytes);
}
Extract text
pdftotext input.pdf output.txt
pdftotext -raw input.pdf output.txt
pdftotext -f 1 -l 5 input.pdf output.txt
pdftotext -layout input.pdf -
Node.js (pdf-parse):
const fs = require('fs');
const pdf = require('pdf-parse');
async function extractText(filePath) {
const dataBuffer = fs.readFileSync(filePath);
const data = await pdf(dataBuffer);
return data.text;
}
Extract images
pdfimages -all input.pdf output_prefix
pdfimages -j input.pdf output_prefix
Redact / Remove pages
pdftk input.pdf cat 1 5-end output redacted.pdf
pdftk input.pdf cat 1-10 20-30 output selected.pdf
Add password protection
pdftk input.pdf output secured.pdf user_pw mypassword
pdftk secured.pdf input_pw mypassword output unlocked.pdf
qpdf --encrypt userpass ownerpass 256 -- input.pdf output.pdf
Node.js (pdf-lib):
const { PDFDocument } = require('pdf-lib');
const fs = require('fs');
async function encryptPDF(inputPath, password, outputPath) {
const pdfBytes = fs.readFileSync(inputPath);
const pdfDoc = await PDFDocument.load(pdfBytes);
const encryptedBytes = await pdfDoc.save({
userPassword: password,
ownerPassword: password
});
fs.writeFileSync(outputPath, encryptedBytes);
}
Rotate pages
pdftk input.pdf cat 1-endright output rotated.pdf
pdftk input.pdf cat 1-5 6right 7-end output rotated.pdf
Compress / Reduce file size
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook \
-dNOPAUSE -dQUIET -dBATCH -sOutputFile=compressed.pdf input.pdf
qpdf --linearize --object-streams=generate input.pdf compressed.pdf
Convert PDF to images
pdftoppm -png -r 300 input.pdf output_prefix
pdftoppm -jpeg -r 150 input.pdf output_prefix
convert -density 300 input.pdf output_%03d.png
Add watermark
pdftk input.pdf stamp watermark.pdf output watermarked.pdf
pdftk input.pdf background watermark.pdf output watermarked.pdf
pdftk input.pdf multistamp watermark.pdf output watermarked.pdf
Get PDF metadata
pdftk input.pdf dump_data
qpdf --show-object=1 input.pdf
pdfinfo input.pdf
Multi-operation script (Node.js)
const { PDFDocument } = require('pdf-lib');
const fs = require('fs');
class PDFHelper {
static async merge(files, output) {
const merged = await PDFDocument.create();
for (const file of files) {
const pdf = await PDFDocument.load(fs.readFileSync(file));
const pages = await merged.copyPages(pdf, pdf.getPageIndices());
pages.forEach(p => merged.addPage(p));
}
fs.writeFileSync(output, await merged.save());
}
static async split(input, ranges, output) {
const pdf = await PDFDocument.load(fs.readFileSync(input));
const newPdf = await PDFDocument.create();
const pages = await newPdf.copyPages(pdf, ranges);
pages.forEach(p => newPdf.addPage(p));
fs.writeFileSync(output, await newPdf.save());
}
static async info(input) {
const pdf = await PDFDocument.load(fs.readFileSync(input));
return {
pages: pdf.getPageCount(),
title: pdf.getTitle(),
author: pdf.getAuthor(),
creator: pdf.getCreator()
};
}
}
module.exports = PDFHelper;
Agent prompt
You have PDF manipulation skills. When a user requests PDF operations:
1. Detect the operation: merge, split, extract (text/images/pages), redact, compress, encrypt, rotate, watermark, or get info.
2. Use appropriate tools:
- pdftk for merge, split, rotate, encrypt, watermark
- pdftotext/pdfimages for extraction
- ghostscript for compression
- qpdf for repair and advanced operations
3. Always validate input files exist before processing.
4. For scripting, prefer pdf-lib (Node.js) or PyPDF2 (Python) for portability.
5. Return structured output (file paths, metadata, text) in JSON format.
Best practices
- Validate PDFs before processing (use
qpdf --check input.pdf).
- Preserve metadata when possible (use pdftk or pdf-lib, avoid ghostscript for simple operations).
- Use appropriate compression — ghostscript
/ebook is a good balance for most cases.
- Security — Always remove passwords before processing if user provides them; never log passwords.
- Large files — For 100+ page PDFs, process in chunks or use streaming APIs.
Common workflows
Invoice processing
pdftotext invoice.pdf invoice.txt
pdftk invoice.pdf cat 1 output summary.pdf
gs -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -dBATCH -dNOPAUSE -q \
-sOutputFile=invoice_compressed.pdf invoice.pdf
Batch processing
pdftk *.pdf cat output combined.pdf
for f in *.pdf; do
pdftk "$f" burst output "${f%.pdf}_page_%02d.pdf"
done
for f in *.pdf; do
pdftotext "$f" "${f%.pdf}.txt"
done
Troubleshooting
- Corrupted PDF: Use
qpdf --check then qpdf input.pdf --replace-input to repair.
- Encrypted PDF: Remove password first with
qpdf --decrypt --password=PASS input.pdf output.pdf.
- Large file size: Use ghostscript compression or remove embedded fonts/images if not needed.
- Missing fonts: Install
fonts-liberation or msttcorefonts packages.
See also