A multiline(paragraph) footer and header in reportlab

前端 未结 4 1764
一向
一向 2020-12-15 20:38

What is a best way to have a footer and header in reportlab, that not just a single line, that can be drawed with canvas.drawString in onPage function. Didn`t find a way to

4条回答
  •  悲&欢浪女
    2020-12-15 21:01

    Jochen's answer is great, but I found it incomplete. It works for footers, but not for headers as Reportlab will draw all the flowables on top of the header. You need to be sure the size of the Frame you create excludes the space taken up by the header so flowabls are not printed on top of the header.

    Using jochen's code, here is a complete example for headers:

    from reportlab.lib.pagesizes import letter, cm
    from reportlab.lib.styles import getSampleStyleSheet
    from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Paragraph
    from functools import partial
    
    styles = getSampleStyleSheet()
    styleN = styles['Normal']
    styleH = styles['Heading1']
    
    def header(canvas, doc, content):
        canvas.saveState()
        w, h = content.wrap(doc.width, doc.topMargin)
        content.drawOn(canvas, doc.leftMargin, doc.height + doc.topMargin - h)
        canvas.restoreState()
    
    doc = BaseDocTemplate('test.pdf', pagesize=letter)
    frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height-2*cm, id='normal')
    header_content = Paragraph("This is a multi-line header.  It goes on every page.  " * 8, styleN)
    template = PageTemplate(id='test', frames=frame, onPage=partial(header, content=header_content))
    doc.addPageTemplates([template])
    
    text = []
    for i in range(111):
        text.append(Paragraph("This is line %d." % i, styleN))
    doc.build(text)
    

    Pay attention to the decleration of the Frame, it subtracts 2 cm from the height of the frame to allow room for the header. The flowables will be printed within the frame so you can change the size of the frame to allow for various sizes of headers.

    I also find that I usually need to pass variables into the header, so I used a partial function assigned to onPage so that the content of the header can be passed in. This way you can have a variable header based on the content of the page.

提交回复
热议问题