Reportlab – All About Fonts

Have you ever wondered how to embed custom fonts in Reportlab? Or maybe you just want to switch fonts or change the font’s color. Well in this tutorial, we’ll take a look at all of these questions. You’ll need to go out and download a copy of Reportlab as it isn’t a part of the standard Python installation. You can go to PyPI or the official Reportlab website to get the package. Reportlab only works with Python 2.5-2.7, so keep that in mind. Once you’re ready, we can continue.

How to Embed Fonts in PDFs

We’ll be using a barcode font for this example called free3of9. You can find it on numerous websites, including this one. I’ve used this font in production before. It should be noted that Reportlab can actually do barcodes itself, so you really don’t need this font at all. However, we’re going to use it for this example for demonstration purposes. After you have downloaded the font and put it somewhere, we can continue. Are you ready? Then let’s look at some code:

from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.platypus import Paragraph
from reportlab.lib.units import mm

#----------------------------------------------------------------------
def createBarcode(path):
    """
    Demo to show how to embed a barcode font
    """
    style = getSampleStyleSheet()
    width, height = letter
    c = canvas.Canvas(path, pagesize=letter)
    barcode_font = r"/full/path/to/free3of9.ttf"
    pdfmetrics.registerFont(TTFont("Free 3 of 9 Regular", barcode_font))
    
    barcode_string = '%s'
    barcode_string = barcode_string % "1234567890"
    
    p = Paragraph(barcode_string, style=style["Normal"])
    p.wrapOn(c, width, height)
    p.drawOn(c, 20, 750, mm)
    
    c.save()
    
if __name__ == "__main__":
    createBarcode(r"/path/to/barcode.pdf")

First of all, we need to import several items from different parts of Reportlab. Next we need to do the following call to register the font with Reportlab:

pdfmetrics.registerFont(TTFont("Free 3 of 9 Regular", barcode_font))

Occasionally this doesn’t work for some reason. Perhaps the ttf file is poorly defined or corrupt. I don’t really know. But if you’re lucky, the font might have come with afm and pfb files. If so, you can register it that way. I found this out when I was playing with the demo copy of a MICR font I was using for creating checks. You can get the trial version if you like.

To use it, I had to something like this:

# add micr font
afm = 'path/to/MICRCheckPrixa.afm'
pfb = 'path/to/MICRCheckPrixa.pfb'
face = pdfmetrics.EmbeddedType1Face(afm, pfb)
faceName = "MICRCheckPrixa"
pdfmetrics.registerTypeFace(face)
justFont = pdfmetrics.Font(faceName, faceName, 'WinAnsiEncoding')
pdfmetrics.registerFont(justFont)

Most of the time, the first method works. However, you should know about this fallback method in case you run into weird issues with your TrueType fonts. Now we’re ready to learn about Reportlab’s standard fonts.

How to Switch Between Fonts in Reportlab

Reportlab supports several fonts internally. You can think of them as standard or default fonts. We’ll create a simple piece of code that is based on one of their examples to create a document with different fonts in it. Here’s the code:

import sys
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfgen import canvas
import string

def standardFonts():
    """
    Create a PDF with all the standard fonts
    """
    for enc in ['MacRoman', 'WinAnsi']:
        canv = canvas.Canvas(
                'StandardFonts_%s.pdf' % enc,
                )
        canv.setPageCompression(0)
        
        x = 0
        y = 744
        for faceName in pdfmetrics.standardFonts:
            if faceName in ['Symbol', 'ZapfDingbats']:
                encLabel = faceName+'Encoding'
            else:
                encLabel = enc + 'Encoding'

            fontName = faceName + '-' + encLabel
            pdfmetrics.registerFont(pdfmetrics.Font(fontName,
                                        faceName,
                                        encLabel)
                        )

            canv.setFont('Times-Bold', 18)
            canv.drawString(80, y, fontName)
            
            y -= 20
            
            alpha = "abcdefghijklmnopqrstuvwxyz"
            canv.setFont(fontName, 14)
            canv.drawString(x+85, y, alpha)
            
            y -= 20

        canv.save()
        
if __name__ == "__main__":
    standardFonts()

This script will create two PDFs: StandardFonts_MacRoman.pdf and StandardFonts_WinAnsi.pdf. As you can see, we just use a nested pair of for loops to extract the various fonts and register them with Reportlab. This shows one way of setting fonts. There’s actually another way to do this where we don’t have to register the font. Reportlab supports some XML tags, so you can use that to set the font. Let’s take a look at that code:

from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
from reportlab.platypus import Paragraph

#----------------------------------------------------------------------
def settingFontsDemo(path):
    """
    Demo to show how to use fonts in Paragraphs
    """
    p_font = 12
    c = canvas.Canvas(path, pagesize=letter)
    
    ptext = """Welcome to Reportlab! (helvetica)
    """ % p_font
    createParagraph(c, ptext, 20, 750)
    
    ptext = """Welcome to Reportlab! (courier)
    """ % p_font
    createParagraph(c, ptext, 20, 730)
    
    ptext = """Welcome to Reportlab! (times-roman)
    """ % p_font
    createParagraph(c, ptext, 20, 710)
    
    c.save()
    
#----------------------------------------------------------------------
def createParagraph(c, text, x, y):
    """"""
    style = getSampleStyleSheet()
    width, height = letter
    p = Paragraph(text, style=style["Normal"])
    p.wrapOn(c, width, height)
    p.drawOn(c, x, y, mm)
    
if __name__ == "__main__":
    settingFontsDemo("/path/to/fontDemo.pdf")

If you run the code above, you should get something like the following:

reportlab_font_demo

As you can see, all we had to do was use a font tag and specify the font name. I have yet to find a full list of default fonts that Reportlab supports, so you’ll have to play around with that. However, I think these are the main three, plus some variants thereof. You’ll also note that Reportlab is not case sensitive in regards to the font name. Note: we use the createParagraph method just to reduce code repetition.

Now we’re ready to discuss changing font colors!

How to Change Font Colors in Reportlab

Changing colors of fonts in Reportlab is extremely easy if you use the tag method we used in the last example. All you have to do is add on to the font definition and specify a color. We’ll just modify the last piece of code for this example:

from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
from reportlab.platypus import Paragraph

#----------------------------------------------------------------------
def colorFontsDemo(path):
    """
    Demo to show how to use fonts in Paragraphs
    """
    p_font = 12
    c = canvas.Canvas(path, pagesize=letter)
    
    ptext = """Welcome to Reportlab! (helvetica)
    """ % p_font
    createParagraph(c, ptext, 20, 750)
    
    ptext = """Welcome to Reportlab! (courier)
    """ % p_font
    createParagraph(c, ptext, 20, 730)
    
    ptext = """Welcome to Reportlab! (times-roman)
    """ % p_font
    createParagraph(c, ptext, 20, 710)
    
    c.save()
    
#----------------------------------------------------------------------
def createParagraph(c, text, x, y):
    """"""
    style = getSampleStyleSheet()
    width, height = letter
    p = Paragraph(text, style=style["Normal"])
    p.wrapOn(c, width, height)
    p.drawOn(c, x, y, mm)
    
if __name__ == "__main__":
    colorFontsDemo(r"/path/to/fontColorDemo.pdf")

If you run the code above, you’ll get a document that is very similar to the last one, except that each line will be a different color.

Wrapping Up

Now you know how to manipulate the fonts in Reportlab. If you want to learn additional formatting tricks, I recommend looking at the Paragraph XML Markup Tags section in the Reportlab user guide, which is in chapter 6. You’ll find out how to bold, underline, italicize, and strike-through as well as how to do superscripts and subscripts. There’s also additional information about fonts, especially regarding setting fonts for canvas objects, in the user guide. Good luck and happy coding!

Related Articles

Download the Source

8 thoughts on “Reportlab – All About Fonts”

  1. How about OTF fonts? At the moment, I have to convert OTF to TTF in order to work with ReportLabs. Are there any other ways to support OTF fonts in reportlabs?

    Thanks

  2. Thanks

    Do you mind adding OTF fonts in your code to see if it works. I’ve tried many times but ended up fail

  3. After digging a bit, it sounds like OTF fonts can store additional information that breaks reportlab. According to this (http://stackoverflow.com/questions/895596/can-anyone-recomend-a-python-pdf-generator-with-opentype-otf-support) it appears to break when the font uses CFF. Other forums seem to indicate that it works if the OTF is based on TTF instead of Type 1. There are ways to convert an OTF font to a TTF font…which supposedly works. I’m going to post to the reportlab users list and see what the devs there have to say as well.

  4. Pingback: Mike Driscoll: Reportlab: How to Create Landscape Pages | The Black Velvet Room

  5. Pingback: Reportlab: How to Create Landscape Pages | Hello Linux

  6. Pingback: Reportlab - How to Add Charts / Graphs - The Mouse Vs. The Python

  7. Pingback: Reportlab: How to Create Landscape Pages - The Mouse Vs. The Python

Comments are closed.