ReportLab Custom Fonts: Embed and Use TrueType Fonts in PDF

ReportLab can embed custom TrueType fonts in PDF files by registering the font with TTFont() and pdfmetrics.registerFont(). After registration, the font can be used with both the low-level PDF Canvas and Platypus components such as Paragraph.


How to Embed and Use Custom TrueType Fonts in PDFs with Python ReportLab

Install ReportLab 🔝

Install ReportLab with pip:

python -m pip install reportlab

Then import the classes required for TrueType font registration:

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

Standard PDF Fonts vs Custom Fonts 🔝

ReportLab can use standard PDF fonts such as:

Helvetica
Helvetica-Bold
Times-Roman
Times-Bold
Courier
Courier-Bold

These standard fonts can be selected directly:

c.setFont('Helvetica', 14)

A custom TrueType font must first be registered.

pdfmetrics.registerFont(TTFont('MyFont', 'fonts/MyFont-Regular.ttf'))

After registration:

c.setFont('MyFont', 14)
The name 'MyFont' is the internal ReportLab name you choose during registration. It does not have to be identical to the TTF filename.

Keep Custom Fonts inside Your Project 🔝

A simple project structure is:

my_project/
|-- create_pdf.py
|-- fonts/
|   |-- MyFont-Regular.ttf
|   |-- MyFont-Bold.ttf
|-- output/
    |-- document.pdf

Keeping fonts with the application is usually easier to deploy than copying font files into the installed ReportLab package directory.

Build the Font Path with pathlib

from pathlib import Path

base_dir=Path(__file__).resolve().parent
font_path=base_dir / 'fonts' / 'MyFont-Regular.ttf'

print(font_path)

pathlib avoids hard-coded path separators and works across Windows, macOS and Linux.

Register a TrueType Font with TTFont 🔝

Create a TTFont object and register it with pdfmetrics.

from pathlib import Path
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

font_path=Path('fonts/MyFont-Regular.ttf')

pdfmetrics.registerFont(
    TTFont('MyFont', str(font_path))
)

The two important arguments are:

TTFont('MyFont', 'fonts/MyFont-Regular.ttf')
       ^                 ^
       |                 |
 ReportLab name       Font file

Use the ReportLab name when selecting the font later.

Use a Custom Font with ReportLab Canvas 🔝

The pdfgen.canvas.Canvas class is useful when text and graphics must be positioned directly on a PDF page.

from pathlib import Path
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

font_path=Path('fonts/MyFont-Regular.ttf')
pdfmetrics.registerFont(TTFont('MyFont', str(font_path)))

c=canvas.Canvas('custom-font.pdf', pagesize=letter)
c.setFont('MyFont', 18)
c.drawString(72, 720, 'Welcome to plus2net')
c.save()

The custom font is selected by:

c.setFont('MyFont', 18)

and the text is placed by:

c.drawString(72, 720, 'Welcome to plus2net')

Change Font Size

c.setFont('MyFont', 12)
c.drawString(72, 690, '12 point custom font')

c.setFont('MyFont', 24)
c.drawString(72, 650, '24 point custom font')

TrueType Fonts and Unicode Text 🔝

ReportLab TrueType fonts work with Unicode text, but the selected font must actually contain glyphs for the characters being used.

msg='Caf\u00e9 - Python PDF'
c.drawString(72, 720, msg)

If the font does not contain a required character, choosing that font cannot create the missing glyph.

Use a Custom Font with ReportLab Paragraph 🔝

For multi-line text, wrapping and document layouts, use Platypus Paragraph with a ParagraphStyle.

from pathlib import Path
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import SimpleDocTemplate, Paragraph

font_path=Path('fonts/MyFont-Regular.ttf')
pdfmetrics.registerFont(TTFont('MyFont', str(font_path)))

style=ParagraphStyle(
    'CustomFont',
    fontName='MyFont',
    fontSize=12,
    leading=16
)

doc=SimpleDocTemplate('paragraph-font.pdf', pagesize=A4)

story=[
    Paragraph('This paragraph uses a custom TrueType font registered with ReportLab.', style)
]

doc.build(story)

The custom font is connected to the paragraph through:

fontName='MyFont'

Add Background, Border and Padding

style=ParagraphStyle(
    'CustomFont',
    fontName='MyFont',
    fontSize=12,
    leading=16,
    backColor='#F1F1F1',
    borderColor='#CCCCCC',
    borderWidth=1,
    borderPadding=10
)

For longer documents, Platypus handles wrapping and page flow more naturally than manually positioning every line with drawString().

Register Regular, Bold and Italic Fonts as a Family 🔝

If a custom font provides separate regular, bold, italic and bold-italic TTF files, register each file.

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

pdfmetrics.registerFont(TTFont('MyFont', 'fonts/MyFont-Regular.ttf'))
pdfmetrics.registerFont(TTFont('MyFont-Bold', 'fonts/MyFont-Bold.ttf'))
pdfmetrics.registerFont(TTFont('MyFont-Italic', 'fonts/MyFont-Italic.ttf'))
pdfmetrics.registerFont(TTFont('MyFont-BoldItalic', 'fonts/MyFont-BoldItalic.ttf'))

Then map them as one family:

pdfmetrics.registerFontFamily(
    'MyFont',
    normal='MyFont',
    bold='MyFont-Bold',
    italic='MyFont-Italic',
    boldItalic='MyFont-BoldItalic'
)

This is important when Paragraph markup uses:

<b>Bold text</b>
<i>Italic text</i>
<b><i>Bold italic text</i></b>

Use Different Fonts inside One Paragraph 🔝

Paragraph markup supports the <font> tag.

text='''This uses the paragraph font.
<font name="Helvetica" color="blue">This part uses Helvetica.</font>
<font name="MyFont" color="red">This part uses the custom font.</font>'''

paragraph=Paragraph(text, style)

The font name used inside the tag must be a font name ReportLab knows about.

Handle a Missing Font File 🔝

A common error is supplying an incorrect path to the TTF file.

from pathlib import Path

font_path=Path('fonts/MyFont-Regular.ttf')

if not font_path.is_file():
    raise FileNotFoundError(f'Font file not found: {font_path}')

Register the font only after confirming the file exists:

pdfmetrics.registerFont(
    TTFont('MyFont', str(font_path))
)

Complete Safe Registration Function

from pathlib import Path
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

def register_font(name, filename):
    font_path=Path(filename)

    if not font_path.is_file():
        raise FileNotFoundError(f'Font file not found: {font_path}')

    pdfmetrics.registerFont(TTFont(name, str(font_path)))

register_font('MyFont', 'fonts/MyFont-Regular.ttf')

Arabic, Hindi and Other Complex Scripts 🔝

A TrueType font may contain Arabic, Devanagari or other complex-script glyphs, but having the glyphs is only one part of correct text rendering.

Some writing systems require:

  • character shaping,
  • ligature handling,
  • bidirectional text processing,
  • script-specific positioning, and
  • appropriate text direction and alignment.

Modern ReportLab versions include developing support for text shaping and right-to-left scripts. This is particularly relevant to Arabic, Hebrew and Persian and can also affect Indic and other complex scripts.

Simple Unicode vs Complex Shaping

Text RequirementWhat Is Needed
Latin text with accentsA TrueType font containing the required glyphs
Many CJK TrueType fontsSuitable font coverage
Arabic / Persian / HebrewGlyph coverage plus RTL/BiDi and, where required, shaping
Many Indic scriptsGlyph coverage plus script shaping

For multilingual projects, test the exact font and the actual language content rather than assuming that successful font registration guarantees correct output.

Check the Font License before Embedding 🔝

Custom fonts are software assets with their own licenses. Before distributing a PDF that embeds a font, check that the font license allows PDF embedding and the intended type of distribution.

Open-source fonts often provide clear embedding permissions, while commercial fonts can have different licensing conditions.

A font being installed on your computer does not automatically mean that you have permission to distribute it inside generated documents or applications.

Common ReportLab Custom Font Mistakes 🔝

1. Using the Font Filename in setFont()

After:

pdfmetrics.registerFont(TTFont('MyFont', 'fonts/MyFont-Regular.ttf'))

use:

c.setFont('MyFont', 14)

not:

c.setFont('MyFont-Regular.ttf', 14)

2. Using an Incorrect Font Path

Confirm that the file exists before registering it.

3. Storing Fonts inside the Installed ReportLab Package

Application font files are easier to maintain in a project directory such as fonts/. Package upgrades or environment changes should not be relied on to preserve your own assets.

4. Assuming Every TTF Contains Every Unicode Character

Unicode support depends on the glyph coverage of the actual font.

5. Expecting Bold Markup to Create a Bold Font File

Register and map regular, bold, italic and bold-italic font variants when those styles are required.

6. Assuming Arabic or Indic Text Only Needs a Different Font

Complex scripts can require shaping and bidirectional processing in addition to an appropriate font.

7. Manually Positioning Long Paragraphs with drawString()

drawString() is appropriate for positioned single-line text. Use Paragraph and Platypus for wrapping and flowing multi-line text.

8. Ignoring Font Licensing

Verify that your font license allows the required PDF embedding and distribution.

Summary of ReportLab Custom Fonts 🔝

  • ReportLab supports embedded TrueType fonts through TTFont.
  • Register fonts with pdfmetrics.registerFont().
  • The first TTFont() argument is the internal ReportLab font name.
  • The second argument identifies the TTF font file.
  • Keep application font files in a project directory instead of modifying the installed ReportLab package.
  • Use pathlib for portable font paths.
  • Use Canvas.setFont() for directly positioned PDF text.
  • Use ParagraphStyle(fontName=...) for Platypus Paragraphs.
  • TrueType fonts support Unicode, but the font must contain the required glyphs.
  • Register separate bold and italic files when genuine font variants are required.
  • Use registerFontFamily() so Paragraph <b> and <i> markup can map to custom font variants.
  • Use <font name="..."> to switch fonts inside Paragraph markup.
  • Check that a font file exists before attempting to register it.
  • Complex scripts can require shaping and bidirectional processing in addition to font registration.
  • Test multilingual output with the actual languages and fonts used by the application.
  • Check the font license before embedding or distributing custom fonts.
Python PDF Paragraph PDF Tables Bar Charts Line Charts Pie Charts




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