PDF Processing Guide
Overview
This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see REFERENCE.md. If you need to fill out a PDF form, read FORMS.md and follow its instructions.Quick Start
Python Libraries
pypdf - Basic Operations
Merge PDFs
Split PDF
Extract Metadata
Rotate Pages
pdfplumber - Text and Table Extraction
Extract Text with Layout
Extract Tables
Advanced Table Extraction
reportlab - Create PDFs
🚨 MANDATORY RULE — Read before writing any reportlab code Every reportlab script MUST import and callsetup_chinese_pdf()first — even for English-only content. Step 0 — import the helper (this skill ships it asscripts/setup_chinese_pdf.py):If your script is NOT in the skill root directory, use the absolute path toscripts/instead. Then follow these rules:Skipping any of these steps causes every Chinese character to render as a solid black box. There is NO error — the script exits 0 and the PDF looks silently broken. All examples below already follow this pattern. You can use any of them as a starting template.
- Call
cn_font, styles = setup_chinese_pdf()as the very first reportlab operation.- Use the returned
stylesfor allParagraph(...)calls — do NOT callgetSampleStyleSheet()separately.- For any custom
ParagraphStyle, useparent=styles['X']so it inherits the CJK font.- For Canvas API, call
c.setFont(cn_font, size)before everyc.drawString()/c.drawCentredString().- NEVER use
Helvetica,Times-Roman, orCourierfor any text that may contain Chinese.
Basic PDF Creation
Create PDF with Multiple Pages
Chinese / CJK PDF Content
⚠️ IMPORTANT — NEVER fall back to English: If the user asked for Chinese content, the PDF must contain Chinese. Do not replace Chinese content with English and claim it is a “limitation” — that is incorrect behaviour. Follow the instructions below to produce correct Chinese output on every platform.ReportLab’s built-in fonts (Helvetica, Times-Roman, Courier) are Latin-only — they contain no CJK glyphs. Passing Chinese text to these fonts causes characters to silently render as blank spaces or boxes. The script exits with code 0, so there is no error to catch; the PDF simply has no Chinese text. Why intermittent garbling happens — three traps in reportlab:
-
ParagraphStylecopies parent attributes at construction time.ParagraphStyle('X', parent=styles['Title'])copiesfontName='Helvetica-Bold'into the new object’s__dict__immediately. Patching the parent afterwards has no effect on already-created children. Every style that may contain Chinese MUST receivefontName=cn_fontexplicitly, or inherit from an already-patched parent. -
getSampleStyleSheet()returns a new instance every call. Patching one instance does not affect the next call. Sostyles['Normal'].fontName = cn_fontonly works for that onestylesobject. -
TableStyle FONTNAMEis silently ignored for Paragraph cells. When a table cell contains aParagraphobject, the Paragraph’s ownfontNamewins — theTableStyle('FONTNAME', ...)setting has zero effect on it.
setup_chinese_pdf() below. It returns (cn_font, styles) where styles is a pre-patched stylesheet. Use it for ALL text — then Chinese never breaks.
The complete solution — setup_chinese_pdf()
Preferred: import from the pre-built modulescripts/setup_chinese_pdf.py(see MANDATORY RULE above).
Fallback: if importing is not possible (e.g. Windows base64 workflow), copy the function below verbatim into your script.
Source code:scripts/setup_chinese_pdf.py
Using setup_chinese_pdf() — Platypus (Paragraph / Table)
Using setup_chinese_pdf() — Canvas API
CanvasdrawString/drawCentredStringrequires explicitc.setFont(cn_font, size)before every call that contains Chinese. The font is NOT inherited between draw calls.
Windows: write Python scripts without any Chinese in the shell command
On Windows, both PowerShell and CMD interpret the command line before passing it to Python. Their default encoding (GBK / CP936) corrupts Chinese string literals in the shell command before Python ever sees them — even insidepython -c "...".
Do NOT do this (Chinese in the shell string — always breaks on GBK consoles):
Why this works:base64.b64decode(...)is pure ASCII in the shell. The Chinese characters are encoded as\uXXXXUnicode escapes (ASCII-safe) inside the script string, and Python’stextwrap.dedent+ UTF-8encode/decodereconstruct the original Chinese bytes correctly — the console encoding never touches the content.
Rule: On Windows, never put Chinese string literals inside a shell command (python -c "...", PowerShell heredoc, orecho). Always use base64 or Unicode escapes (\uXXXX) to carry non-ASCII content through the shell layer.
Subscripts and Superscripts
IMPORTANT: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes. Instead, use ReportLab’s XML markup tags in Paragraph objects:Command-Line Tools
pdftotext (poppler-utils)
qpdf
pdftk (if available)
Common Tasks
Extract Text from Scanned PDFs
Add Watermark
Extract Images
Password Protection
Quick Reference
Next Steps
- For advanced pypdfium2 usage, see REFERENCE.md
- For JavaScript libraries (pdf-lib), see REFERENCE.md
- If you need to fill out a PDF form, follow the instructions in FORMS.md
- For troubleshooting guides, see REFERENCE.md