.. _outlines:

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.

.. ipython::
    :verbatim:

    In [1]: from pikepdf import Pdf, OutlineItem

    In [1]: pdf = Pdf.open('document.pdf')

    In [1]: 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)
       ...:     ])

    In [1]: pdf.save('document_with_outline.pdf')

Another example, for automatically adding an entry for each file in a merged document:

.. ipython::
    :verbatim:

    In [1]: from glob import glob

    In [1]: pdf = Pdf.new()

    In [1]: page_count = 0

    In [1]: 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)

    In [1]: 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 ``Dest`` attribute is used.
* When editing an existing entry with an assigned action, it is left as-is, unless a
  ``destination`` is set. The latter is preferred if both are present.

Creating a more detailed destination with page location:

.. ipython::
    :verbatim:

    In [1]: 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:

.. ipython::
    :verbatim:

    In [1]: oi.destination = make_page_destination(pdf, 0, 'FitB', top=1000)

Outline structure
------------------
For nesting outlines, add items to the ``children`` list of another ``OutlineItem``.

.. ipython::
    :verbatim:

    In [1]: with pdf.open_outline() as outline:
       ...:     main_item = OutlineItem('Main', 0)
       ...:     outline.root.append(main_item)
       ...:     main_item.children.append(OutlineItem('A', 1))
