Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page number incorrect when using TableOfContents.render_toc #1343

Open
mschoettle opened this issue Jan 9, 2025 · 2 comments
Open

Page number incorrect when using TableOfContents.render_toc #1343

mschoettle opened this issue Jan 9, 2025 · 2 comments

Comments

@mschoettle
Copy link

mschoettle commented Jan 9, 2025

This is a follow-up to #136.

When using the new TableOfContents.render_toc and the table of contents spans more than one page, the page numbers are incorrect.

Another issue (when using page labels) is that doing "Page x of y" (via {nb}) is not possible because the last page number can then be incorrect. And when using roman numerals for the front matter it shows the total pages.

Error details

When running the below MRE, the following issues occur:

  • page 2 (ToC) has an incorrect page number (57)
  • all content pages are shifted by one, i.e., section 1 has page 2 instead of 3

Minimal code
Please include some minimal Python code reproducing your issue:

from fpdf import FPDF
from fpdf.outline import TableOfContents

NUMBER_SECTIONS = 56


def p(pdf, text, **kwargs):
    pdf.multi_cell(
        w=pdf.epw,
        h=pdf.font_size,
        text=text,
        new_x="LMARGIN",
        new_y="NEXT",
        **kwargs,
    )


class CustomFPDF(FPDF):
    def footer(self) -> None:
        self.set_y(-15)
        self.set_font("Helvetica", size=8)
        self.cell(w=0, h=10, text="Page %s" % self.page_no(), align="C")
        self.set_font("Helvetica", size=12)


pdf = CustomFPDF()
pdf.set_font("Helvetica", size=12)
pdf.add_page()
pdf.start_section("Test", level=0)
pdf.insert_toc_placeholder(TableOfContents().render_toc, allow_extra_pages=True)

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."

for i in range(1, NUMBER_SECTIONS):
    if i > 1:
        pdf.add_page()
    pdf.start_section(f"Section {i}", level=1)
    p(pdf, f"Section {i}")
    p(pdf, text)

pdf.output('output.pdf')

MRE 2

When using set_page_label and get_page_label it is somewhat better:

from fpdf import FPDF
from fpdf.outline import TableOfContents

NUMBER_SECTIONS = 56


def p(pdf, text, **kwargs):
    pdf.multi_cell(
        w=pdf.epw,
        h=pdf.font_size,
        text=text,
        new_x="LMARGIN",
        new_y="NEXT",
        **kwargs,
    )


class CustomFPDF(FPDF):
    def footer(self) -> None:
        self.set_y(-15)
        self.set_font("Helvetica", size=8)
        self.cell(w=0, h=10, text="Page %s" % self.get_page_label(), align="C")
        self.set_font("Helvetica", size=12)


pdf = CustomFPDF()
pdf.set_font("Helvetica", size=12)
pdf.add_page()
pdf.set_page_label(label_style="D")
pdf.start_section("Test", level=0)
pdf.insert_toc_placeholder(TableOfContents().render_toc, allow_extra_pages=True)

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."

for i in range(1, NUMBER_SECTIONS):
    if i > 1:
        pdf.add_page()
    pdf.start_section(f"Section {i}", level=1)
    p(pdf, f"Section {i}")
    p(pdf, text)

pdf.output('output.pdf')

Issues:

  • all content pages are shifted by 1 (section 1 has page 2 instead of 3)

MRE 3

Making use of roman numerals before the actual content works with the exception of adding the total page count:

from fpdf import FPDF
from fpdf.outline import TableOfContents

NUMBER_SECTIONS = 56


def p(pdf, text, **kwargs):
    pdf.multi_cell(
        w=pdf.epw,
        h=pdf.font_size,
        text=text,
        new_x="LMARGIN",
        new_y="NEXT",
        **kwargs,
    )


class CustomFPDF(FPDF):
    def footer(self) -> None:
        self.set_y(-15)
        self.set_font("Helvetica", size=8)
        self.cell(w=0, h=10, text="Page %s of {nb}" % self.get_page_label(), align="C")
        self.set_font("Helvetica", size=12)


pdf = CustomFPDF()
pdf.set_font("Helvetica", size=12)
pdf.add_page()
pdf.set_page_label(label_style="R")
pdf.start_section("Test", level=0)
pdf.insert_toc_placeholder(TableOfContents().render_toc, allow_extra_pages=True)

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."

pdf.set_page_label(label_style="D")

for i in range(1, NUMBER_SECTIONS):
    if i > 1:
        pdf.add_page()
    pdf.start_section(f"Section {i}", level=1)
    p(pdf, f"Section {i}")
    p(pdf, text)

pdf.output('output.pdf')

Environment
Please provide the following information:

  • Operating System: Windows, Mac OSX, Linux flavour...
  • Python version: 3.11.x
  • fpdf2 version used: 2.8.2
@andersonhc
Copy link
Collaborator

The numbering issue when using allow_extra_pages is a known limitation. The only workaround I’ve found is to use page labels, so I’ve added notes about this in the documentation and docstrings.

As for your MRE3 example, the extra page appears because insert_toc_placeholder() automatically inserts a page break, and you also call add_page() before writing the first section. You can fix this by adjusting your loop so add_page() is only called after the first section:

for i in range(1, NUMBER_SECTIONS):
    if i > 1:
        pdf.add_page()
    pdf.start_section(f"Section {i}", level=1)
    p(pdf, f"Section {i}")
    p(pdf, text)

@mschoettle
Copy link
Author

Thanks! I added this to all MREs and updated the issues.

MRE3 works with using roman numerals for the ToC and then arabic numerals for the content. The only problem with that is that the total page count (via {nb}) is incorrect in both cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants