Outlines
Outlines (sometimes also called bookmarks) are shown in a the PDF viewer aside of the page, allowing for navigation within the document.
Creating outlines
Outlines can be created from scratch, e.g. when assembling a set of PDF files into a single document.
The following example adds outline entries referring to the 1st, 3rd and 9th page of an existing PDF.
>>> from pikepdf import Pdf, OutlineItem
>>> pdf = Pdf.open('document.pdf')
>>> with pdf.open_outline() as outline:
... outline.root.extend([
... # Page counts are zero-based
... OutlineItem('Section One', 0),
... OutlineItem('Section Two', 2),
... OutlineItem('Section Three', 8)
... ])
>>> pdf.save('document_with_outline.pdf')
Another example, for automatically adding an entry for each file in a merged document:
>>> from glob import glob
>>> pdf = Pdf.new()
>>> page_count = 0
>>> with pdf.open_outline() as outline:
... for file in glob('*.pdf'):
... src = Pdf.open(file)
... oi = OutlineItem(file, page_count)
... outline.root.append(oi)
... page_count += len(src.pages)
... pdf.pages.extend(src.pages)
>>> pdf.save('merged.pdf')
Editing outlines
Existing outlines can be edited. Entries can be moved and renamed without affecting the targets they refer to.
Destinations
Destinations tell the PDF viewer where to go when navigating through outline items.
The simplest case is a reference to a page, together with the page location, e.g.
Fit (default). However, named destinations can also be assigned.
The PDF specification allows for either use of a destination (Dest attribute) or
an action (A attribute), but not both on the same element. OutlineItem elements
handle this as follows:
When creating new outline entries passing in a page number or reference name, the
Destattribute is used.When editing an existing entry with an assigned action, it is left as-is, unless a
destinationis set. The latter is preferred if both are present.
Creating a more detailed destination with page location:
>>> oi = OutlineItem('First', 0, 'FitB', top=1000)
The above will call make_page_destination when saving to a Pdf document,
roughly equivalent to the following:
>>> oi.destination = make_page_destination(pdf, 0, 'FitB', top=1000)
An existing destination array (whatever form .destination takes – an
explicit array, a page number, or a named destination) can be resolved to a
Destination with named accessors for its page, fit type, and viewport
parameters:
>>> with pdf.open_outline() as outline:
... dest = outline.root[0].resolved_destination(pdf)
... dest.page, dest.fit_type, dest.left, dest.top
resolved_destination follows named destinations (a String via the
document’s Names.Dests name tree, or a Name via the legacy Dests
dictionary) automatically, and returns None if there is no destination, or
a named destination cannot be resolved.
A Destination can also be built directly and passed as destination=:
>>> from pikepdf import Destination, PageLocation
>>> oi = OutlineItem('First', Destination(pdf.pages[0].obj, PageLocation.FitB, top=1000))
Actions
Instead of a destination, an outline item’s action can be set to any PDF
action dictionary (GoTo, URI, Launch, etc. – see PDF spec 12.6). The raw
action dictionary set on .action is always what gets written back to the
Pdf; .parsed_action gives a read-only, typed view of it:
>>> from pikepdf import Dictionary, Name
>>> with pdf.open_outline() as outline:
... item = outline.root[0]
... item.action = Dictionary(S=Name.URI, URI='https://example.com')
... item.parsed_action.uri
'https://example.com'
Typed action wrappers – GoToAction, GoToRAction, GoToEAction,
GoToDpAction, LaunchAction, URIAction, NamedAction,
SetOCGStateAction, JavaScriptAction – can also be constructed directly
and passed as action=; the OutlineItem unwraps it to the underlying
dictionary automatically. A GoToAction’s destination can be resolved the
same way as an OutlineItem’s:
>>> from pikepdf import GoToAction
>>> action = GoToAction(Dictionary(S=Name.GoTo, D=[pdf.pages[0].obj, Name.Fit]))
>>> action.resolve_destination(pdf).page
Unrecognized action subtypes (e.g. Rendition, Trans) are returned as a
plain Action, whose .subtype and .obj give raw access.
Color and style
An outline item’s displayed text can be given a color and italic/bold styling:
>>> from pikepdf import OutlineItemFlag
>>> with pdf.open_outline() as outline:
... item = outline.root[0]
... item.color = (1.0, 0.0, 0.0) # RGB, each component 0.0-1.0
... item.bold = True
... item.flags == OutlineItemFlag.Bold
True
item.italic/item.bold are convenience accessors backed by
item.flags (an OutlineItemFlag). Setting item.color = None (the
default) removes the /C entry so viewers fall back to black text.
Structure element linkage
For tagged PDFs, an outline item can carry a structure_element reference
back to the structure element it corresponds to (PDF spec 12.3.3, /SE).
Per spec this is not intended for navigation – use destination/action
with a structure destination for that – it is purely a semantic backlink
for accessibility tooling:
>>> with pdf.open_outline() as outline:
... outline.root[0].structure_element = pdf.Root.StructTreeRoot.K[0]
Outline structure
For nesting outlines, add items to the children list of another OutlineItem.
>>> with pdf.open_outline() as outline:
... main_item = OutlineItem('Main', 0)
... outline.root.append(main_item)
... main_item.children.append(OutlineItem('A', 1))