fpdf2 Text Index
Adds a text index to fpdf2, based on the documentation and source code of Math Gemmell's Text Index:
from fpdf2_textindex import FPDF, TextIndexRenderer
pdf = FPDF()
pdf.add_page()
pdf.set_font('helvetica', size=12)
# Adding text index entry "example
pdf.cell(text="example{^}", markdown=True)
# Add the text index to a page
pdf.add_page()
pdf.insert_index_placeholder(TextIndexRenderer().render_text_index)
# Save as pdf
pdf.output("example.pdf")
The text index will have a single entry:
- example, 1
Installation
Using pip:
# Install
pip install fpdf2_textindex
# Keep it updated
pip upgrade fpdf2_textindex
Using uv:
# Install
uv install fpdf2_textindex
# Keep it updated
uv upgrade fpdf2_textindex
Adding Text Index Entries
Use the text index-syntax to define index directives in a text:
Most mechanical keyboard firmware{^} supports the use of [key combinations]{^}.
Print it in the PDF by enabling markdown in fpdf2.FPDF.cell or
fpdf2.FPDF.multi_cell:
pdf = FPDF()
pdf.add_page()
pdf.set_font('helvetica', size=12)
pdf.cell(
text="Most mechanical keyboard firmware{^} supports the use of [key combinations]{^}.",
markdown=True,
)
...
For a complete documentation of the supported text index directives, see the excellent documentation of Math Gemmell.
The only difference to this documentation is the adaption of the emphasis to the markdown style of fpdf2.
So the text:
This entry will be **emphasised**{^} in the index.
This expanded entry will be **[not emphasised]{^"* (nope)"}** in the index but here in the text.
will be printed in the PDF as:
This entry will be emphasised in the index.
This expanded entry will be not emphasised in the index but here in the text.
Similarly, the marks for italics __, underline -- and strikethrough ~~ are
supported.
Inserting the Text Index
Use the adapted FPDF-class of this package that offers a
fpdf2_textindex.FPDF.insert_index_placeholder-method to define a placeholder
for the text index. At least, one page break is triggered after inserting
the text index:
...
pdf.add_page()
pdf.insert_index_placeholder(render_index_function)
Parameters:
render_index_function: Function called to render the text index, receiving two parameters:pdf, an adaptedFPDFinstance, andentries, a list offpdf2_textindex.TextIndexEntrys. A reference implementation is supported throughfpdf2_textindex.TextIndexRenderer.render_text_index.pages: The number of pages that the text index will span, including the current one. A page break occurs for each page specified.allow_extra_pages: IfTrue, allows unlimited additional pages to be added to the text index as needed. These extra text index pages are initially created at the end of the document and then reordered when the final PDF is produced.
Text Index Directive Syntax
__example__{^foo>"\* text"#demo |bar;+baz>fiz [whiz] ~z !}
1 2 3 4 5 6
The index directive in the example will:
- Create a reference from the
"example text"subentry within the"foo"top-level entry that leads to the directive's location in the text on the corresponding PDF page. If the entry or subentry do not exist, they will be created. - Define the alias
"#demo"for the path to the subentry ("foo">"example text"). - Adds cross-references to the entry:
- A SEE-cross reference to the
"bar"top-level entry, - A SEE ALSO-cross reference to the
"fiz"subentry within the"baz"top-level entry.
- A SEE-cross reference to the
- Apply the
"whiz"suffix to the directive's reference locator. - Sort the entry as if its heading starts with
"z". - Apply an emphasis (bold) to the mark's reference locator.
The resulting index with page numbers would look like:
- bar, 3
- baz
- fiz, 5
- foo
- example text, 6 (see bar). See also baz: fiz
if index directives with page references (locators) for "bar" and "baz" >
"fiz" have been added as well.
In a real index, this would provoke an error, because either you set a reference
locator to a PDF page and a SEE ALSO-cross reference or a SEE- and a
SEE ALSO-cross reference, but not all three at the same time.
Alternatively, you can deactivate strict-mode by setting
FPDF.STRICT_INDEX_MODE = False which would automatically convert the
SEE-cross reference into a SEE ALSO-cross reference, accompanied by a
warning.
Example
An example can be created by
example/textindex_figures.py
and produces
textindex_figures.pdf
with all the examples from
Math Gemmell's website.
Internals - Idea
For the curious reader:
This package adds a markdown parser to fpdf2
that intercepts markdown-styled strings to fpdf2.FPDF.cell or
fpdf2.FPDF.multi_cell and translates
Math Gemmell's Text Index-directives into
markdown-links with an unset internal PDF link as destination, while the created
index entries are internally saved:
"example{^}"
=
"[example](#idx0)"
+
TextIndexEntry(label="example", references=[Reference(start_id=0)])
When creating the actual text index in the PDF, all unset internal PDF link annotations that are related to the text index (identified by an unique id schema) are collected and its page, x/y-position on the page added to the entry's references:
{"idx0": LinkLocation(page=3, x=20.0, y=40.0, ...), ...}
->
TextIndexEntry.references[0].start_location = LinkLocation(page=3, x=20.0, y=40.0, ...)
Finally, a render_index_function similar to the
official TOC-implementation of fpdf2
is used to render the index. The package supports a reference implementation,
but the user can implement its own version if necessary.
The reference index implementation
fpdf2_textindex.TextIndexRenderer.render_text_index would render the example
as
"example, 3"
in the text index (assuming it has been written on page 3 in the PDF).
The unset link annotation in the text is pointed to this entry in the index and, thus, is finally set.
In the reference index implementation, inverted links are added as well:
To create a connection of the index entry to the text page, the printed page
number will point to the text page, where the text index directive has been
set.
So clicking on "example" on the text page will lead to corresponding entry in
the text index. Clicking on the reference (locator) in the text index, page
"3", will return the reader to the text page.
Cross-references are interconnected in the same way but inside of the text
index.
Metadata
Release files for fpdf2-textindex 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fpdf2_textindex-0.1.1.tar.gz | 65.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fpdf2_textindex-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 137.5 kB
Release files / fpdf2_textindex-0.1.1.tar.gz
| Download URL | fpdf2_textindex-0.1.1.tar.gz |
|---|---|
| Size | 65.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
670f3d16acd86bc9f718d6ea8024f6c8a45bc80e138b7ebdbbed57d6a5ee6582
|
|
BLAKE2b-256 checksum How to use checksums |
f8a2cd6312f24fc153bb13a5997a680696369c9c13ddee1849c3b52fa25753ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fpdf2_textindex-0.1.1-py3-none-any.whl
| Download URL | fpdf2_textindex-0.1.1-py3-none-any.whl |
|---|---|
| Size | 71.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1d3a12f0b116427b89806bbf0415b96dac9a002d2cea600d0411213003c94eb6
|
|
BLAKE2b-256 checksum How to use checksums |
b4a37961d159565d3ef94a347e2ade3a722970ed96c7f858c471c8763f0aee35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|