Reportlab: How to Add Page Numbers

Have you ever needed to add page numbers to your Reportlab generated PDF but didn’t know how? Well you’ve come to the right place. We’re going to look at how to add page number in three different circumstances:

  1. How to add page numbers with just the canvas object
  2. How to add page numbers using the SimpleDocTemplate
  3. How to add “Page # of #” (i.e. Page 1 of 10)

Are you ready? Let’s do this thing!

Adding Page Numbers with Just a Canvas

canvas_page_num

The canvas object has a very simple method for grabbing the page number built right into it. Here’s an example:

from reportlab.pdfgen import canvas

#----------------------------------------------------------------------
def createMultiPage():
    """
    Create a multi-page document
    """
    c = canvas.Canvas("canvas_page_num.pdf")
    
    for i in range(5):
        page_num = c.getPageNumber()
        text = "This is page %s" % page_num
        c.drawString(100, 750, text)
        c.showPage()
    c.save()
        
#----------------------------------------------------------------------
if __name__ == "__main__":
    createMultiPage()

As you can see, all you have to do is call the canvas object’s getPageNumber() to get the page’s page number. In the code above, we create a five page document with one string of text per page. Now we’re ready to move on and learn how to add page numbers with Reportlab’s templates.

How to Add Page Numbers in Reportlab’s Document Templates

doc_page_num

In this example, we’ll be using Reportlab’s SimpleDocTemplate. It’s actually really easy to use. We’ll be taking some code from a previous article to help fill out the document and make it look more interesting than the last one. Here’s the code:

from reportlab.lib.enums import TA_JUSTIFY
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm

#----------------------------------------------------------------------
def addPageNumber(canvas, doc):
    """
    Add the page number
    """
    page_num = canvas.getPageNumber()
    text = "Page #%s" % page_num
    canvas.drawRightString(200*mm, 20*mm, text)

#----------------------------------------------------------------------
def createMultiPage():
    """
    Create a multi-page document
    """
    doc = SimpleDocTemplate("doc_page_num.pdf",pagesize=letter,
                            rightMargin=72,leftMargin=72,
                            topMargin=72,bottomMargin=18)
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
    
    Story = []
    
    magName = "Pythonista"
    issueNum = 12
    subPrice = "99.00"
    limitedDate = "03/05/2010"
    freeGift = "tin foil hat"
    full_name = "Marvin Jones"
    address_parts = ["411 State St.", "Reno, NV 80158"]
    
    for page in range(5):
        # Create return address
        ptext = '%s' % full_name
        Story.append(Paragraph(ptext, styles["Normal"]))       
        for part in address_parts:
            ptext = '%s' % part.strip()
            Story.append(Paragraph(ptext, styles["Normal"]))
            
        Story.append(Spacer(1, 12))
        ptext = 'Dear %s:' % full_name.split()[0].strip()
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 12))
         
        ptext = """We would like to welcome you to our subscriber base 
        for %s Magazine! You will receive %s issues at the excellent introductory 
        price of $%s. Please respond by %s to start receiving your subscription 
        and get the following free gift: %s.""" 
        ptext = ptext % (magName, issueNum, subPrice, limitedDate, freeGift)
        Story.append(Paragraph(ptext, styles["Justify"]))
        Story.append(Spacer(1, 12))
         
         
        ptext = 'Thank you very much and we look forward to serving you.'
        Story.append(Paragraph(ptext, styles["Justify"]))
        Story.append(Spacer(1, 12))
        ptext = 'Sincerely,'
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 48))
        ptext = 'Ima Sucker'
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 12))
        Story.append(PageBreak())
        
    doc.build(Story, onFirstPage=addPageNumber, onLaterPages=addPageNumber)
    
#----------------------------------------------------------------------
if __name__ == "__main__":
    createMultiPage()

In this case, we need to create a simple addPageNumber function that we can call. Next we create a multi-page document using Reportlab flowables, which in this case is a series of Paragraph objects. We also instantiate a SimpleDocTemplate and call its build method. In that call, we tell it to call our addPageNumber function for the first page and all the other pages too. This allows us to add a page number to each page dynamically!

How to Add “Page Number of Total” in Reportlab

doc_page_num2

Reportlab doesn’t have a built in way to add page numbers where you want to include the total, such as “Page 1 of 5” or whatever. So I went looking to see if anyone had solved this dilemma and found two recipes on ActiveState. You can read about them here or here. We’re going to take the examples from those recipes and combine them with the code in the previous section.

from reportlab.lib.enums import TA_JUSTIFY
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm

########################################################################
class PageNumCanvas(canvas.Canvas):
    """
    http://code.activestate.com/recipes/546511-page-x-of-y-with-reportlab/
    http://code.activestate.com/recipes/576832/
    """

    #----------------------------------------------------------------------
    def __init__(self, *args, **kwargs):
        """Constructor"""
        canvas.Canvas.__init__(self, *args, **kwargs)
        self.pages = []
        
    #----------------------------------------------------------------------
    def showPage(self):
        """
        On a page break, add information to the list
        """
        self.pages.append(dict(self.__dict__))
        self._startPage()
        
    #----------------------------------------------------------------------
    def save(self):
        """
        Add the page number to each page (page x of y)
        """
        page_count = len(self.pages)
        
        for page in self.pages:
            self.__dict__.update(page)
            self.draw_page_number(page_count)
            canvas.Canvas.showPage(self)
            
        canvas.Canvas.save(self)
        
    #----------------------------------------------------------------------
    def draw_page_number(self, page_count):
        """
        Add the page number
        """
        page = "Page %s of %s" % (self._pageNumber, page_count)
        self.setFont("Helvetica", 9)
        self.drawRightString(195*mm, 272*mm, page)
        
#----------------------------------------------------------------------
def createMultiPage():
    """
    Create a multi-page document
    """
    doc = SimpleDocTemplate("doc_page_num_v2.pdf",pagesize=letter,
                            rightMargin=72,leftMargin=72,
                            topMargin=72,bottomMargin=18)
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
    
    Story = []
    
    magName = "Pythonista"
    issueNum = 12
    subPrice = "99.00"
    limitedDate = "03/05/2010"
    freeGift = "tin foil hat"
    full_name = "Marvin Jones"
    address_parts = ["411 State St.", "Reno, NV 80158"]
    
    for page in range(5):
        # Create return address
        ptext = '%s' % full_name
        Story.append(Paragraph(ptext, styles["Normal"]))       
        for part in address_parts:
            ptext = '%s' % part.strip()
            Story.append(Paragraph(ptext, styles["Normal"]))
            
        Story.append(Spacer(1, 12))
        ptext = 'Dear %s:' % full_name.split()[0].strip()
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 12))
         
        ptext = """We would like to welcome you to our subscriber base 
        for %s Magazine! You will receive %s issues at the excellent introductory 
        price of $%s. Please respond by %s to start receiving your subscription 
        and get the following free gift: %s.""" 
        ptext = ptext % (magName, issueNum, subPrice, limitedDate, freeGift)
        Story.append(Paragraph(ptext, styles["Justify"]))
        Story.append(Spacer(1, 12))
         
         
        ptext = 'Thank you very much and we look forward to serving you.'
        Story.append(Paragraph(ptext, styles["Justify"]))
        Story.append(Spacer(1, 12))
        ptext = 'Sincerely,'
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 48))
        ptext = 'Ima Sucker'
        Story.append(Paragraph(ptext, styles["Normal"]))
        Story.append(Spacer(1, 12))
        Story.append(PageBreak())
        
    doc.build(Story, canvasmaker=PageNumCanvas)
    
#----------------------------------------------------------------------
if __name__ == "__main__":
    createMultiPage()

Let’s take a quick look at our changes. First of all we subclass canvas.Canvas and override a couple of its methods to keep track of the number of pages that are created in a list. Then when the document saves itself, it goes through all the pages in the list and adds the appropriate to each page. To get the document to use this canvas, we pass the class to the canvasmaker parameter, which you’ll see in the last line of the createMultiPage function: doc.build(Story, canvasmaker=PageNumCanvas). That’s it!

Wrapping Up

Today you have learned several ways to add page numbers to your Reportlab PDFs. Now get out there and start coding up something neat!

Download the Source

7 thoughts on “Reportlab: How to Add Page Numbers”

  1. Pingback: Mike Driscoll: Reportlab: How to Add Page Numbers | The Black Velvet Room

  2. Pingback: Reportlab: How to Create Custom Flowables - Mouse Vs Python

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

Comments are closed.