Python PDF Generation with ReportLab — Core Concepts
ReportLab is Python’s most established PDF generation library. It provides two main APIs: a low-level Canvas for precise drawing, and a high-level Platypus system for flowing documents with automatic pagination.
Installation
pip install reportlab
The Low-Level Canvas
The Canvas gives you direct control over every element:
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
c = canvas.Canvas("hello.pdf", pagesize=A4)
width, height = A4
c.setFont("Helvetica-Bold", 24)
c.drawString(100, height - 100, "Hello, ReportLab!")
c.setFont("Helvetica", 12)
c.drawString(100, height - 140, "This is a basic PDF document.")
c.line(100, height - 150, 500, height - 150) # Horizontal line
c.save()
Coordinates start from the bottom-left corner. (0, 0) is the bottom-left of the page.
Platypus: Flowing Documents
Platypus (Page Layout and Typography Using Scripts) handles multi-page documents automatically. You create Flowables (paragraphs, tables, spacers) and Platypus places them on pages.
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report.pdf", pagesize=A4)
styles = getSampleStyleSheet()
story = []
story.append(Paragraph("Monthly Sales Report", styles["Title"]))
story.append(Spacer(1, 24))
story.append(Paragraph(
"Revenue increased 15% compared to last quarter, driven primarily "
"by expansion into European markets.",
styles["BodyText"]
))
doc.build(story)
Tables
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
data = [
["Product", "Q1", "Q2", "Q3"],
["Widget A", "$12,000", "$15,400", "$18,200"],
["Widget B", "$8,500", "$9,100", "$11,800"],
["Widget C", "$22,000", "$19,600", "$24,500"],
]
table = Table(data, colWidths=[120, 80, 80, 80])
table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#2C3E50")),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 10),
("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#ECF0F1")]),
("ALIGN", (1, 0), (-1, -1), "RIGHT"),
]))
story.append(table)
Custom Styles
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER
heading_style = ParagraphStyle(
"CustomHeading",
parent=styles["Heading1"],
fontSize=20,
textColor=colors.HexColor("#2C3E50"),
spaceAfter=16,
alignment=TA_CENTER,
)
story.append(Paragraph("Custom Styled Heading", heading_style))
Headers and Footers
Add repeating headers and footers by defining callbacks:
def add_header_footer(canvas_obj, doc):
canvas_obj.saveState()
# Header
canvas_obj.setFont("Helvetica", 9)
canvas_obj.drawString(72, A4[1] - 40, "Acme Corp — Confidential")
# Footer with page number
canvas_obj.drawString(72, 30, f"Page {doc.page}")
canvas_obj.drawRightString(A4[0] - 72, 30, "Generated by ReportLab")
canvas_obj.restoreState()
doc.build(story, onFirstPage=add_header_footer, onLaterPages=add_header_footer)
Adding Images
from reportlab.platypus import Image
logo = Image("logo.png", width=120, height=40)
story.insert(0, logo)
Common Misconception
“ReportLab is just for simple documents.” It powers some of the highest-volume PDF generation systems in the world, including financial reports and government documents. The open-source version handles tables, charts, barcodes, and complex layouts. The commercial version (ReportLab PLUS) adds even more.
The one thing to remember: Use Canvas for precise pixel-level control and Platypus for flowing multi-page documents — most real projects use Platypus with SimpleDocTemplate and a list of flowables.
See Also
- Python Docx Generation python-docx lets you create and edit Word documents from Python — perfect for automating letters, contracts, and reports.
- Python Excel Openpyxl openpyxl lets Python read and write real Excel files — no Excel needed on the computer.
- Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.
- Containerization Why does software that works on your computer break on everyone else's? Containers fix that — and they're why Netflix can deploy 100 updates a day without the site going down.
- Python 310 New Features Python 3.10 gave programmers a shape-sorting machine, friendlier error messages, and cleaner ways to say 'this or that' in type hints.