Python PDF Generator

We will learn how to make a PDF file using the Python library ReportLab.

Interactive Google Colab Practice Notebook

Practice setting up canvas coordinates, drawing text, line grids, adding watermark transforms, custom page dimensions, and letterhead templates interactively in Google Colab.

View on GitHub Open In Colab
Creating PDF file and adding text line image rectangle and watermark by using Python ReportLab

Installing ReportLab 🔝

At your terminal or command prompt, install the package via pip:

pip install reportlab

Create your first PDF file:

Create PDF files with dynamic data taken from SQLite database in Colab.

Understanding Canvas 🔝

Layout and margin of pdf page

Canvas is like a blank white paper where the (x, y) coordinates start by default from the bottom-left corner.

The x-coordinate increases towards the right, and the y-coordinate increases upwards. The bottomup argument configures the coordinate origin (setting bottomup=0 flips the origin to top-left, whereas bottomup=1 is bottom-left).

How to Create a PDF File 🔝

Write string in pdf page

Import canvas from ReportLab. The code below writes "Hello World" at x=200, y=200 on the canvas page.

from pathlib import Path
from reportlab.pdfgen import canvas

output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
my_path = output_dir / 'my_pdf.pdf'

c = canvas.Canvas(str(my_path), bottomup=0)
c.drawString(200, 200, "Hello World")  # write text in page
c.showPage()   # saves current page
c.save()       # stores the file and closes canvas
print(f"PDF generated: {my_path}")

Font Colour and Font Size 🔝

We can manage font size and font colour prior to invoking drawString():

c.setFont("Helvetica", 20)  # font family and size
# c.setFillColorCMYK(.2, .2, 0, .39) # font colour as CMYK
# c.setFillColorRGB(0, 0, 1)        # font colour as RGB
c.setFillColor('lightblue')         # named color
c.drawString(200, 200, "Hello World")

Font Style & Available System Fonts 🔝

ReportLab includes built-in core font families. Inspect registered fonts using getAvailableFonts():

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter

output_dir = Path('output')
my_path = output_dir / 'font_list.pdf'

c = canvas.Canvas(str(my_path), pagesize=letter)
c.translate(inch, inch)  # 1 inch margin
c.setFillColorRGB(0, 0, 1)

l1 = c.getAvailableFonts()
j = 1
for my_font in l1:
    c.setFont(my_font, 16)
    c.drawString(inch, j * inch * 0.5, my_font)
    j += 1

c.showPage()
c.save()
font family supported by default in ReportLab

Installing and Working with Custom Fonts 🔝

Learn how to embed and register custom TrueType (.ttf) fonts in ReportLab to display specialized typography in your PDF outputs.

Adding different font support in Reportlab

Understanding Geometry & Units 🔝

Utilize unit helper tools like inch and cm alongside page definitions (letter, A4) to manage precise page dimensions:

from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter, A4

c.translate(inch, inch)  # offset origin by 1 inch

Drawing Lines 🔝

drawing line in pdf page

Specify starting (x1, y1) and ending (x2, y2) coordinates to draw lines. Configure stroke color with setStrokeColorRGB() and line width with setLineWidth():

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter

output_dir = Path('output')
my_path = output_dir / 'line_drawing.pdf'

c = canvas.Canvas(str(my_path), bottomup=1, pagesize=letter)
c.translate(inch, inch)
c.setStrokeColorRGB(1, 0, 0)  # red line
c.setLineWidth(10)
c.line(0, 8 * inch, 7 * inch, 8 * inch)
c.showPage()
c.save()

Drawing Grid Layouts 🔝

drawing grid in pdf page

Construct grids easily using coordinate sequence lists for x and y boundaries:

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4

output_dir = Path('output')
my_path = output_dir / 'grid_layout.pdf'

c = canvas.Canvas(str(my_path), bottomup=1, pagesize=A4)
w, h = A4
xlist = [20, 70, 120, 170]
ylist = [h - 20, h - 70, h - 120, h - 170]

c.grid(xlist, ylist)
c.drawString(70, h - 70, "plus2net")
c.save()
Creating PDF Documents with Grid and 2D List Data

Adding Images to PDF Files 🔝

Adding image to pdf file

Add local photo assets or web images using drawImage():

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter

output_dir = Path('output')
my_path = output_dir / 'image_example.pdf'

c = canvas.Canvas(str(my_path), bottomup=1, pagesize=letter)
c.translate(inch, inch)
c.drawImage('https://www.plus2net.com/images/top2.jpg', -0.8 * inch, 9.3 * inch)
c.showPage()
c.save()

Rotating Elements 🔝

Rotate the coordinate space using rotate(angle) and restore origin alignment by reversing the rotation angle offset:

c.rotate(-45)
c.drawImage('logo.jpg', 0, 0)
c.rotate(45)

Drawing Rectangles 🔝

Adding rectangle with border colour to pdf file

Draw vector shapes with stroke borders and fill colors using rect():

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter

output_dir = Path('output')
my_path = output_dir / 'rectangle.pdf'

c = canvas.Canvas(str(my_path), bottomup=1, pagesize=letter)
c.translate(inch, inch)
c.setLineWidth(10)
c.setStrokeColor('yellow')
c.setFillColor('lightgreen')
c.rect(1 * inch, 2 * inch, 3.5 * inch, 5 * inch, fill=1)
c.showPage()
c.save()

Setting a Custom Page Size in ReportLab 🔝

Define custom dimensions by supplying a (width, height) point tuple (where 72 points = 1 inch):

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch

output_dir = Path('output')
my_path = output_dir / 'custom_size.pdf'

custom_size = (595, 841)
c = canvas.Canvas(str(my_path), bottomup=1, pagesize=custom_size)
c.translate(inch, inch)
c.setLineWidth(10)
c.setStrokeColor('yellow')
c.setFillColor('lightgreen')
c.rect(1 * inch, 2 * inch, 3.5 * inch, 5 * inch, fill=1)
c.showPage()
c.save()

Watermarking PDF Documents 🔝

Adding watermark to pdf document

Combine rotated text with subtle CMYK opacity styling to render security background watermarks:

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter

output_dir = Path('output')
my_path = output_dir / 'watermarked.pdf'

c = canvas.Canvas(str(my_path), bottomup=1, pagesize=letter)
c.translate(inch, inch)
c.setLineWidth(10)
c.setStrokeColor('yellow')
c.setFillColor('lightgreen')
c.rect(1 * inch, 2 * inch, 3.5 * inch, 5 * inch, fill=1)

# Watermark execution
c.rotate(45)
c.setFillColorCMYK(0, 0, 0, 0.08)
c.setFont("Helvetica", 100)
c.drawString(2 * inch, 1 * inch, "SAMPLE")
c.rotate(-45)

c.setFont("Helvetica", 10)
c.setFillColorRGB(1, 0, 0)
c.drawString(0, -0.9 * inch, "\u00A9 plus2net.com")
c.showPage()
c.save()

PDF Standard Templates 🔝

Modularize page designs by encapsulating letterheads and headers in a template module (temp1.py) and calling it inside your primary builder script (main.py).

main.py

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import letter
from temp1 import my_temp

output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
my_path = output_dir / 'template_output.pdf'

c = canvas.Canvas(str(my_path), pagesize=letter)
c = my_temp(c)

c.setFillColorRGB(0, 0, 1)
c.setFont("Helvetica", 16)
c.drawString(2 * inch, 4 * inch, 'This is my product')
c.showPage()
c.save()

temp1.py

from reportlab.lib.units import inch
from datetime import date

def my_temp(c):
    c.translate(inch, inch)
    c.setFont("Helvetica", 14)
    c.setStrokeColorRGB(0.1, 0.8, 0.1)
    c.setFillColorRGB(0, 0, 1)
    c.drawImage('https://www.plus2net.com/images/top2.jpg', -0.8 * inch, 9.3 * inch)
    c.drawString(0, 9 * inch, "Shop No : 1234, ABCD Road")
    c.drawString(0, 8.7 * inch, "City Name: Mycity, ZIP : 12345")
    
    c.setFillColorRGB(0, 0, 0)
    c.line(0, 8.6 * inch, 6.8 * inch, 8.6 * inch)
    c.drawString(5.6 * inch, 9.5 * inch, 'Bill No :# 1234')
    
    dt = date.today().strftime('%d-%b-%Y')
    c.drawString(5.6 * inch, 9.3 * inch, dt)
    
    c.setFont("Helvetica", 8)
    c.drawString(3 * inch, 9.6 * inch, 'Tax No :# ABC1234')
    c.line(0, -0.7 * inch, 6.8 * inch, -0.7 * inch)
    
    c.setFillColorRGB(1, 0, 0)
    c.drawString(0, -0.9 * inch, "\u00A9 plus2net.com")
    
    c.rotate(45)
    c.setFillColorCMYK(0, 0, 0, 0.08)
    c.setFont("Helvetica", 100)
    c.drawString(2 * inch, 1 * inch, "SAMPLE")
    c.rotate(-45)
    
    return c

Password-Protected PDF File 🔝

Secure documents against unauthorized opening using the pdfencrypt module:

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib import pdfencrypt

output_dir = Path('output')
my_path = output_dir / 'protected_hello.pdf'

pw = pdfencrypt.StandardEncryption('test')  # password is 'test'
c = canvas.Canvas(str(my_path), bottomup=0, encrypt=pw)
c.drawString(200, 200, 'Hello world')
c.showPage()
c.save()

Practical Uses of ReportLab Canvas Generation 🔝

  • Dynamic Letterhead Generation: Standardize corporate identity headers across invoices, statements, and official receipts.
  • Security & Encryption: Protect payroll summaries and personal student records with passwords and restricted permissions.
  • Precise Graphic Layouts: Position vector lines, shapes, images, and tabular grids down to sub-point accuracy.

Common Errors & Troubleshooting 🔝

  • Flipped Coordinates: If text appears upside down or misplaced, verify your bottomup coordinate setting.
  • Path Object Type Mismatch: Cast pathlib.Path variables to strings when initializing canvas.Canvas(str(path)).
  • Missing Page Flush: Always call c.showPage() before c.save() to ensure all canvas draw commands render onto the final page.

Frequently Asked Questions (FAQ) 🔝

Q: How do I change the default unit from points to inches or centimeters?
A: Import inch or cm from reportlab.lib.units and multiply coordinates (e.g. 2 * inch).

Q: How do I handle multi-page canvas documents?
A: Call c.showPage() after finishing each page to start a new page on the same canvas instance.

Related Python PDF Tutorials & Section Modules

Multiple PDF files each with unique password consists of combination of name and birth month
Adding different font support in Reportlab
Creating PDF Documents with Grid and 2D List Data
PDF Mark sheet by using data from SQLite database Generate PDF Invoice using Sales data Table from different data sources to PDF file Table from Pandas DataFrame to PDF file PDF Circles & Shapes
Create Report in PDF using Charts, images, tables and Paragraphs
PDF Id-card ID card from user Inputs in Tkinter
Bar charts in PDF Line charts in PDF Pie Charts Paragraph
Python



Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer