Today we’ll be looking at a simple PDF generation library called pyfpdf, a port of FPDF which is a php library. This is not a replacement for Reportlab, but it does give you more than enough to create simple PDFs and may meet your needs. Let’s take a look and see what it can do!

Installing pyfpdf

You can just use pip to install pyfpdf:

pip install pyfpdf

Taking pyfpdf for a Test Drive

As with any new library, you need to actually write some code to see how it works. Here’s one of the simplest scripts you can make that will create a PDF:

import pyfpdf pdf = pyfpdf.FPDF(format='letter') pdf.add_page() pdf.set_font("Arial", size=12) pdf.cell(200, 10, txt="Welcome to Python!", align="C") pdf.output("tutorial.pdf")

Note that when we initialize our FPDF object we need to tell it that we want the result to be “letter” size. It defaults to “A4”. Next we need to add a page, set the font and put some text in. The pdf.cell call was a little unintuitive. The first two arguments are width and height and kind of specify the location of the text you pass in. The align parameter only takes single letter abbreviations and you’ll have to look in the source to figure those out. In this case, we’re centering the text by passing it a “C”. The last line accepts two parameters: the pdf name and the destination. If there’s no destination present, then the PDF is output to the same directory that the script is run in.

What if you wanted to add another line? Well you can add more text to the end if you edit how big the cell is and just create another cell. If you need a line break, then you can change the code to the following:

import pyfpdf pdf = pyfpdf.FPDF(format='letter') pdf.add_page() pdf.set_font("Arial", size=12) pdf.cell(200, 10, txt="Welcome to Python!", ln=1, align="C") pdf.cell(200,10,'Powered by FPDF',0,1,'C') pdf.output("tutorial.pdf")

Which results in the following PDF: tutorial.pdf

Adding Bling with Headers, Footers and PageBreaks

The tutorial that is included on pyfpdf’s Google Code site shows how to do headers, footers and page breaks. It doesn’t run due to a method name that must have changed and the code is written using “this” instead of “self”, so I rewrote it and cleaned it up a bit. Here’s the code:

import pyfpdf ######################################################################## class MyPDF(pyfpdf.FPDF): """""" #---------------------------------------------------------------------- def header(self): """ Header on each page """ # insert my logo self.image("logo.png", x=10, y=8, w=23) # position logo on the right self.cell(w=80) # set the font for the header, B=Bold self.set_font("Arial", style="B", size=15) # page title self.cell(40,10, "Python Rules!", border=1, ln=0, align="C") # insert a line break of 20 pixels self.ln(20) #---------------------------------------------------------------------- def footer(self): """ Footer on each page """ # position footer at 15mm from the bottom self.set_y(-15) # set the font, I=italic self.set_font("Arial", style="I", size=8) # display the page number and center it pageNum = "Page %s/{nb}" % self.page_no() self.cell(0, 10, pageNum, align="C") #---------------------------------------------------------------------- if __name__ == "__main__": pdf = MyPDF() pdf.alias_nb_pages() pdf.add_page() pdf.set_font("Times", size=12) # put some lines on the page for i in range(1, 50): pdf.cell(0, 10, "Line number %s" % i, border=0, ln=1) pdf.output("tutorial2.pdf")

Which creates the following PDF: tutorial2.pdf

This time around, we create a subclass of FPDF and override its header and footer methods as they don’t actually do anything anyway (i.e. they’re stubs). In our header, we create an image object and pass in a logo file as well as the x/y location and the width (23) of the logo. You can also pass a height too if you care about keeping the aspect ratio sane. Then we position it and insert a string of text for the title. Finally, we put in a line break.

The footer is set up to be 15 mm from the bottom. It’s also in 8pt Arial Italic. The error in the official tutorial is that it calls self.PageNo(), but that doesn’t exist. However there is a page_no method that seems to replace it, so I used that. Then at the bottom of the script, we actually create our pdf object and tell it to write a bunch of lines. If you run this script, you should get a 3-page document.

Using pyfpdf to Generate a PDF from HTML

One of my readers pointed out that pyfpdf can also generate a PDF from basic HTML. I don’t know how I missed that, but it’s true! You can! You can read about it on the project’s wiki. I am reproducing a slightly modified example below:

html = """ html2fpdf Basic usage You can now easily print text while mixing different styles : bold, italic, underlined , or all at once !

You can also insert hyperlinks like this www.mousevspython.comg, or include a hyperlink in an image. Just click on the one below.

Sample List

option 1

option 2

option 3

Header 1 header 2 cell 1 cell 2 cell 2 cell 3

""" from pyfpdf import FPDF, HTMLMixin class MyFPDF(FPDF, HTMLMixin): pass pdf=MyFPDF() #First page pdf.add_page() pdf.write_html(html) pdf.output('html.pdf','F')

Which will create the following PDF: html.pdf

Wrapping Up

There’s one more tutorial on their website that talks about colors and line breaks, but I’ll leave that for you to do as an exercise. I didn’t see anything in here about drawing, inserting tables or graphs, custom font embedding or the many other features that are available in Reportlab, but then again this is supposed to be a simple PDF generation library. If you need more advanced features, then you should certainly look at Reportlab or even some of the offshoot projects that are based on it (rst2pdf or xhtml2pdf come to mind).

Further Reading

Source Code