Changing fonts for Platypus document templates in reportlab

Tue 30 November 2010 by Thejaswi Puthraya

If you've wanted to generate PDF reports in python, you don't have choices. Most of the so called alternatives are also built on top of 'reportlab'.

I am not comfortable with reportlab (this is a post in itself) but because there's no viable alternative, I have stuck on. Reportlab has got a feature called 'Platypus' which lets the developer build a PDF document by arranging elements very similar to an HTML document.

For a side-project, I was looking at generating reports with Platypus. Things were fairly easy to setup but the PDF wouldn't display properly in windows because the Helvetica font replaced the diacritics with black boxes. The problem could not be reproduced on a linux based operating system.

The solution was to embed a font so that the PDF would render uniformly across all fonts. I selected the LinLibertine font because it was being used at Wikipedia and has a liberal license.

I struggled to embed the font even though it looked straight forward. I ran into lot of issues and took nearly a month to read the code and try to figure it out. Finally, I gave up and consulted the reportlab mailing list. I got very quick responses [1] and the problem was solved. At this point, I swore to blog about this scenario to be of assistance to some other frustrated soul.

Here's how to embed a custom font while using Platypus:

pdfmetrics.registerFont(TTFont('LinLibertine',
                               "/path/to/font.ttf")))
doct = doctemplate.SimpleDocTemplate("/path/to/output.pdf",
                                     pagesize=landscape(A4))
style_sheet = getSampleStyleSheet()
style_sheet.add(ParagraphStyle(name='TestStyle',
                               fontName='LinLibertine',
                               fontSize=12,
                               leading=12)
data = []
data.append((Paragraph(some_content, style=style_sheet["Title"]),
             Paragraph(story_content,
                       style=style_sheet["TestStyle"])))
style = GRID_STYLE
style.add(*('VALIGN', (0,0), (-1,-1), 'MIDDLE'))
style.add(*('LEFTPADDING', (0,0), (-1,-1), 15))
style.add(*('RIGHTPADDING', (0,0), (-1,-1), 15))
table = LongTable(data, colWidths=360, rowHeights=215, style=style)
page_flowables = [table]
doct._doSave = 0
doct.build(page_flowables)
canvas = doct.canv
canvas.setTitle("Some title")
canvas.showPage()
# Use the raw data below to pass into a HTTP Response
canvas.getpdfdata()

The process is:

  • Register a font through registerFont
  • Create a style (here TestStyle)
  • Reference it in the Platypus flowables

Note

Remember to use the doct._doSave line because it does not save the canvas while building it. Saving the canvas will prevent it from being modified later. If you forget the above mentioned line, there are possibilities of getting redefining named object error in reportlab.

Hopefully, this short post might be helpful. Thanks to Robin Becker and Henning von Bargen for assisting me in solving the issue. Remember when in doubt, try to solve it yourself and seek help if you aren't able to help yourself :)