diff --git a/src/calibre/ebooks/pdf/html_writer.py b/src/calibre/ebooks/pdf/html_writer.py
index 5a6acb041f..1daa4412b6 100644
--- a/src/calibre/ebooks/pdf/html_writer.py
+++ b/src/calibre/ebooks/pdf/html_writer.py
@@ -791,7 +791,7 @@ def test_merge_fonts():
PAGE_NUMBER_TEMPLATE = ''
-def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map, page_layout, page_margins_map, pdf_metadata, report_progress):
+def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map, page_layout, page_margins_map, pdf_metadata, report_progress, toc=None):
header_template, footer_template = opts.pdf_header_template, opts.pdf_footer_template
if not footer_template and opts.pdf_page_numbers:
footer_template = PAGE_NUMBER_TEMPLATE
@@ -801,6 +801,7 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
name = create_skeleton(container)
root = container.parsed(name)
body = root[-1]
+ body.attrib.pop('id', None)
body.set('style', 'margin: 0; padding: 0; border-width: 0')
skeleton = xml2text(root, method='html')
job = job_for_name(container, name, Margins(0, 0, 0, 0), page_layout)
@@ -828,6 +829,43 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
}}
'''.format(justify=justify)))
+ def create_toc_stack(iterator):
+ ans = []
+ for level, child in iterator:
+ pdf_loc = getattr(child, 'pdf_loc', None)
+ if pdf_loc is not None and pdf_loc.pagenum > 0:
+ ans.append((level, pdf_loc.pagenum, child.title))
+ return ans
+
+ def stack_to_map(stack):
+ ans = []
+ stack_pos = 0
+ current, page_for_current, level_for_current = '', -1, -1
+ stack_len = len(stack)
+ for page in range(1, pdf_doc.page_count() + 1):
+ while stack_pos < stack_len:
+ level, pagenum, title = stack[stack_pos]
+ if pagenum != page:
+ break
+ if pagenum != page_for_current or level > level_for_current:
+ page_for_current = pagenum
+ level_for_current = level
+ current = title
+ stack_pos += 1
+ ans.append(current)
+ return ans
+
+ if toc is None:
+ page_toc_map = stack_to_map(())
+ toplevel_toc_map = stack_to_map(())
+ else:
+ page_toc_map = stack_to_map(create_toc_stack(toc.iterdescendants(level=0)))
+
+ def tc():
+ for x in toc:
+ yield 0, x
+ toplevel_toc_map = stack_to_map(create_toc_stack(tc()))
+
def create_iframe(margins, f, is_footer=False):
style = {
'margin-left': '{}pt'.format(margins.left),
@@ -840,15 +878,17 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
)
def format_template(template, page_num):
- # TODO: _SECTION_ and _TOP_LEVEL_SECTION_
- template = template.replace('_PAGENUM_', unicode_type(page_number_display_map[page_num]))
extra_style = 'header, footer { margin: 0; padding: 0; border-width: 0; height: 100vh; display: flex; align-items: center }'
if page_num % 2:
extra_style += '.even_page { display: none }'
else:
extra_style += '.odd_page { display: none }'
+
+ template = template.replace('_PAGENUM_', unicode_type(page_number_display_map[page_num]))
template = template.replace('_TITLE_', prepare_string_for_xml(pdf_metadata.title, True))
template = template.replace('_AUTHOR_', prepare_string_for_xml(pdf_metadata.author, True))
+ template = template.replace('_TOP_LEVEL_SECTION_', prepare_string_for_xml(toplevel_toc_map[page_num - 1]))
+ template = template.replace('_SECTION_', prepare_string_for_xml(page_toc_map[page_num - 1]))
template += ''.format(extra_style)
repl = skeleton.replace('