Welcome, guest | Sign In | My Account | Store | Cart

This recipe is based on Recipe 546511 which does not work reliably if there are images in the content.

Python, 60 lines
 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm

class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        canvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        """add page info to each page (page x of y)"""
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page_number(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_page_number(self, page_count):
        self.setFont("Helvetica", 7)
        self.drawRightString(200*mm, 20*mm,
            "Page %d of %d" % (self._pageNumber, page_count))

def main():
    import sys
    import urllib2
    from cStringIO import StringIO
    from reportlab.platypus import SimpleDocTemplate, Image, Paragraph, PageBreak
    from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet

    #This is needed because ReportLab accepts the StringIO as a file-like object,
    #but doesn't accept urllib2.urlopen's return value
    def get_image(url):
        u = urllib2.urlopen(url)
        return StringIO(u.read())

    styles = getSampleStyleSheet()
    styleN = ParagraphStyle(styles['Normal'])

    # build doc

    if len(sys.argv) > 1:
        fn = sys.argv[1]
    else:
        fn = "filename.pdf"
    doc = SimpleDocTemplate(open(fn, "wb"))
    elements = [
        Paragraph("Hello,", styleN),
        Image(get_image("http://www.red-dove.com/images/rdclogo.gif")),
        PageBreak(),
        Paragraph("world!", styleN),
        Image(get_image("http://www.python.org/images/python-logo.gif")),
    ]
    doc.build(elements, canvasmaker=NumberedCanvas)

if __name__ == "__main__":
    main()

The earlier recipe only saved part of the page state, which causes failure when the content contains images (either the images don't appear in the PDF, or the reader complains that the PDF is corrupt). This version saves the entire state - which may be overkill, but seems to work.