From 3e3503ec64eaaf3dad2c5dfcc9c1725e9c66a6ea Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 2 Jul 2020 09:41:22 +0200 Subject: [PATCH] Add table of contents to PDFs based on h1 tags For each h1 tag in the notebook we add a bookmark to the PDF, which in turn is rendered as a table of contents by most PDF viewers. --- example.ipynb | 6 +-- example.pdf | Bin 359302 -> 359594 bytes notebook_as_pdf/__init__.py | 73 ++++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/example.ipynb b/example.ipynb index f9db850..5c14221 100644 --- a/example.ipynb +++ b/example.ipynb @@ -138,11 +138,9 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "source": [] + "source": ["# A h1 title\n"] } ], "metadata": { diff --git a/example.pdf b/example.pdf index 77ced1c3cd4876acd789f4fe9098ccb079c7a844..3b0c90d3b59964858a70504b1609db52702f20c4 100644 GIT binary patch delta 24313 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 delta 24035 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 OFocAMM^#Ua { + var vals = [] + for (const elem of document.getElementsByTagName("h1")) { + //console.log(elem, getOffset(elem).top, elem.innerText) + vals.push({ top: getOffset(elem).top, text: elem.innerText }) + } + return vals + }""" + ) + await page.pdf( { "path": pdf_file, @@ -87,12 +114,47 @@ async def html_to_pdf(html_file, pdf_file, pyppeteer_args=None): await browser.close() + return h1s + + +def finish_pdf(pdf_in, pdf_out, notebook, headings): + """Add finishing touches to the PDF file. + + To make the PDF nicer we: -def attach_notebook(pdf_in, pdf_out, notebook): + * attach the original notebook to the PDF for reference + * add bookmarks pointing to the headers in a notebook + """ pdf = PyPDF2.PdfFileWriter() pdf.appendPagesFromReader(PyPDF2.PdfFileReader(pdf_in, "rb")) pdf.addAttachment(notebook["file_name"], notebook["contents"]) + for heading in headings: + page_num = heading["top"] // (200 * 72) + + page_height = pdf.getPage(page_num).artBox[-1] + + # position on the page as measured from the bottom of the page + # with a bit of leeway so that clicking the bookmark doesn't put + # the heading right at the border + on_page_pos = page_height - (heading["top"] % (200 * 72)) + 20 + + # there is no nice way of passing the "zoom arguments" at the very + # end of the function call without explicitly listing all the parameters + # of the function. We can't use keyword arguments :( + pdf.addBookmark( + heading["text"], + page_num, + None, + None, + False, + False, + "/XYZ", + 0, + on_page_pos, + None, + ) + with open(pdf_out, "wb") as fp: pdf.write(fp) @@ -116,7 +178,9 @@ async def notebook_to_pdf( with tempfile.NamedTemporaryFile(suffix=".html") as f: f.write(exported_html.encode()) f.flush() - await html_to_pdf(f.name, pdf_path, pyppeteer_args) + heading_positions = await html_to_pdf(f.name, pdf_path, pyppeteer_args) + + return heading_positions class PDFExporter(Exporter): @@ -161,7 +225,7 @@ def from_notebook_node(self, notebook, resources=None, **kwargs): pdf_fname2 = os.path.join(name, "output-with-attachment.pdf") pyppeteer_args = ["--no-sandbox"] if self.no_sandbox else None - self.pool.submit( + heading_positions = self.pool.submit( asyncio.run, notebook_to_pdf( notebook, @@ -174,13 +238,14 @@ def from_notebook_node(self, notebook, resources=None, **kwargs): ).result() resources["output_extension"] = ".pdf" - attach_notebook( + finish_pdf( pdf_fname, pdf_fname2, { "file_name": f"{resources['metadata']['name']}.ipynb", "contents": nbformat.writes(notebook).encode("utf-8"), }, + heading_positions, ) with open(pdf_fname2, "rb") as f: