This approach at the common "page x of y" problem avoids a double pass (creating the pdf document twice). This is achieved by a customized canvas class which saves the codes into a list instead of creating postscript on pagebreak (showPage). When the document should be saved, we recall each page and draw the pageinfo. The trick is that you can modify the canvas of each page until it is saved (meaning you already know the total pagecount).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | from reportlab.pdfgen import canvas
from reportlab.platypus import SimpleDocTemplate
class NumberedCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._codes = []
def showPage(self):
self._codes.append({'code': self._code, 'stack': self._codeStack})
self._startPage()
def save(self):
"""add page info to each page (page x of y)"""
# reset page counter
self._pageNumber = 0
for code in self._codes:
# recall saved page
self._code = code['code']
self._codeStack = code['stack']
self.setFont("Helvetica", 7)
self.drawRightString(200*mm, 20*mm,
"page %(this)i of %(total)i" % {
'this': self._pageNumber+1,
'total': len(self._codes),
}
)
canvas.Canvas.showPage(self)
# build doc
doc = SimpleDocTemplate("filename.pdf")
... # add your report definition here
doc.build(elements, canvasmaker=NumberedCanvas)
|
We were not satisfied with the solutions we found (e.g. http://eccentric.cx/wordpress/2006/04/04/using-reportlab-forms-for-page-numbers/). It is suboptimal to draw the pageinfo at different times, mainly because you don't know how much space the total pagecount will use up. That makes it difficult to align the pageinfo (particulary on the right side).
This is the nicest and cleanest solution I've come across for this type of pagination. The only problem I'm having is that the png image I'm inserting displays when no canvasmaker argument is supplied to doc.build, but doesn't display when I use this canvas. I'm not terribly familiar with ReportLab so any help is appreciated.
Thanks, Patrick
The nicest solution I've found but:
I've tried this code but I can't see the resulting pdf. Can you post a complete example with pdf output ?
Thanks Franco
@franco
Put this line at the end of save() method outside for loop. This actually saves pdf to file.
self._doc.SaveToFile(self._filename, self)
Artur
I'm having the same problem as the first poster. When I use image flowables with this canvas, the space is left for the image (i.e. there is a gap of the proper size), but the image itself is not shown. Does anyone have a fix for that?
See the improved Recipe 576832 which should work with images (a test is included as part of the recipe).
I can create a pdf with clickable bookmarks in the table of contents (toc), or I can create a pdf with "x of y" page numbering, but table of contents clickable appears to break when I try to do both.