fpdf2
Lightweight PDF generation library for Python — pure Python, no external dependencies, creates PDF documents programmatically. fpdf2 features: FPDF class with add_page()/set_font()/cell()/multi_cell()/text() methods, image embedding (JPEG/PNG/GIF/WEBP), table support (Table class for complex tables), header/footer via inherited class methods, automatic page breaks, links (internal and external), TrueType font embedding, SVG support, HTML2FPDF for basic HTML rendering, output() to file or bytes, ArcAnnotation/Highlight for annotations, and templates for recurring layouts. Simpler than reportlab, no dependencies.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Pure Python PDF library. Image embedding: validate image sources. User-controlled text in PDFs: sanitize to prevent PDF injection (though fpdf2 treats all text as literal). Font files from trusted sources only. output() returns unencrypted PDF — add password protection separately if needed.
⚡ Reliability
Best When
Simple PDF generation without system dependencies — fpdf2 is pure Python with no C library requirements, ideal for simple reports, certificates, and invoices in constrained environments.
Avoid When
HTML-to-PDF conversion (use weasyprint), complex multi-column layouts (use reportlab), editing existing PDFs (use pikepdf), or when rich CSS styling needed.
Use Cases
- • Agent simple PDF — from fpdf import FPDF; pdf = FPDF(); pdf.add_page(); pdf.set_font('Helvetica', size=12); pdf.cell(200, 10, text='Hello World', new_x='LMARGIN', new_y='NEXT'); pdf.output('hello.pdf') — basic PDF; agent creates simple text PDF without dependencies; cell() creates text box
- • Agent invoice PDF — pdf = FPDF(); pdf.add_page(); pdf.set_font('Helvetica', 'B', 16); pdf.cell(0, 10, 'Invoice', align='C', new_y='NEXT'); pdf.set_font('Helvetica', size=11); pdf.multi_cell(0, 7, invoice_text) — multi-line; agent generates invoice with headers and multi-line text blocks
- • Agent with images — pdf = FPDF(); pdf.add_page(); pdf.image('logo.png', x=10, y=10, w=50); pdf.set_y(70); pdf.set_font('Helvetica', size=12); pdf.cell(200, 10, text='Report', new_y='NEXT') — image embedding; agent adds images to PDF; x/y in mm from top-left; w= controls width; height auto-scales
- • Agent table — from fpdf import FPDF, XPos, YPos; pdf = FPDF(); pdf.add_page(); with pdf.table() as table: row = table.row(); row.cell('Name'); row.cell('Value'); for name, val in data: row = table.row(); row.cell(name); row.cell(str(val)) — table API; agent creates data tables with auto-column sizing
- • Agent PDF bytes — pdf = FPDF(); pdf.add_page(); pdf.set_font('Helvetica', size=12); pdf.cell(200, 10, text=content); return pdf.output() — bytes; agent generates PDF bytes for HTTP response; output() without filename returns bytes (fpdf2); output('file.pdf') writes to file
Not For
- • HTML/CSS to PDF — fpdf2's HTML support is basic; for full HTML rendering use weasyprint
- • Complex document layouts — fpdf2 requires manual positioning; for complex layouts use reportlab PLATYPUS or weasyprint
- • Editing existing PDFs — fpdf2 creates new PDFs only; for modifying existing PDFs use PyPDF2 or pikepdf
Interface
Authentication
No auth — PDF generation library.
Pricing
fpdf2 is LGPL 3.0 licensed. Free for all use. Pure Python — no system dependencies.
Agent Metadata
Known Gotchas
- ⚠ fpdf2 vs fpdf — pip install fpdf2 not fpdf (old version); from fpdf import FPDF works for both but fpdf2 has breaking changes from fpdf 1.x; fpdf2 cell() uses text= keyword not positional; fpdf2 multi_cell() API changed; agent requirements.txt: fpdf2>=2.7 not fpdf
- ⚠ cell() vs multi_cell() — cell(w, h, text) creates single-line cell, truncates overflow; multi_cell(w, h, text) wraps text to multiple lines; agent code with long text: use multi_cell(); cell() for table columns with known-short text; new_x/new_y control cursor position after cell
- ⚠ Coordinates are in mm from top-left — x=0, y=0 is top-left of page; default A4 is 210mm x 297mm; pdf.get_y() gets current Y position; pdf.set_xy(x, y) moves cursor; agent code: calculate positions in mm; margins: pdf.set_margins(left=20, top=20, right=20); effective width: pdf.epw (effective page width)
- ⚠ Fonts must be set before text — pdf.set_font('Helvetica', size=12) before any text call; changing font mid-document: call set_font() again; built-in fonts: Helvetica, Times, Courier; for Unicode/custom: pdf.add_font('Name', '', '/path/font.ttf'); TrueType fonts require ttf file accessible at render time
- ⚠ output() returns bytes in fpdf2 — pdf.output() returns bytes object in fpdf2 2.x; pdf.output('file.pdf') writes file AND returns None; agent code: return pdf.output() for bytes; or: pdf.output('path.pdf'); bytes_io = BytesIO(); pdf.output(bytes_io); bytes_io.getvalue() for buffer pattern
- ⚠ add_page() must be called before drawing — drawing operations before add_page() raise FPDFException; agent code: always add_page() first; auto_page_break=True (default) adds pages automatically when content reaches bottom; set_auto_page_break(auto=True, margin=15) to control break threshold
Alternatives
Full Evaluation Report
Comprehensive deep-dive: security analysis, reliability audit, agent experience review, cost modeling, competitive positioning, and improvement roadmap for fpdf2.
AI-powered analysis · PDF + markdown · Delivered within 30 minutes
Package Brief
Quick verdict, integration guide, cost projections, gotchas with workarounds, and alternatives comparison.
Delivered within 10 minutes
Score Monitoring
Get alerted when this package's AF, security, or reliability scores change significantly. Stay ahead of regressions.
Continuous monitoring
Scores are editorial opinions as of 2026-03-06.