name: processing-pdf description: Reads, creates, and modifies PDF files — extracts text and tables, builds new PDFs, merges, splits, rotates, watermarks, encrypts/decrypts, and fills PDF forms. Use when the user asks to read, extract, parse, create, generate, merge, combine, split, rotate, watermark, password-protect, decrypt, or fill a PDF, mentions a .pdf file, or asks to pull text or tables out of a PDF. Do not use for Word documents, images, or converting Office files to PDF (use the corresponding Office skill and export).
Processing PDF
When to use / when NOT to use
- Use for: any operation where a
.pdffile is the input or the output — extraction, creation, page manipulation, forms, encryption. - Do NOT use for: Word documents (
.docx), images, or converting Office files to PDF — use the corresponding Office skill and export instead.
Quick reference — one default per operation
Extract text/tables — pdfplumber:
python
import pdfplumber
with pdfplumber.open("in.pdf") as pdf:
text = "\n".join(p.extract_text() or "" for p in pdf.pages)
tables = pdf.pages[0].extract_tables()Escape hatch: if output is garbled or misordered, use pdftotext -layout in.pdf out.txt (poppler-utils). If pages yield no text at all, the PDF is scanned — OCR it with pytesseract + pdf2image (see recipes).
Page operations (merge/split/rotate/encrypt) and form filling — pypdf:
python
from pypdf import PdfReader, PdfWriter
writer = PdfWriter()
for path in ["a.pdf", "b.pdf"]:
writer.append(path) # merge
writer.write("merged.pdf")Create new PDFs — reportlab (Platypus):
python
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
styles = getSampleStyleSheet()
SimpleDocTemplate("out.pdf", pagesize=letter).build(
[Paragraph("Title", styles["Title"]), Paragraph("Body text.", styles["Normal"])])Workflow
- Identify the operation (extract / create / modify / form-fill) and pick the default tool above.
- Run the operation with the minimal code needed; write output next to the input unless the user names a path.
- Validate: re-open the output with
PdfReader("out.pdf")and checklen(reader.pages)matches expectations; for extraction, confirm the text/tables are non-empty before reporting success. - If validation fails, fix and repeat step 2 — never deliver an unverified file.
- Report the output path and a one-line summary (page count, or rows/chars extracted).
Edge cases & failure modes
- Missing dependency → install exactly:
pip install pdfplumber pypdf reportlab. - Corrupt/malformed PDF → report the parser's error message verbatim (it names the object/offset); do not guess at contents.
- Encrypted PDF →
PdfReader(path)raises orreader.is_encryptedis True; callreader.decrypt(password)— ask the user for the password, never brute-force. - Scanned PDF (no text layer) →
extract_text()returns None/empty; switch to OCR (recipes) and tell the user accuracy depends on scan quality. - Huge PDF → process page-by-page (pdfplumber pages are lazy); never load all text into one string above ~1,000 pages.
- Empty file (0 bytes) → report "file is empty, not a valid PDF" and stop.
References
Deeper copy-paste recipes (watermark, split, encrypt, forms, OCR, conversion): see references/recipes.md.