Tworzenie spisu treści i łączenie rozdziałów w PDF

Kacper Sieradziński
Kacper Sieradziński
5 lutego 2025Edukacja2 min czytania

Tworzenie spisu treści (outline/zakładek) w dokumentach PDF to kluczowa funkcja, która znacząco poprawia czytelność i nawigację w obszernych dokumentach. Zamiast przewijać setki stron w poszukiwaniu konkretnego rozdziału, użytkownicy mogą kliknąć odpowiednią zakładkę i natychmiast przejść do wybranej sekcji. W Pythonie możesz automatycznie tworzyć zarówno proste, jak i złożone hierarchiczne struktury zakładek używając biblioteki pypdf, co jest szczególnie przydatne przy automatyzacji generowania raportów, dokumentacji technicznej czy długich dokumentów biznesowych.

Obraz główny Tworzenie spisu treści i łączenie rozdziałów w PDF

Podstawowe zakładki w PDF

Dodawanie prostych zakładek do dokumentu:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from pypdf import PdfReader, PdfWriter def add_bookmarks(input_pdf: str, output_pdf: str, bookmarks: dict): """ Dodaje zakładki do dokumentu PDF. bookmarks: dict w formacie {"nazwa_zakladki": numer_strony} """ reader = PdfReader(input_pdf) writer = PdfWriter() # Kopiowanie wszystkich stron for page in reader.pages: writer.add_page(page) # Dodawanie zakładek for title, page_num in bookmarks.items(): writer.add_outline_item(title, page_num - 1) # Indeksy od 0 with open(output_pdf, 'wb') as f: writer.write(f) print(f"Dodano {len(bookmarks)} zakładek do {output_pdf}") add_bookmarks( "dokument.pdf", "dokument_z_zakladkami.pdf", { "Wprowadzenie": 1, "Rozdział 1": 5, "Rozdział 2": 15, "Zakończenie": 30 } )

Hierarchiczne zakładki (zagnieżdżone)

Tworzenie zagnieżdżonej struktury zakładek:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from pypdf import PdfReader, PdfWriter def add_nested_bookmarks(input_pdf: str, output_pdf: str, structure: dict): """ Dodaje zagnieżdżone zakładki do dokumentu. structure: dict gdzie klucz to nazwa, wartość to (strona, podzakładki) """ reader = PdfReader(input_pdf) writer = PdfWriter() for page in reader.pages: writer.add_page(page) def add_bookmark_item(title: str, page: int, parent=None): if parent is None: return writer.add_outline_item(title, page - 1) else: return writer.add_outline_item(title, page - 1, parent=parent) def process_structure(items: dict, parent=None): for title, value in items.items(): if isinstance(value, tuple): page, children = value bookmark = add_bookmark_item(title, page, parent) if children: process_structure(children, bookmark) else: add_bookmark_item(title, value, parent) process_structure(structure) with open(output_pdf, 'wb') as f: writer.write(f) print(f"Utworzono hierarchiczną strukturę zakładek w {output_pdf}") add_nested_bookmarks( "dokument.pdf", "dokument_hierarchiczny.pdf", { "Wprowadzenie": 1, "Część I": (5, { "Rozdział 1.1": 5, "Rozdział 1.2": (10, { "Podrozdział 1.2.1": 10, "Podrozdział 1.2.2": 12 }) }), "Część II": (20, { "Rozdział 2.1": 20, "Rozdział 2.2": 25 }), "Zakończenie": 30 } )

Łączenie rozdziałów z automatycznymi zakładkami

Automatyczne łączenie wielu plików PDF z tworzeniem spisu treści:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 from pypdf import PdfReader, PdfWriter from pathlib import Path def merge_with_toc(chapters: list[dict], output_pdf: str): """ Łączy rozdziały PDF z automatycznym spisem treści. chapters: list[dict] gdzie każdy dict ma: { "file": "ścieżka_do_pliku.pdf", "title": "Tytuł rozdziału", "subchapters": [{"title": "...", "page_in_file": 1}, ...] } """ writer = PdfWriter() current_page = 0 for chapter in chapters: file_path = chapter["file"] title = chapter["title"] reader = PdfReader(file_path) chapter_start_page = current_page # Dodawanie stron rozdziału for page in reader.pages: writer.add_page(page) # Dodawanie zakładki głównej main_bookmark = writer.add_outline_item(title, chapter_start_page) current_page += len(reader.pages) # Dodawanie podrozdziałów subchapters = chapter.get("subchapters", []) for sub in subchapters: sub_page = chapter_start_page + sub["page_in_file"] - 1 writer.add_outline_item(sub["title"], sub_page, parent=main_bookmark) with open(output_pdf, 'wb') as f: writer.write(f) print(f"Połączono {len(chapters)} rozdziałów z TOC w {output_pdf}") merge_with_toc( [ { "file": "wstep.pdf", "title": "Wprowadzenie" }, { "file": "rozdzial_1.pdf", "title": "Rozdział 1: Podstawy", "subchapters": [ {"title": "1.1 Wprowadzenie", "page_in_file": 1}, {"title": "1.2 Teoria", "page_in_file": 5} ] }, { "file": "rozdzial_2.pdf", "title": "Rozdział 2: Zaawansowane" } ], "kompletna_ksiazka.pdf" )

Tworzenie osobnej strony ze spisem treści

Możesz również utworzyć osobną stronę ze spisem treści:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas from reportlab.lib.units import inch from pypdf import PdfReader, PdfWriter def create_toc_page(toc_items: list[tuple], output_pdf: str): """ Tworzy stronę PDF ze spisem treści. toc_items: list[(tytul, strona, poziom_zagniezdzenia)] """ c = canvas.Canvas(output_pdf, pagesize=letter) width, height = letter c.setFont("Helvetica-Bold", 20) c.drawString(50, height - 50, "Spis treści") y = height - 100 c.setFont("Helvetica", 12) for title, page, level in toc_items: indent = 50 + (level * 20) # Tytuł z wcięciem c.drawString(indent, y, title) # Kropki prowadzące dots_start = indent + c.stringWidth(title) + 10 dots_end = width - 100 for x in range(int(dots_start), int(dots_end), 5): c.drawString(x, y, ".") # Numer strony c.drawRightString(width - 50, y, str(page)) y -= 20 if y < 50: c.showPage() y = height - 50 c.save() print(f"Utworzono stronę TOC w {output_pdf}") create_toc_page( [ ("Wprowadzenie", 1, 0), ("Część I", 5, 0), ("Rozdział 1.1", 5, 1), ("Rozdział 1.2", 10, 1), ("Podrozdział 1.2.1", 10, 2), ("Część II", 20, 0), ("Zakończenie", 30, 0) ], "toc.pdf" )

Łączenie TOC z głównym dokumentem

Połączenie strony TOC z głównym dokumentem:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from pypdf import PdfReader, PdfWriter def merge_toc_with_document(toc_pdf: str, main_pdf: str, output_pdf: str): """Łączy stronę TOC z głównym dokumentem.""" writer = PdfWriter() # Dodanie strony TOC na początku toc_reader = PdfReader(toc_pdf) for page in toc_reader.pages: writer.add_page(page) # Dodanie głównego dokumentu main_reader = PdfReader(main_pdf) for page in main_reader.pages: writer.add_page(page) # Aktualizacja numerów stron w zakładkach (o +1 bo TOC) # To wymagałoby bardziej zaawansowanej logiki... with open(output_pdf, 'wb') as f: writer.write(f) print(f"Połączono TOC z dokumentem w {output_pdf}") merge_toc_with_document("toc.pdf", "dokument.pdf", "dokument_z_toc.pdf")

Podsumowanie

Tworzenie spisu treści w PDF pozwala na:

  • Dodawanie prostych zakładek do dokumentów
  • Tworzenie hierarchicznych, zagnieżdżonych struktur
  • Automatyczne generowanie TOC przy łączeniu rozdziałów
  • Tworzenie osobnych stron ze spisem treści
  • Profesjonalną organizację dużych dokumentów

Te techniki są niezbędne przy pracy z obszernymi dokumentami PDF.


➡️ Następny artykuł

Teraz, gdy znasz różne techniki pracy z PDF, poznaj dostępne narzędzia i wybierz najlepsze dla swoich potrzeb:

Narzędzia do PDF w Pythonie: przegląd bibliotek — porównanie bibliotek pypdf, pdfminer.six, reportlab, WeasyPrint i PyMuPDF, wraz z zaleceniami dotyczącymi wyboru narzędzia.