Extract, manipulate, and generate PDF documents using secure Python-based workflows.

Install

mkdir -p .claude/skills/pdf-sam-cogan && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10540" && unzip -o skill.zip -d .claude/skills/pdf-sam-cogan && rm skill.zip

Installs to .claude/skills/pdf-sam-cogan

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Read, extract, create, merge, split, rotate, watermark, encrypt, OCR, or fill forms in PDF files. Triggers: any mention of \".pdf\", \"PDF\", or requests to extract text/tables from PDFs, combine/merge PDFs, split pages, create new PDFs, fill PDF forms, add watermarks, encrypt/decrypt, extract images, or OCR scanned documents. Do NOT use for Word documents (use docx skill), spreadsheets (use xlsx skill), or PowerPoint files.
428 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Extract text and tables from PDF files
  • Merge multiple PDF documents into one
  • Split a PDF into individual page files
  • Add watermarks to PDF pages
  • Encrypt or decrypt PDF files
  • Perform OCR on scanned PDF documents

How it works

The skill uses Python libraries like pypdf and pdfplumber to perform various PDF operations, and it manages a virtual environment for dependency isolation.

Inputs & outputs

You give it
PDF file path and desired operation
You get back
Modified PDF file, extracted text/tables, or image files

When to use pdf

  • Merging PDF files
  • Extracting data from documents
  • Encrypting sensitive PDFs

About this skill

PDF Processing Guide

Python Environment — MANDATORY

All Python scripts in this skill MUST run inside a virtual environment. No exceptions.

# Create venv (once per session, skip if .venv already exists)
python -m venv .venv

# Activate (Windows PowerShell)
.venv\Scripts\Activate.ps1

# Activate (bash/macOS)
source .venv/bin/activate

# Install dependencies INSIDE venv only
pip install pypdf pdfplumber reportlab

# For OCR (only if needed)
pip install pytesseract pdf2image

# For advanced rendering (only if needed)
pip install pypdfium2

Rules:

  • NEVER run pip install globally — always activate .venv first
  • Check if .venv exists before creating: Test-Path .venv
  • All python scripts/... commands assume the venv is active
  • Clean up .venv when the session is done if it was created for this task

Temp file cleanup — MANDATORY:

  • All temp scripts MUST use .tmp_ prefix (e.g., .tmp_merge_pdfs.py)
  • After the task completes, delete ALL .tmp_* files autonomously — never leave them behind, never ask the user
  • Remove-Item is deny-listed in auto-approval mode. Use Python instead:
    .venv\Scripts\python.exe -c "import os,glob; [os.remove(f) for f in glob.glob('.tmp_*')]"
    
  • If no .venv exists, use system python -c "..."

Overview

This guide covers PDF processing using Python libraries and command-line tools. For advanced features and JavaScript libraries, see reference.md. For PDF form filling, see forms.md.

Output directory: Save generated/merged/split .pdf files to the Obsidian vault (see shared-patterns.instructions.md § Artifact Output Directory). Create directories before writing. Never save into a git repo.

Note: scripts/ paths are relative to this skill folder (.github/skills/pdf/).

Quick Reference

TaskBest ToolKey Code
Read/extract textpdfplumberpage.extract_text()
Extract tablespdfplumberpage.extract_tables()
Merge PDFspypdfwriter.add_page(page)
Split PDFspypdfOne page per file
Create PDFsreportlabCanvas or Platypus
Rotate pagespypdfpage.rotate(90)
Add watermarkpypdfpage.merge_page(watermark)
Encrypt/decryptpypdfwriter.encrypt()
OCR scanned PDFspytesseractConvert to image first
Fill PDF formsSee forms.mdFillable or annotation-based
Command-line mergeqpdfqpdf --empty --pages ...

Reading & Extracting

Quick Start

from pypdf import PdfReader

reader = PdfReader("document.pdf")
print(f"Pages: {len(reader.pages)}")

text = ""
for page in reader.pages:
    text += page.extract_text()

Text with Layout (pdfplumber)

import pdfplumber

with pdfplumber.open("document.pdf") as pdf:
    for page in pdf.pages:
        text = page.extract_text()
        print(text)

Extract Tables

import pdfplumber

with pdfplumber.open("document.pdf") as pdf:
    for i, page in enumerate(pdf.pages):
        tables = page.extract_tables()
        for j, table in enumerate(tables):
            print(f"Table {j+1} on page {i+1}:")
            for row in table:
                print(row)

Tables to Excel

import pdfplumber
import pandas as pd

with pdfplumber.open("document.pdf") as pdf:
    all_tables = []
    for page in pdf.pages:
        tables = page.extract_tables()
        for table in tables:
            if table:
                df = pd.DataFrame(table[1:], columns=table[0])
                all_tables.append(df)

if all_tables:
    combined_df = pd.concat(all_tables, ignore_index=True)
    combined_df.to_excel("extracted_tables.xlsx", index=False)

Extract Metadata

reader = PdfReader("document.pdf")
meta = reader.metadata
print(f"Title: {meta.title}, Author: {meta.author}, Pages: {len(reader.pages)}")

Merging & Splitting

Merge PDFs

from pypdf import PdfWriter, PdfReader

writer = PdfWriter()
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
    reader = PdfReader(pdf_file)
    for page in reader.pages:
        writer.add_page(page)

with open("merged.pdf", "wb") as output:
    writer.write(output)

Split PDF

from pypdf import PdfReader, PdfWriter

reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
    writer = PdfWriter()
    writer.add_page(page)
    with open(f"page_{i+1}.pdf", "wb") as output:
        writer.write(output)

Page Manipulation

Rotate Pages

from pypdf import PdfReader, PdfWriter

reader = PdfReader("input.pdf")
writer = PdfWriter()
page = reader.pages[0]
page.rotate(90)  # 90 degrees clockwise
writer.add_page(page)

with open("rotated.pdf", "wb") as output:
    writer.write(output)

Add Watermark

from pypdf import PdfReader, PdfWriter

watermark = PdfReader("watermark.pdf").pages[0]
reader = PdfReader("document.pdf")
writer = PdfWriter()

for page in reader.pages:
    page.merge_page(watermark)
    writer.add_page(page)

with open("watermarked.pdf", "wb") as output:
    writer.write(output)

Creating PDFs (reportlab)

Basic PDF

from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas

c = canvas.Canvas("hello.pdf", pagesize=letter)
width, height = letter
c.drawString(100, height - 100, "Hello World!")
c.line(100, height - 140, 400, height - 140)
c.save()

Multi-Page Report

from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet

doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = []

story.append(Paragraph("Report Title", styles['Title']))
story.append(Spacer(1, 12))
story.append(Paragraph("Body content here. " * 20, styles['Normal']))
story.append(PageBreak())
story.append(Paragraph("Page 2", styles['Heading1']))

doc.build(story)

Subscripts and Superscripts

IMPORTANT: Never use Unicode subscript/superscript characters in ReportLab. They render as black boxes. Use XML markup instead:

from reportlab.platypus import Paragraph
from reportlab.lib.styles import getSampleStyleSheet
styles = getSampleStyleSheet()

chemical = Paragraph("H<sub>2</sub>O", styles['Normal'])
squared = Paragraph("x<super>2</super>", styles['Normal'])

Security

Encrypt PDF

from pypdf import PdfReader, PdfWriter

reader = PdfReader("input.pdf")
writer = PdfWriter()
for page in reader.pages:
    writer.add_page(page)

writer.encrypt("userpassword", "ownerpassword")
with open("encrypted.pdf", "wb") as output:
    writer.write(output)

OCR (Scanned PDFs)

# Requires: pip install pytesseract pdf2image
# Also requires Tesseract OCR engine installed on system
import pytesseract
from pdf2image import convert_from_path

images = convert_from_path('scanned.pdf')
text = ""
for i, image in enumerate(images):
    text += f"Page {i+1}:\n"
    text += pytesseract.image_to_string(image)
    text += "\n\n"

Extract Images

# Using pdfimages (poppler-utils)
pdfimages -j input.pdf output_prefix
# Extracts as output_prefix-000.jpg, output_prefix-001.jpg, etc.

Command-Line Tools

qpdf

qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf     # Merge
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf               # Extract pages
qpdf input.pdf output.pdf --rotate=+90:1                    # Rotate page 1
qpdf --password=mypassword --decrypt encrypted.pdf out.pdf  # Decrypt

pdftotext (poppler-utils)

pdftotext input.pdf output.txt            # Extract text
pdftotext -layout input.pdf output.txt    # Preserve layout
pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5 only

PDF Form Filling

For form filling workflows, read forms.md — it covers both fillable (AcroForm) and non-fillable (annotation-based) approaches with helper scripts.


Next Steps

  • reference.md — Advanced pypdfium2, pdf-lib (JS), pdfjs-dist
  • forms.md — Complete form filling workflow with validation

When not to use it

  • Working with Word documents
  • Working with spreadsheet files
  • Working with PowerPoint files

Limitations

  • Requires a Python virtual environment for all script execution
  • Temporary files must use a specific prefix and be deleted after use
  • Does not support Word, Excel, or PowerPoint documents

How it compares

This skill automates PDF processing tasks using Python scripts within a managed virtual environment, unlike manual operations or separate tools for each function.

Compared to similar skills

pdf side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
pdf (this skill)04moReviewIntermediate
pdf-processing-pro179moReviewIntermediate
data-engineering137moReviewAdvanced
crawl4ai218moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry