Un pie de página multilínea (párrafo) y encabezado en reportlab

¿Cuál es la mejor manera de tener un pie de página y un encabezado en reportlab, que no solo una sola línea, que se pueda dibujar con canvas.drawString en la función onPage? No encontró una manera de poner algo como Párrafo en el encabezado / pie de página en la función onPage. ¿Cuál es la mejor manera de manejar esto? ¿Hay una manera de poner un párrafo en pie de página?

Puede usar comandos de dibujo arbitrarios en la función onPage, así que solo puede dibujar un párrafo (consulte la sección 5.3 en la guía del usuario de reportlab ) de su función.

Aquí hay un ejemplo completo:

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

La respuesta de Jochen es genial, pero la encontré incompleta. Funciona para los pies de página, pero no para los encabezados, ya que Reportlab dibujará todos los elementos fluidos en la parte superior del encabezado. Debe asegurarse de que el tamaño del Marco que crea excluye el espacio ocupado por el encabezado, por lo que los flowabls no se imprimen en la parte superior del encabezado.

Usando el código de Jochen, aquí hay un ejemplo completo para los encabezados:

 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.restreState() 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) 

Preste atención a la decoración del Marco, que resta 2 cm de la altura del marco para dejar espacio para el encabezado. Los materiales fluidos se imprimirán dentro del marco para que pueda cambiar el tamaño del marco para permitir varios tamaños de encabezados.

También encuentro que generalmente necesito pasar variables en el encabezado, así que usé una función parcial asignada a onPage para que el contenido del encabezado pueda pasar. De esta manera, puede tener un encabezado variable basado en el contenido de la página. .

Sé que esto es un poco viejo, pero he encontrado este problema y pude resolverlo. Cuando tienes más de una página en tu PDF y quieres tener el pie de página / encabezado en cada página, debes usar NextPageTemplate('template_id') . Solo estoy escribiendo el código relevante, ya que el rest se muestra en el ejemplo anterior de @jochen.

En mi caso, estaba usando PageBreak() y me tomó un tiempo entender por qué solo estaba obteniendo el pie de página en la primera página.

 from reportlab.platypus import Paragraph, PageBreak, PageTemplate, Frame, NextPageTemplate frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal') template = PageTemplate(id='footer', onPage=footer, frames=[frame]) # add a NextPageTemplate before a PageBreak to have the footer in the next page text.append(Paragraph('some text', style)), text.append(NextPageTemplate('footer')), # this will make the footer to be on the next page if exists text.append(PageBreak()) doc.build(text) 

Enfoque adicional para agregar el encabezado o el pie de página en todas las páginas: existen argumentos para que el método de comstackción haga esto.

No uses el marco y la plantilla en la respuesta de jochen. En la última línea, use

 doc.build(text, onFirstPage=footer, onLaterPages=footer) 

El rest del enfoque será el mismo que desde Jochen.