Created
April 8, 2026 05:06
-
-
Save milnak/b596986f4c6b877ff87c787919f481f2 to your computer and use it in GitHub Desktop.
Adds bookmarks to a PDF file from a CSV list of titles and page numbers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """Add bookmarks to a PDF from a CSV file. | |
| CSV format: <title>,<filename>,<page> | |
| Usage: python pdf-add-csv-bookmarks.py <csv_file> <pdf_file> | |
| python -m venv venv | |
| .\venv\Scripts\pip install pypdf # Windows | |
| source venv/bin/activate && pip install pypdf # macOS/Linux | |
| """ | |
| import argparse | |
| import csv | |
| import sys | |
| from pathlib import Path | |
| from pypdf import PdfReader, PdfWriter | |
| def add_bookmarks(csv_path: Path, pdf_path: Path) -> None: | |
| reader = PdfReader(str(pdf_path)) | |
| writer = PdfWriter() | |
| writer.append(reader) | |
| with csv_path.open(newline="", encoding="utf-8") as f: | |
| for lineno, row in enumerate(csv.reader(f), start=1): | |
| if len(row) < 3: | |
| print(f"Warning: skipping malformed line {lineno}: {row}", file=sys.stderr) | |
| continue | |
| title = row[0].strip() | |
| page_str = row[2].strip() | |
| try: | |
| page_num = int(page_str) | |
| except ValueError: | |
| print(f"Warning: invalid page number on line {lineno}: {page_str!r}", file=sys.stderr) | |
| continue | |
| if page_num < 1 or page_num > len(reader.pages): | |
| print(f"Warning: page {page_num} out of range on line {lineno}", file=sys.stderr) | |
| continue | |
| writer.add_outline_item(title, page_num - 1) # pypdf uses 0-based page index | |
| output_path = pdf_path.with_stem(pdf_path.stem + "_bookmarked") | |
| with output_path.open("wb") as out: | |
| writer.write(out) | |
| print(f"Saved: {output_path}") | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description="Add bookmarks to a PDF from a CSV file.") | |
| parser.add_argument("csv_file", help="CSV file with columns: title, filename, page") | |
| parser.add_argument("pdf_file", help="Input PDF file") | |
| args = parser.parse_args() | |
| csv_path = Path(args.csv_file) | |
| pdf_path = Path(args.pdf_file) | |
| if not csv_path.exists(): | |
| sys.exit(f"Error: CSV file not found: {csv_path}") | |
| if not pdf_path.exists(): | |
| sys.exit(f"Error: PDF file not found: {pdf_path}") | |
| add_bookmarks(csv_path, pdf_path) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment