First of all, Reportlab is awesome. Best library I've found to generate pdfs.
Please install reportlab before trying the examples:
pip install reportlab
In order to create a footnote you need to render a document with multibuild and use a canvasmaker to add the footer.
First, let's create a simple pdf file with two pages:
from reportlab.platypus import (SimpleDocTemplate, Paragraph, PageBreak)
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import LETTER
if __name__ == '__main__':
# Content
styles = getSampleStyleSheet()
elements = []
elements.append(Paragraph("Hello", styles["Normal"]))
elements.append(Paragraph("World", styles["Normal"]))
elements.append(PageBreak())
elements.append(Paragraph("You are in page 2", styles["Normal"]))
# Build
doc = SimpleDocTemplate("my_file.pdf", pagesize=LETTER)
doc.build(elements)
Check that the pdf file is created correctly.
Now let's add a canvas class to draw the footer that shows a line and page numbers and change build to multibuild in the last line:
from reportlab.pdfgen import canvas
from reportlab.platypus import (SimpleDocTemplate, Paragraph, PageBreak)
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import LETTER
class FooterCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self.pages = []
def showPage(self):
self.pages.append(dict(self.__dict__))
self._startPage()
def save(self):
page_count = len(self.pages)
for page in self.pages:
self.__dict__.update(page)
self.draw_canvas(page_count)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_canvas(self, page_count):
page = "Page %s of %s" % (self._pageNumber, page_count)
x = 128
self.saveState()
self.setStrokeColorRGB(0, 0, 0)
self.setLineWidth(0.5)
self.line(66, 78, LETTER[0] - 66, 78)
self.setFont('Times-Roman', 10)
self.drawString(LETTER[0]-x, 65, page)
self.restoreState()
if __name__ == '__main__':
# Content
styles = getSampleStyleSheet()
elements = []
elements.append(Paragraph("Hello", styles["Normal"]))
elements.append(Paragraph("World", styles["Normal"]))
elements.append(PageBreak())
elements.append(Paragraph("You are in page 2", styles["Normal"]))
# Build
doc = SimpleDocTemplate("my_file.pdf", pagesize=LETTER)
doc.multiBuild(elements, canvasmaker=FooterCanvas)
In multibuild you can also specify a different canvas for the first page if you will:
doc.multiBuild(Elements, onFirstPage=myFirstPage, onLaterPages=myLaterPages)
Hope this helps.
EDIT
The goal now is to add a footer to an existing pdf file. Unfortunately, this can't be done alone with Reportlab (at least the open source version, I think the proffesional version have this feature).
Firt, we need to add to the recipe a little of pdfrw
pip install pdfrw
Now we can add a footer to an existing pdf doing this: opening the original pdf, extracting the pages, and "drawing" the pages along the footer to a new pdf, one page at a time:
from reportlab.pdfgen.canvas import Canvas
from pdfrw import PdfReader
from pdfrw.toreportlab import makerl
from pdfrw.buildxobj import pagexobj
input_file = "my_file.pdf"
output_file = "my_file_with_footer.pdf"
# Get pages
reader = PdfReader(input_file)
pages = [pagexobj(p) for p in reader.pages]
# Compose new pdf
canvas = Canvas(output_file)
for page_num, page in enumerate(pages, start=1):
# Add page
canvas.setPageSize((page.BBox[2], page.BBox[3]))
canvas.doForm(makerl(canvas, page))
# Draw footer
footer_text = "Page %s of %s" % (page_num, len(pages))
x = 128
canvas.saveState()
canvas.setStrokeColorRGB(0, 0, 0)
canvas.setLineWidth(0.5)
canvas.line(66, 78, page.BBox[2] - 66, 78)
canvas.setFont('Times-Roman', 10)
canvas.drawString(page.BBox[2]-x, 65, footer_text)
canvas.restoreState()
canvas.showPage()
canvas.save()
DISCLAIMER: Tested on Linux using as input file a pdf file generated by Reportlab. It would probably not work in an arbitrary pdf file.
os.system("libreoffice --headless --invisible --convert-to doc
or something – Retouch