pdf-toc-generator 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pdf_toc_generator-1.0.0.dist-info/METADATA +309 -0
- pdf_toc_generator-1.0.0.dist-info/RECORD +7 -0
- pdf_toc_generator-1.0.0.dist-info/WHEEL +5 -0
- pdf_toc_generator-1.0.0.dist-info/entry_points.txt +2 -0
- pdf_toc_generator-1.0.0.dist-info/licenses/LICENSE +21 -0
- pdf_toc_generator-1.0.0.dist-info/top_level.txt +1 -0
- pdf_toc_generator.py +1461 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdf-toc-generator
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Automatically generate and add bookmarks to PDF files
|
|
5
|
+
Author-email: Sameer Bajaj <sameer@sameerbajaj.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://sameerbajaj.com/tools/pdf-toc/
|
|
8
|
+
Project-URL: Website, https://sameerbajaj.com
|
|
9
|
+
Project-URL: Repository, https://github.com/sameerbajaj/pdf_toc_generator
|
|
10
|
+
Keywords: pdf,table-of-contents,bookmarks,toc,pymupdf
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pymupdf>=1.23.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: jupyter>=1.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: ipykernel>=6.25.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# PDF Table of Contents Generator
|
|
29
|
+
|
|
30
|
+
Automatically generate and add bookmarks (table of contents) to PDF files. Supports two methods:
|
|
31
|
+
1. **Extract from existing TOC page** - Intelligently detects and extracts from built-in TOC pages
|
|
32
|
+
2. **Font-based detection** - Analyzes text formatting to identify heading hierarchy
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- 🔖 Automatically adds clickable bookmarks to PDFs
|
|
37
|
+
- 📄 Detects and extracts from existing TOC pages
|
|
38
|
+
- 🎯 Smart matching of TOC entries to document pages
|
|
39
|
+
- 🎛️ Multiple structure options (hierarchical or flat)
|
|
40
|
+
- ⚡ One-line installation and execution
|
|
41
|
+
- 🖥️ Interactive mode with guided prompts
|
|
42
|
+
- 🐍 Pure Python with minimal dependencies
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
### One-Line Execution (with UV)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uvx --from git+https://github.com/sameerbajaj/pdf_toc_generator pdf_toc_generator
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This will:
|
|
53
|
+
1. Install the tool automatically
|
|
54
|
+
2. Run in interactive mode
|
|
55
|
+
3. Guide you through the process with prompts
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
#### Using UV (Recommended)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Install UV if you haven't already
|
|
63
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
64
|
+
|
|
65
|
+
# Run the tool directly (no installation needed)
|
|
66
|
+
uvx --from git+https://github.com/sameerbajaj/pdf_toc_generator pdf_toc_generator
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Manual Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/sameerbajaj/pdf_toc_generator.git
|
|
73
|
+
cd pdf_toc_generator
|
|
74
|
+
uv sync
|
|
75
|
+
uv run pdf_toc_generator.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage
|
|
79
|
+
|
|
80
|
+
### Interactive Mode (Recommended for First-Time Users)
|
|
81
|
+
|
|
82
|
+
Simply run without arguments to enter interactive mode:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv run pdf_toc_generator.py
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You'll be prompted for:
|
|
89
|
+
- PDF file path
|
|
90
|
+
- Output file path (optional, defaults to `input_with_toc.pdf`)
|
|
91
|
+
- Whether to extract from existing TOC page (y/n)
|
|
92
|
+
- Whether to use flat structure (y/n)
|
|
93
|
+
- Whether to add "Table of Contents" bookmark (y/n)
|
|
94
|
+
|
|
95
|
+
### Command-Line Arguments
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Basic usage
|
|
99
|
+
uv run pdf_toc_generator.py input.pdf
|
|
100
|
+
|
|
101
|
+
# Specify output file
|
|
102
|
+
uv run pdf_toc_generator.py input.pdf -o output.pdf
|
|
103
|
+
|
|
104
|
+
# Create flat structure (no hierarchy)
|
|
105
|
+
uv run pdf_toc_generator.py input.pdf --flat
|
|
106
|
+
|
|
107
|
+
# Skip existing TOC page detection (use font-based method)
|
|
108
|
+
uv run pdf_toc_generator.py input.pdf --no-existing-toc
|
|
109
|
+
|
|
110
|
+
# Don't add "Table of Contents" bookmark
|
|
111
|
+
uv run pdf_toc_generator.py input.pdf --no-toc-bookmark
|
|
112
|
+
|
|
113
|
+
# Use OCR mode for poorly scanned PDFs
|
|
114
|
+
uv run pdf_toc_generator.py scanned_document.pdf --ocr-mode
|
|
115
|
+
|
|
116
|
+
# Combine options
|
|
117
|
+
uv run pdf_toc_generator.py input.pdf -o output.pdf --flat --ocr-mode
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Help
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
uv run pdf_toc_generator.py --help
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
### Example 1: Book with Existing TOC
|
|
129
|
+
```bash
|
|
130
|
+
$ uv run pdf_toc_generator.py book.pdf
|
|
131
|
+
|
|
132
|
+
================================================================================
|
|
133
|
+
PDF TABLE OF CONTENTS GENERATOR
|
|
134
|
+
================================================================================
|
|
135
|
+
|
|
136
|
+
Processing: book.pdf
|
|
137
|
+
|
|
138
|
+
Step 1: Checking for existing TOC page...
|
|
139
|
+
✓ Found TOC spanning pages 2-5
|
|
140
|
+
|
|
141
|
+
Step 2: Extracting TOC from dedicated page...
|
|
142
|
+
✓ Extracted 174 entries from TOC page
|
|
143
|
+
...
|
|
144
|
+
✓ COMPLETE! (Method: existing_toc)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Example 2: Technical Document (Font-Based)
|
|
148
|
+
```bash
|
|
149
|
+
$ uv run pdf_toc_generator.py document.pdf --no-existing-toc
|
|
150
|
+
|
|
151
|
+
Processing: document.pdf
|
|
152
|
+
|
|
153
|
+
Step 1: Extracting text with formatting...
|
|
154
|
+
Extracted 1234 text blocks from 50 pages
|
|
155
|
+
|
|
156
|
+
Step 2: Analyzing font statistics...
|
|
157
|
+
Body text size (most common): 12.0
|
|
158
|
+
...
|
|
159
|
+
✓ COMPLETE! (Method: font_detection)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Example 3: Flat Structure
|
|
163
|
+
```bash
|
|
164
|
+
$ uv run pdf_toc_generator.py report.pdf --flat -o report_bookmarks.pdf
|
|
165
|
+
|
|
166
|
+
✓ Converting to flat structure (all entries at level 1)
|
|
167
|
+
✓ Added 45 bookmarks to PDF
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Example 4: OCR Mode (Poorly Scanned PDFs)
|
|
171
|
+
```bash
|
|
172
|
+
$ uv run pdf_toc_generator.py scanned_book.pdf --ocr-mode
|
|
173
|
+
|
|
174
|
+
Step 2: Extracting TOC from dedicated page...
|
|
175
|
+
(OCR mode enabled - will use enhanced extraction for poor quality scans)
|
|
176
|
+
Found 25 potential titles and 25 page numbers
|
|
177
|
+
⚠ Warning: 20/25 page numbers exceed PDF page count (15)
|
|
178
|
+
This appears to be an excerpt or the TOC references the original document's page numbers.
|
|
179
|
+
Will use fuzzy matching to find headings in the available pages.
|
|
180
|
+
✓ Matched 25 entries using OCR-style extraction
|
|
181
|
+
...
|
|
182
|
+
✓ COMPLETE! (Method: existing_toc)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## How It Works
|
|
186
|
+
|
|
187
|
+
### Method 1: Existing TOC Page (Primary)
|
|
188
|
+
|
|
189
|
+
1. **Detects** TOC pages by looking for "Table of Contents", "Contents", or multiple chapter references
|
|
190
|
+
2. **Extracts** entries with page numbers, preserving hierarchy based on indentation and font size
|
|
191
|
+
- **Standard extraction**: Expects title and page number on the same line (e.g., "Chapter 1 ... 15")
|
|
192
|
+
- **OCR mode** (use `--ocr-mode`): Handles poorly scanned PDFs where titles and page numbers are on separate lines
|
|
193
|
+
3. **Validates** extracted page numbers against PDF page count (warns if out of range for excerpts)
|
|
194
|
+
4. **Matches** TOC entries to actual document locations using fuzzy text matching (excludes TOC pages from search)
|
|
195
|
+
5. **Creates** bookmarks that mirror the original TOC structure
|
|
196
|
+
|
|
197
|
+
### Method 2: Font-Based Detection (Fallback)
|
|
198
|
+
|
|
199
|
+
1. **Extracts** all text with font metadata (size, style, position)
|
|
200
|
+
2. **Analyzes** font size distribution to identify body text vs headings
|
|
201
|
+
3. **Classifies** headings by hierarchy level based on font size
|
|
202
|
+
4. **Generates** TOC structure with proper nesting
|
|
203
|
+
|
|
204
|
+
## Options Explained
|
|
205
|
+
|
|
206
|
+
### `--flat`
|
|
207
|
+
Creates a flat bookmark structure where all entries are at level 1 (no indentation/hierarchy).
|
|
208
|
+
|
|
209
|
+
**Without `--flat` (hierarchical):**
|
|
210
|
+
```
|
|
211
|
+
▪ Chapter 1
|
|
212
|
+
• Section 1.1
|
|
213
|
+
• Subsection 1.1.1
|
|
214
|
+
▪ Chapter 2
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**With `--flat`:**
|
|
218
|
+
```
|
|
219
|
+
▪ Chapter 1
|
|
220
|
+
▪ Section 1.1
|
|
221
|
+
▪ Subsection 1.1.1
|
|
222
|
+
▪ Chapter 2
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `--no-existing-toc`
|
|
226
|
+
Forces the tool to use font-based detection instead of trying to extract from an existing TOC page. Useful if the PDF has a TOC page but you want to generate bookmarks based on actual headings.
|
|
227
|
+
|
|
228
|
+
### `--no-toc-bookmark`
|
|
229
|
+
Prevents adding a "Table of Contents" bookmark that points to the TOC page. Only applies when an existing TOC page is detected.
|
|
230
|
+
|
|
231
|
+
### `--ocr-mode`
|
|
232
|
+
Enables OCR-tolerant extraction for poorly scanned PDFs. Use this when:
|
|
233
|
+
- The PDF has low quality OCR text
|
|
234
|
+
- Titles and page numbers in the TOC are on separate lines
|
|
235
|
+
- Standard extraction produces garbage bookmarks or fails
|
|
236
|
+
|
|
237
|
+
**What it does:**
|
|
238
|
+
- Collects all text lines from TOC pages
|
|
239
|
+
- Separates titles from page numbers
|
|
240
|
+
- Combines fragmented section headers (e.g., "PART", "ONE" → "PART ONE")
|
|
241
|
+
- Validates page numbers against PDF page count
|
|
242
|
+
- Uses full-document fuzzy matching for out-of-range pages (common with excerpts)
|
|
243
|
+
- **Validates matches**: Only includes bookmarks with match score > 0.85 (skips TOC entries not found in document)
|
|
244
|
+
|
|
245
|
+
**When to use:**
|
|
246
|
+
- Scanned documents with poor OCR quality
|
|
247
|
+
- PDFs where TOC extraction produces individual words as bookmarks
|
|
248
|
+
- Excerpt PDFs where TOC references original document page numbers
|
|
249
|
+
|
|
250
|
+
**Important for excerpts:**
|
|
251
|
+
If your PDF is an excerpt (e.g., 20 pages from a 200-page book), the tool will skip TOC entries for missing chapters. This is expected behavior and ensures bookmarks only point to content that actually exists in your PDF.
|
|
252
|
+
|
|
253
|
+
## Requirements
|
|
254
|
+
|
|
255
|
+
- Python 3.8+
|
|
256
|
+
- PyMuPDF (automatically installed)
|
|
257
|
+
|
|
258
|
+
## Development
|
|
259
|
+
|
|
260
|
+
### Using Jupyter Notebook
|
|
261
|
+
|
|
262
|
+
A Jupyter notebook version is included for exploration and customization:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
uv run jupyter notebook pdf_toc_generator.ipynb
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Troubleshooting
|
|
269
|
+
|
|
270
|
+
### "No headings found"
|
|
271
|
+
- Try adjusting the font size detection threshold
|
|
272
|
+
- Use `--no-existing-toc` to force font-based detection
|
|
273
|
+
- Check if your PDF has selectable text (not scanned images)
|
|
274
|
+
|
|
275
|
+
### Poor quality bookmarks (individual words like "THE", "MINTO", etc.)
|
|
276
|
+
- Your PDF likely has poor OCR quality
|
|
277
|
+
- Use `--ocr-mode` flag to enable enhanced extraction
|
|
278
|
+
- In interactive mode, answer "yes" to "Is this a poorly scanned/OCR'd PDF?"
|
|
279
|
+
|
|
280
|
+
### TOC page numbers don't match document (e.g., TOC says page 45 but PDF only has 20 pages)
|
|
281
|
+
- This is normal for excerpt PDFs or scanned partial documents
|
|
282
|
+
- The tool automatically uses fuzzy matching to find headings in available pages
|
|
283
|
+
- Use `--ocr-mode` for better results with excerpts
|
|
284
|
+
|
|
285
|
+
### "File not found"
|
|
286
|
+
- Verify the PDF path is correct
|
|
287
|
+
- Use absolute paths or ensure you're in the correct directory
|
|
288
|
+
- Check file permissions
|
|
289
|
+
|
|
290
|
+
### Bookmarks not visible in PDF viewer
|
|
291
|
+
- Try a different PDF viewer (Adobe Acrobat, Preview, Chrome)
|
|
292
|
+
- Look for a bookmarks/outline panel (usually on the left sidebar)
|
|
293
|
+
- Some nested bookmarks may be collapsed - click the expand arrow
|
|
294
|
+
|
|
295
|
+
## License
|
|
296
|
+
|
|
297
|
+
MIT License - see LICENSE file for details
|
|
298
|
+
|
|
299
|
+
## Contributing
|
|
300
|
+
|
|
301
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
302
|
+
|
|
303
|
+
## Acknowledgments
|
|
304
|
+
|
|
305
|
+
Built with [PyMuPDF](https://pymupdf.readthedocs.io/) for PDF processing.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
Part of the open-source tools collection by [Sameer Bajaj](https://sameerbajaj.com). Learn more on the [project page](https://sameerbajaj.com/tools/pdf-toc/).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
pdf_toc_generator.py,sha256=B0_-a7yu1eqbnnPVhWrKrCrGBAzkNhAd-57eEWHGjQ4,55347
|
|
2
|
+
pdf_toc_generator-1.0.0.dist-info/licenses/LICENSE,sha256=aZ-A1VSgJSeGP6bz-0r83Z8HQsL1JBVJe0uFslVEteY,1069
|
|
3
|
+
pdf_toc_generator-1.0.0.dist-info/METADATA,sha256=PPLQJdjaASokyNE852MBbn2Hxz653jDyjTebMmLrorg,9925
|
|
4
|
+
pdf_toc_generator-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
pdf_toc_generator-1.0.0.dist-info/entry_points.txt,sha256=6Wj52-MkXoLfd2gfXiUiNI6vABMwZxszPf1_22ljnE8,61
|
|
6
|
+
pdf_toc_generator-1.0.0.dist-info/top_level.txt,sha256=GSa1iw4jLRR1rtMIntLT9BSR3pb7DCeRoWuzwhPSWk8,18
|
|
7
|
+
pdf_toc_generator-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sameer Bajaj
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pdf_toc_generator
|