I already asked this question but there's no answer yet, so I want to take a look at Reportlab which seems to be actively developed and better than fpdf python library.
I've already seen this question The answer given seems more or less the same as this blog post. Anyhow, the script shown is full of errors, but I don't want to vote it down, the OP accepted it, seemed to solve his problem, who am I to argue, I'd rather ask another question.
First of all you need to import
from reportlab.pdfgen.canvas import Canvas
and it's not canvas
it's Canvas
and then you can't just do
Canvas.restoreState()
or Canvas.saveState()
Maybe there are more errors, I'd rather use another example. I spent the entire night yesterday trying to make that snippet work and couldn't.
Is there another method to create footer? A specific method I want to ask about is this, the guy do a for loop, on row[0]
he writes something, row[1]
something
I counted on a LibreOffice document, which is A4, using Liberation Serif
12, there are 49 rows. Assuming that on average there are 45 rows, depending on the font size, and the footer font size is 8, can't one just insert the footer like this x=row[45]
and then increment x based on the page number? wouldn't that be a far easier solution?
If I can detect that the end of file, or the last line on which text is inserted, then I can do it, I think.
If you refer to my other question, you would notice that I convert powerpoint, excel and word to pdf and then insert a footer.
If there is a library that works on linux and windows covert powerpoint and excel to word, then add the footer then convert to pdf, it would be great, since I think it's easier to work with documents then PDFs
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.