I'm working on a PDF generation script using ReportLab in Python. The script generates a PDF with a client table and some additional information. I have implemented a custom PageNumCanvas class to handle page numbering.(PageNumCanvas is from https://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/)
this is the PageNumCanvas. I override(in save method) the first page to add the page no on a fixed location.
But i need to load the page_count dynamically, in the client table.
class PageNumCanvas(canvas.Canvas):
"""
http://code.activestate.com/recipes/546511-page-x-of-y-with-reportlab/
http://code.activestate.com/recipes/576832/
This below code is taken from the
https://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/
"""
#----------------------------------------------------------------------
def __init__(self, *args, **kwargs):
"""Constructor"""
canvas.Canvas.__init__(self, *args, **kwargs)
self.pages = []
#----------------------------------------------------------------------
def showPage(self):
"""
On a page break, add information to the list
"""
self.pages.append(dict(self.__dict__))
self._startPage()
#----------------------------------------------------------------------
def save(self):
"""
Add the page number to each page (page x of y)
"""
page_count = len(self.pages)
self.__dict__.update(self.pages[0])
self.setFont("Helvetica", 9)
self.drawRightString(270, 679, str(page_count))
for page in self.pages:
self.__dict__.update(page)
self.draw_page_number(page_count)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
#----------------------------------------------------------------------
def draw_page_number(self, page_count):
"""
Add the page number
"""
page = "Page %s of %s" % (self._pageNumber, page_count)
self.setFont("Helvetica", 9)
self.drawRightString(200*mm, 20*mm, page)
class YourPdfClass:
def __init__(self):
pass
def header(self, canvas, doc):
pass
def write_pdf_lines(self, columns_fields, file_path):
pdf_filename = file_path
pdf_document = SimpleDocTemplate(pdf_filename, pagesize=letter
)
# Calculate the available width within the margins
available_width = pdf_document.width
styless = getSampleStyleSheet()
client_data=client_data = [
[
Paragraph(f"Client: <b>{x}</b>", styless['Normal']),
Paragraph(f"Downloaded By: <b>{y}</b>", styless['Normal']),
Paragraph(f"Date and Time: <b>{05-Jan-2024, 03:20 pm}</b>", styless['Normal'])
],
[
Paragraph(f"Records: <b>{z}</b>", styless['Normal']),
Paragraph("Pages:{}", styless['Normal']),
""
]
]
client_table=Table(client_data,
# colWidths=[available_width / 3] * 3,
spaceBefore=10)
# Build the PDF document
print("we started making pdf")
pdf_document.build([client_table],canvasmaker=PageNumCanvas)
def save(self):
"""
Add the page number to each page (page x of y)
"""
page_count = len(self.pages)
self.__dict__.update(self.pages[0])
self.setFont("Helvetica", 9)
self.drawRightString(270, 679, str(page_count))
for page in self.pages:
self.__dict__.update(page)
self.draw_page_number(page_count)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
This load the data in fixed location. but if the dynamic value of other fields are large, it will get bigger, so it will look like misplaced.
Any insights into why this might be happening and suggestions for fixing it would be greatly appreciated. Thank you!
Ok sorry lets try again.
How's about we render the document but don't save it and use PageNumCanvas to count the pages. At this point we know the number of pages and we can update the cell that has the page count re-rendering the document.
using {{TOTAL_PAGES}}
So change the client_data:
client_data = [
# ... (other rows)
[
Paragraph(f"Records: <b>{z}</b>", styless['Normal']),
Paragraph("Pages: <b>{{TOTAL_PAGES}}</b>", styless['Normal']),
""
]
]
and:
def write_pdf_lines(self, columns_fields, file_path):
(your existing code to set up the document and table)
# First Pass: Render the document to count pages
pdf_document.build([client_table], canvasmaker=PageNumCanvas)
# Get the total pages from your PageNumCanvas instance
page_count = len(self.pages)
# Update the placeholder in the client_data
for row in client_data:
for i, cell in enumerate(row):
if isinstance(cell, Paragraph):
text = cell.text
# Replace placeholder with actual page count
if "{{TOTAL_PAGES}}" in text:
row[i] = Paragraph(text.replace("{{TOTAL_PAGES}}",
str(page_count)), styless['Normal'])
# Second Pass: Re-render the document with the updated page count
pdf_document.build([client_table], canvasmaker=PageNumCanvas)
Let me know how you get on. Sorry for the late reply I am quite often away working. Good luck :)