I have a PDF with a number of parts. I would like to create a Table of Contents to navigate the PDF with ease. I would like to do on a Mac this with freeware. (A command-line program would be great.)

Is that possible? Similar questions have been asked before, but as far as I can tell, the best answer given has been PDFOutliner, which is not freeware.


I found PDFtk Server and Coherent PDF Command Line Tools have a wide range of PDF command line utilities.

I've used both tools on and off, but never needed to do any TOC work. The Bookmarks section in Coherent's Usage Examples Page looks like it may be an approach to experiment with:


cpdf -list-bookmarks in.pdf

List the bookmarks in in.pdf. This would produce:

0 "Part 1" 1 open
1 "Part 1A" 2
2 "Part 1B" 3
0 "Part 2" 4
1 "Part 2a" 5

cpdf -add-bookmarks bookmarks.txt in.pdf -o out.pdf

Add bookmarks in the same form from a prepared file bookmarks.txt to in.pdf, writing to out.pdf.

| improve this answer | |
  • 2
    That's just what I was looking for. Since cpdf -add-bookmarks overwrites the old table of contents of the PDF, it seems to edit the bookmarks using cpdf, the way to go is: (1) cpdf -list-bookmarks in.pdf > out.txt; (2) edit out.txt; (3) cpdf -add-bookmarks.... – Alex Roberts May 16 '16 at 7:02

Here's a python script that will run on MacOS to produce a rudimentary TOC. You'll need to enter your own values for the input file and output filename, and the page number and label for each entry.

# -*- coding: utf-8 -*-

# CREATE PDF OUTLINES v.1.0 : Add a simple list of Bookmarks to a PDF.

from Foundation import  NSURL, NSString
import Quartz as Quartz
import sys

# You will need to change these filepaths to a local test pdf and an output file.
infile = "/path/to/file.pdf"
outfile = '/path/to/output.pdf'

def getOutline(page, label):
    myPage = myPDF.pageAtIndex_(page)
    pageSize = myPage.boundsForBox_(Quartz.kCGPDFMediaBox)
    x = 0
    y = Quartz.CGRectGetMaxY(pageSize)
    pagePoint = Quartz.CGPointMake(x,y)
    myDestination = Quartz.PDFDestination.alloc().initWithPage_atPoint_(myPage, pagePoint)
    myLabel = NSString.stringWithString_(label)
    myOutline = Quartz.PDFOutline.alloc().init()
    return myOutline

pdfURL = NSURL.fileURLWithPath_(infile)
myPDF = Quartz.PDFDocument.alloc().initWithURL_(pdfURL)
if myPDF:
    # Create Outlines. Add the Page Index (from 0) and label in pairs here:
    myTableOfContents = [
        (0, 'Page 1'), 
        (1, 'Page 2'),
        (2, 'Page 3')
    allMyOutlines = []
    for index, outline in myTableOfContents:
        allMyOutlines.append(getOutline(index, outline))

    rootOutline = Quartz.PDFOutline.alloc().init()
    for index, value in enumerate(allMyOutlines):
        rootOutline.insertChild_atIndex_(value, index)
| improve this answer | |

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .