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.

pythonreportlabPDFdocument-generationtables

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.