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:
Are you ready? Let's do this thing!
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.
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!
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!
Today you have learned several ways to add page numbers to your Reportlab PDFs. Now get out there and start coding up something neat!
Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary