Module fpdf.outline
Quoting section 8.2.2 "Document Outline" of the 2006 PDF spec 1.7:
The document outline consists of a tree-structured hierarchy of outline items (sometimes called bookmarks), which serve as a visual table of contents to display the document’s structure to the user.
The contents of this module are internal to fpdf2, and not part of the public API. They may change at any time without prior warning or any deprecation period, in non-backward-compatible ways.
Functions
def build_outline_objs(sections)
-
Expand source code Browse git
def build_outline_objs(sections): """ Build PDF objects constitutive of the documents outline, and yield them one by one, starting with the outline dictionary """ outline = OutlineDictionary() yield outline outline_items = [] last_outline_item_per_level = {} for section in sections: outline_item = OutlineItemDictionary( title=section.name, dest=section.dest, struct_elem=section.struct_elem, ) yield outline_item if section.level in last_outline_item_per_level: last_outline_item_at_level = last_outline_item_per_level[section.level] last_outline_item_at_level.next = outline_item outline_item.prev = last_outline_item_at_level if section.level - 1 in last_outline_item_per_level: parent_outline_item = last_outline_item_per_level[section.level - 1] else: parent_outline_item = outline outline_item.parent = parent_outline_item if parent_outline_item.first is None: parent_outline_item.first = outline_item parent_outline_item.last = outline_item parent_outline_item.count += 1 outline_items.append(outline_item) last_outline_item_per_level[section.level] = outline_item last_outline_item_per_level = { level: oitem for level, oitem in last_outline_item_per_level.items() if level <= section.level } return [outline] + outline_items
Build PDF objects constitutive of the documents outline, and yield them one by one, starting with the outline dictionary
Classes
class OutlineDictionary (**kwargs)
-
Expand source code Browse git
class OutlineDictionary(PDFObject): __slots__ = ("_id", "type", "first", "last", "count") # RAM usage optimization def __init__(self, **kwargs): super().__init__(**kwargs) self.type = "/Outlines" self.first = None self.last = None self.count = 0 def __str__(self): return f"OutlineDictionary(count={self.count})"
Ancestors
Instance variables
var count
-
Expand source code Browse git
class OutlineDictionary(PDFObject): __slots__ = ("_id", "type", "first", "last", "count") # RAM usage optimization def __init__(self, **kwargs): super().__init__(**kwargs) self.type = "/Outlines" self.first = None self.last = None self.count = 0 def __str__(self): return f"OutlineDictionary(count={self.count})"
var first
-
Expand source code Browse git
class OutlineDictionary(PDFObject): __slots__ = ("_id", "type", "first", "last", "count") # RAM usage optimization def __init__(self, **kwargs): super().__init__(**kwargs) self.type = "/Outlines" self.first = None self.last = None self.count = 0 def __str__(self): return f"OutlineDictionary(count={self.count})"
var last
-
Expand source code Browse git
class OutlineDictionary(PDFObject): __slots__ = ("_id", "type", "first", "last", "count") # RAM usage optimization def __init__(self, **kwargs): super().__init__(**kwargs) self.type = "/Outlines" self.first = None self.last = None self.count = 0 def __str__(self): return f"OutlineDictionary(count={self.count})"
var type
-
Expand source code Browse git
class OutlineDictionary(PDFObject): __slots__ = ("_id", "type", "first", "last", "count") # RAM usage optimization def __init__(self, **kwargs): super().__init__(**kwargs) self.type = "/Outlines" self.first = None self.last = None self.count = 0 def __str__(self): return f"OutlineDictionary(count={self.count})"
Methods
def content_stream(self)
-
Inherited from:
PDFObject
.content_stream
Subclasses can override this method to indicate the presence of a content stream
def serialize(self, obj_dict=None)
-
Inherited from:
PDFObject
.serialize
Serialize the PDF object as an obj<>endobj text block
class OutlineItemDictionary (title: str,
dest: Destination = None,
struct_elem: StructElem = None)-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
Ancestors
Instance variables
var count
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var dest
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var first
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var last
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var next
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var parent
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var prev
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var struct_elem
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
var title
-
Expand source code Browse git
class OutlineItemDictionary(PDFObject): __slots__ = ( # RAM usage optimization "_id", "title", "parent", "prev", "next", "first", "last", "count", "dest", "struct_elem", ) def __init__( self, title: str, dest: Destination = None, struct_elem: StructElem = None, ): super().__init__() self.title = PDFString(title, encrypt=True) self.parent = None self.prev = None self.next = None self.first = None self.last = None self.count = 0 self.dest = dest self.struct_elem = struct_elem def __str__(self): return f"OutlineItemDictionary(title={self.title}, dest={self.dest})"
Methods
def content_stream(self)
-
Inherited from:
PDFObject
.content_stream
Subclasses can override this method to indicate the presence of a content stream
def serialize(self, obj_dict=None)
-
Inherited from:
PDFObject
.serialize
Serialize the PDF object as an obj<>endobj text block
class OutlineSection (name, level, page_number, dest, struct_elem=None)
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
OutlineSection(name, level, page_number, dest, struct_elem=None)
Instance variables
var dest : Destination
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
var level : int
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
var name : str
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
var page_number : int
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
var struct_elem : StructElem | None
-
Expand source code Browse git
@dataclass class OutlineSection: # RAM usage optimization __slots__ = ("name", "level", "page_number", "dest", "struct_elem") name: str level: int page_number: int dest: Destination struct_elem: Optional[StructElem] # With __slots__ used, we need an __init__ method in order to define default values: def __init__(self, name, level, page_number, dest, struct_elem=None): self.name = name self.level = level self.page_number = page_number self.dest = dest self.struct_elem = struct_elem
class TableOfContents (text_style: TextStyle | None = None,
use_section_title_styles=False,
level_indent=7.5,
line_spacing=1.5,
ignore_pages_before_toc=True)-
Expand source code Browse git
class TableOfContents: """ A reference implementation of a Table of Contents (ToC) for use with `fpdf2`. This class provides a customizable Table of Contents that can be used directly or subclassed for additional functionality. To use this class, create an instance of `TableOfContents`, configure it as needed, and pass its `render_toc` method as the `render_toc_function` argument to `FPDF.insert_toc_placeholder()`. """ def __init__( self, text_style: Optional[TextStyle] = None, use_section_title_styles=False, level_indent=7.5, line_spacing=1.5, ignore_pages_before_toc=True, ): self.text_style = text_style or TextStyle() self.use_section_title_styles = use_section_title_styles self.level_indent = level_indent self.line_spacing = line_spacing self.ignore_pages_before_toc = ignore_pages_before_toc def get_text_style(self, pdf: "FPDF", item: OutlineSection): if self.use_section_title_styles and pdf.section_title_styles[item.level]: return pdf.section_title_styles[item.level] if isinstance(self.text_style.l_margin, (str, Align)): raise ValueError( f"Unsupported l_margin value provided as TextStyle: {self.text_style.l_margin}" ) return self.text_style def render_toc_item(self, pdf: "FPDF", item: OutlineSection): link = pdf.add_link(page=item.page_number) page_label = pdf.pages[item.page_number].get_label() # render the text on the left with pdf.use_text_style(self.get_text_style(pdf, item)): indent = item.level * self.level_indent pdf.set_x(pdf.l_margin + indent) pdf.multi_cell( w=pdf.epw - indent, text=item.name, new_x=XPos.END, new_y=YPos.LAST, link=link, align=Align.J, h=pdf.font_size * self.line_spacing, ) # fill in-between with dots current_x = pdf.get_x() page_label_length = pdf.get_string_width(page_label) in_between_space = pdf.w - current_x - page_label_length - pdf.r_margin if in_between_space < 0: # no space to render the page number - go to next line pdf.ln() current_x = pdf.get_x() in_between_space = pdf.w - current_x - page_label_length - pdf.r_margin in_between = "" if in_between_space > 0: while pdf.get_string_width(in_between + " ") < in_between_space: in_between += "." if len(in_between) > 1: pdf.multi_cell( w=pdf.w - current_x - pdf.r_margin, text=in_between[:-1], new_x=XPos.END, new_y=YPos.LAST, link=link, align=Align.L, h=pdf.font_size * self.line_spacing, ) # render the page number on the right pdf.set_x(current_x) pdf.multi_cell( w=pdf.w - current_x - pdf.r_margin, text=page_label, new_x=XPos.LMARGIN, new_y=YPos.NEXT, link=link, align=Align.R, h=pdf.font_size * self.line_spacing, ) def render_toc(self, pdf: "FPDF", outline: List[OutlineSection]): "This method can be overridden by subclasses to customize the Table of Contents style." for section in outline: if ( self.ignore_pages_before_toc and section.page_number <= pdf.toc_placeholder.start_page ): continue self.render_toc_item(pdf, section)
A reference implementation of a Table of Contents (ToC) for use with
fpdf2
.This class provides a customizable Table of Contents that can be used directly or subclassed for additional functionality. To use this class, create an instance of
TableOfContents
, configure it as needed, and pass itsrender_toc
method as therender_toc_function
argument toFPDF.insert_toc_placeholder()
.Methods
def get_text_style(self,
pdf: FPDF,
item: OutlineSection)-
Expand source code Browse git
def get_text_style(self, pdf: "FPDF", item: OutlineSection): if self.use_section_title_styles and pdf.section_title_styles[item.level]: return pdf.section_title_styles[item.level] if isinstance(self.text_style.l_margin, (str, Align)): raise ValueError( f"Unsupported l_margin value provided as TextStyle: {self.text_style.l_margin}" ) return self.text_style
def render_toc(self,
pdf: FPDF,
outline: List[OutlineSection])-
Expand source code Browse git
def render_toc(self, pdf: "FPDF", outline: List[OutlineSection]): "This method can be overridden by subclasses to customize the Table of Contents style." for section in outline: if ( self.ignore_pages_before_toc and section.page_number <= pdf.toc_placeholder.start_page ): continue self.render_toc_item(pdf, section)
This method can be overridden by subclasses to customize the Table of Contents style.
def render_toc_item(self,
pdf: FPDF,
item: OutlineSection)-
Expand source code Browse git
def render_toc_item(self, pdf: "FPDF", item: OutlineSection): link = pdf.add_link(page=item.page_number) page_label = pdf.pages[item.page_number].get_label() # render the text on the left with pdf.use_text_style(self.get_text_style(pdf, item)): indent = item.level * self.level_indent pdf.set_x(pdf.l_margin + indent) pdf.multi_cell( w=pdf.epw - indent, text=item.name, new_x=XPos.END, new_y=YPos.LAST, link=link, align=Align.J, h=pdf.font_size * self.line_spacing, ) # fill in-between with dots current_x = pdf.get_x() page_label_length = pdf.get_string_width(page_label) in_between_space = pdf.w - current_x - page_label_length - pdf.r_margin if in_between_space < 0: # no space to render the page number - go to next line pdf.ln() current_x = pdf.get_x() in_between_space = pdf.w - current_x - page_label_length - pdf.r_margin in_between = "" if in_between_space > 0: while pdf.get_string_width(in_between + " ") < in_between_space: in_between += "." if len(in_between) > 1: pdf.multi_cell( w=pdf.w - current_x - pdf.r_margin, text=in_between[:-1], new_x=XPos.END, new_y=YPos.LAST, link=link, align=Align.L, h=pdf.font_size * self.line_spacing, ) # render the page number on the right pdf.set_x(current_x) pdf.multi_cell( w=pdf.w - current_x - pdf.r_margin, text=page_label, new_x=XPos.LMARGIN, new_y=YPos.NEXT, link=link, align=Align.R, h=pdf.font_size * self.line_spacing, )