Add hyperlink to footer that directs to Table of Contents using ReportLab
Asked Answered
B

0

1

The following ReportLab code generates a starting template that I am (almost) pleased with. The missing piece of the puzzle is to add clickable "Back To Contents" text at the left hand side of the footer, on every page.

Any footer wizards out there?

from datetime import datetime
from reportlab.pdfgen import canvas
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
from reportlab.platypus.frames import Frame
from reportlab.lib.units import cm
from reportlab.platypus import Paragraph, Spacer, PageBreak
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.lib.pagesizes import LETTER


class FooterCanvas(canvas.Canvas):

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

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

    def save(self):
        page_count = len(self.pages)
        for page in self.pages:
            self.__dict__.update(page)
            if (self._pageNumber > 1):
                self.draw_canvas(page_count)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_canvas(self, page_count):
        page = f"Page {self._pageNumber} of {page_count}" 
        x = 128
        self.saveState()
        self.setStrokeColorRGB(0, 0, 0)
        self.setLineWidth(0.5)
        self.line(66, 78, LETTER[0] - 66, 78)
        self.setFont('Helvetica', 10)
        self.drawString(LETTER[0]-x, 65, page)
        self.restoreState()


class MyDocTemplate(BaseDocTemplate):

    def __init__(self, filename, **kw):
        self.allowSplitting = 0
        BaseDocTemplate.__init__(self, filename, **kw)
        template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])
        self.addPageTemplates(template)


    def afterFlowable(self, flowable):
            "Registers TOC entries."
            if flowable.__class__.__name__ == 'Paragraph':
                text = flowable.getPlainText()
                style = flowable.style.name
                if style == 'Heading1':
                    self.notify('TOCEntry', (0, text, self.page))
                if style == 'Heading2':
                    key = 'h2-%s' % self.seq.nextf('heading2')
                    self.canv.bookmarkPage(key)
                    self.notify('TOCEntry', (1, text, self.page, key))
                if style == 'Heading3':
                    key = 'h3-%s' % self.seq.nextf('heading3')
                    self.canv.bookmarkPage(key)
                    self.notify('TOCEntry', (2, text, self.page, key))


timestamp_now = datetime.now().strftime("%Y-%m-%dT%H_%M_%S")
date_now = datetime.now().strftime("%d.%m.%Y")

doc = MyDocTemplate(
  filename="mydoc.pdf",
  author="Person A"
  )

# Define styles
styles = getSampleStyleSheet()

content = []

# Add title to the PDF
title = Paragraph(text="My Document", style=styles["Title"])
content.append(title)

content.append(Spacer(width=0 * cm, height=15 * cm))
content.append(Paragraph(text="Authors", style=styles['h4']))
for author in ["Person A", "Person B", "Person C"]:
        author_para = Paragraph(author, styles["Italic"])
        content.append(author_para)


content.append(Spacer(width=0 * cm, height=4 * cm))
date_para = Paragraph(
  text=f"Document Compiled on {date_now}",
  style=ParagraphStyle(name='centered_date', parent=styles["h4"], alignment=1)
)
content.append(date_para)

# Add a table of contents
content.append(PageBreak())
toc = TableOfContents()


toc.levelStyles = [
  toc.getLevelStyle(0),
  ParagraphStyle(name='blue_hyperlinks', parent=toc.getLevelStyle(1), textColor=colors.blue),
  ParagraphStyle(name='blue_hyperlinks', parent=toc.getLevelStyle(2), textColor=colors.blue)
  ]


content.append(toc)

content.append(PageBreak())
content.append(Paragraph(text="This is an h1 heading", style=styles['Heading1']))
content.append(Paragraph(text="This is an h2 heading", style=styles['Heading2']))

content.append(PageBreak())
content.append(Paragraph(text="This is an h3  heading", style=styles['Heading3']))

content.append(PageBreak())
content.append(Paragraph(text="This is an h2  heading", style=styles['Heading2']))
content.append(Paragraph(text="This is an h3  heading", style=styles['Heading3']))

doc.multiBuild(story=content, canvasmaker=FooterCanvas)
Borglum answered 16/2 at 18:56 Comment(1)
just noticed that the in the code provided, the hyperlinks in the contents page always direct up to the first page :/Borglum

© 2022 - 2024 — McMap. All rights reserved.