pdf-ocr-cli 1.0.0__tar.gz

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.
@@ -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,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdf-ocr-cli
3
+ Version: 1.0.0
4
+ Summary: High-quality OCR tool for scanned PDFs using Tesseract
5
+ Author-email: Sameer Bajaj <sameer@sameerbajaj.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://sameerbajaj.com/tools/pdf-ocr/
8
+ Project-URL: Website, https://sameerbajaj.com
9
+ Project-URL: Repository, https://github.com/sameerbajaj/pdf-ocr
10
+ Keywords: ocr,pdf,tesseract,document-processing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pytesseract>=0.3.13
23
+ Requires-Dist: pdf2image>=1.17.0
24
+ Requires-Dist: pillow>=10.0.0
25
+ Requires-Dist: click>=8.1.0
26
+ Requires-Dist: rich>=13.0.0
27
+ Requires-Dist: PyPDF2>=3.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: black>=23.0.0; extra == "dev"
31
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # PDF OCR Tool
35
+
36
+ Convert scanned or poorly OCR'd PDFs into searchable PDFs with selectable text using Tesseract OCR.
37
+
38
+ ## Features
39
+
40
+ - 🎯 High-quality OCR using Tesseract 5.x
41
+ - 📄 Creates searchable PDFs with invisible text layer
42
+ - 🎨 Interactive, user-friendly command-line interface
43
+ - âš¡ Fast processing with configurable DPI (default: 300)
44
+ - 🎭 Process entire PDFs or specific page ranges
45
+
46
+ ## Prerequisites
47
+
48
+ Install system dependencies first:
49
+
50
+ **macOS:**
51
+ ```bash
52
+ brew install tesseract poppler
53
+ ```
54
+
55
+ **Linux (Ubuntu/Debian):**
56
+ ```bash
57
+ sudo apt-get install tesseract-ocr poppler-utils
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ### Option 1: Run Directly from GitHub (Easiest - No Installation!)
63
+
64
+ ```bash
65
+ uvx --from git+https://github.com/sameerbajaj/pdf-ocr pdf-ocr
66
+ ```
67
+
68
+ That's it! The tool will run directly without any installation.
69
+
70
+ ### Option 2: Clone and Run Locally
71
+
72
+ ```bash
73
+ # Clone the repository
74
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
75
+ cd pdf-ocr
76
+
77
+ # Run directly
78
+ uvx --from . pdf-ocr
79
+ ```
80
+
81
+ ### Option 3: Install Permanently
82
+
83
+ ```bash
84
+ # Clone and install
85
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
86
+ cd pdf-ocr
87
+ uv pip install -e .
88
+ source .venv/bin/activate
89
+
90
+ # Run from anywhere
91
+ pdf-ocr
92
+ ```
93
+
94
+ ## Usage
95
+
96
+ ### Interactive Mode (Recommended)
97
+
98
+ Simply run the command and follow the friendly prompts:
99
+
100
+ ```bash
101
+ pdf-ocr
102
+ ```
103
+
104
+ The tool will ask you:
105
+ 1. **Which PDF file?** - You can type the path or drag & drop the file
106
+ 2. **Which pages?** - Enter a range like `4-5`, a single page like `7`, or press Enter for all pages
107
+
108
+ ### Command-Line Mode
109
+
110
+ ```bash
111
+ # Process entire PDF
112
+ pdf-ocr document.pdf
113
+
114
+ # Process specific pages
115
+ pdf-ocr document.pdf --pages 4-5
116
+ pdf-ocr document.pdf -p 1-10
117
+
118
+ # Custom output
119
+ pdf-ocr document.pdf --output result.pdf
120
+
121
+ # Save text files too
122
+ pdf-ocr document.pdf --save-text
123
+
124
+ # Higher quality (slower)
125
+ pdf-ocr document.pdf --dpi 400
126
+ ```
127
+
128
+ ## Examples
129
+
130
+ ```bash
131
+ # Process pages 4-5 of a book
132
+ pdf-ocr book.pdf --pages 4-5
133
+
134
+ # Process chapter (pages 20-40) with text export
135
+ pdf-ocr textbook.pdf -p 20-40 --save-text
136
+
137
+ # High-quality scan of a single page
138
+ pdf-ocr scan.pdf --pages 7 --dpi 600
139
+ ```
140
+
141
+ ## Output
142
+
143
+ The tool generates:
144
+ - **`filename_ocr.pdf`** or **`filename_pages4-5_ocr.pdf`** - Searchable PDF with text layer
145
+ - **`filename_pageX.txt`** (optional) - Plain text files if `--save-text` is used
146
+
147
+ All files are saved in the same directory as the input PDF.
148
+
149
+ ## Troubleshooting
150
+
151
+ **Command not found:**
152
+ ```bash
153
+ source .venv/bin/activate
154
+ ```
155
+
156
+ **Tesseract not installed:**
157
+ ```bash
158
+ brew install tesseract # macOS
159
+ sudo apt-get install tesseract-ocr # Linux
160
+ ```
161
+
162
+ **Poppler not installed:**
163
+ ```bash
164
+ brew install poppler # macOS
165
+ sudo apt-get install poppler-utils # Linux
166
+ ```
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ # Setup for development
172
+ git clone https://github.com/yourusername/pdf-ocr-tool.git
173
+ cd pdf-ocr-tool
174
+ uv venv
175
+ source .venv/bin/activate
176
+ uv pip install -e ".[dev]"
177
+
178
+ # Run from source
179
+ python -m pdf_ocr_tool.cli
180
+ ```
181
+
182
+ ## Project Structure
183
+
184
+ ```
185
+ pdf-ocr-tool/
186
+ ├── pdf_ocr_tool/ # Main package
187
+ │ ├── cli.py # Command-line interface
188
+ │ ├── ocr.py # OCR processing
189
+ │ └── pdf_utils.py # PDF generation
190
+ ├── pyproject.toml # Package configuration
191
+ ├── setup.sh # Auto-installer script
192
+ └── README.md # This file
193
+ ```
194
+
195
+ ## License
196
+
197
+ MIT License - see LICENSE file for details.
198
+
199
+ ## Acknowledgments
200
+
201
+ - [Tesseract OCR](https://github.com/tesseract-ocr/tesseract)
202
+ - [pdf2image](https://github.com/Belval/pdf2image)
203
+ - [Rich](https://github.com/Textualize/rich)
204
+
205
+ ---
206
+
207
+ Part of the open-source tools collection by [Sameer Bajaj](https://sameerbajaj.com). Learn more on the [project page](https://sameerbajaj.com/tools/pdf-ocr/).
@@ -0,0 +1,174 @@
1
+ # PDF OCR Tool
2
+
3
+ Convert scanned or poorly OCR'd PDFs into searchable PDFs with selectable text using Tesseract OCR.
4
+
5
+ ## Features
6
+
7
+ - 🎯 High-quality OCR using Tesseract 5.x
8
+ - 📄 Creates searchable PDFs with invisible text layer
9
+ - 🎨 Interactive, user-friendly command-line interface
10
+ - âš¡ Fast processing with configurable DPI (default: 300)
11
+ - 🎭 Process entire PDFs or specific page ranges
12
+
13
+ ## Prerequisites
14
+
15
+ Install system dependencies first:
16
+
17
+ **macOS:**
18
+ ```bash
19
+ brew install tesseract poppler
20
+ ```
21
+
22
+ **Linux (Ubuntu/Debian):**
23
+ ```bash
24
+ sudo apt-get install tesseract-ocr poppler-utils
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Option 1: Run Directly from GitHub (Easiest - No Installation!)
30
+
31
+ ```bash
32
+ uvx --from git+https://github.com/sameerbajaj/pdf-ocr pdf-ocr
33
+ ```
34
+
35
+ That's it! The tool will run directly without any installation.
36
+
37
+ ### Option 2: Clone and Run Locally
38
+
39
+ ```bash
40
+ # Clone the repository
41
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
42
+ cd pdf-ocr
43
+
44
+ # Run directly
45
+ uvx --from . pdf-ocr
46
+ ```
47
+
48
+ ### Option 3: Install Permanently
49
+
50
+ ```bash
51
+ # Clone and install
52
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
53
+ cd pdf-ocr
54
+ uv pip install -e .
55
+ source .venv/bin/activate
56
+
57
+ # Run from anywhere
58
+ pdf-ocr
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ ### Interactive Mode (Recommended)
64
+
65
+ Simply run the command and follow the friendly prompts:
66
+
67
+ ```bash
68
+ pdf-ocr
69
+ ```
70
+
71
+ The tool will ask you:
72
+ 1. **Which PDF file?** - You can type the path or drag & drop the file
73
+ 2. **Which pages?** - Enter a range like `4-5`, a single page like `7`, or press Enter for all pages
74
+
75
+ ### Command-Line Mode
76
+
77
+ ```bash
78
+ # Process entire PDF
79
+ pdf-ocr document.pdf
80
+
81
+ # Process specific pages
82
+ pdf-ocr document.pdf --pages 4-5
83
+ pdf-ocr document.pdf -p 1-10
84
+
85
+ # Custom output
86
+ pdf-ocr document.pdf --output result.pdf
87
+
88
+ # Save text files too
89
+ pdf-ocr document.pdf --save-text
90
+
91
+ # Higher quality (slower)
92
+ pdf-ocr document.pdf --dpi 400
93
+ ```
94
+
95
+ ## Examples
96
+
97
+ ```bash
98
+ # Process pages 4-5 of a book
99
+ pdf-ocr book.pdf --pages 4-5
100
+
101
+ # Process chapter (pages 20-40) with text export
102
+ pdf-ocr textbook.pdf -p 20-40 --save-text
103
+
104
+ # High-quality scan of a single page
105
+ pdf-ocr scan.pdf --pages 7 --dpi 600
106
+ ```
107
+
108
+ ## Output
109
+
110
+ The tool generates:
111
+ - **`filename_ocr.pdf`** or **`filename_pages4-5_ocr.pdf`** - Searchable PDF with text layer
112
+ - **`filename_pageX.txt`** (optional) - Plain text files if `--save-text` is used
113
+
114
+ All files are saved in the same directory as the input PDF.
115
+
116
+ ## Troubleshooting
117
+
118
+ **Command not found:**
119
+ ```bash
120
+ source .venv/bin/activate
121
+ ```
122
+
123
+ **Tesseract not installed:**
124
+ ```bash
125
+ brew install tesseract # macOS
126
+ sudo apt-get install tesseract-ocr # Linux
127
+ ```
128
+
129
+ **Poppler not installed:**
130
+ ```bash
131
+ brew install poppler # macOS
132
+ sudo apt-get install poppler-utils # Linux
133
+ ```
134
+
135
+ ## Development
136
+
137
+ ```bash
138
+ # Setup for development
139
+ git clone https://github.com/yourusername/pdf-ocr-tool.git
140
+ cd pdf-ocr-tool
141
+ uv venv
142
+ source .venv/bin/activate
143
+ uv pip install -e ".[dev]"
144
+
145
+ # Run from source
146
+ python -m pdf_ocr_tool.cli
147
+ ```
148
+
149
+ ## Project Structure
150
+
151
+ ```
152
+ pdf-ocr-tool/
153
+ ├── pdf_ocr_tool/ # Main package
154
+ │ ├── cli.py # Command-line interface
155
+ │ ├── ocr.py # OCR processing
156
+ │ └── pdf_utils.py # PDF generation
157
+ ├── pyproject.toml # Package configuration
158
+ ├── setup.sh # Auto-installer script
159
+ └── README.md # This file
160
+ ```
161
+
162
+ ## License
163
+
164
+ MIT License - see LICENSE file for details.
165
+
166
+ ## Acknowledgments
167
+
168
+ - [Tesseract OCR](https://github.com/tesseract-ocr/tesseract)
169
+ - [pdf2image](https://github.com/Belval/pdf2image)
170
+ - [Rich](https://github.com/Textualize/rich)
171
+
172
+ ---
173
+
174
+ Part of the open-source tools collection by [Sameer Bajaj](https://sameerbajaj.com). Learn more on the [project page](https://sameerbajaj.com/tools/pdf-ocr/).
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdf-ocr-cli
3
+ Version: 1.0.0
4
+ Summary: High-quality OCR tool for scanned PDFs using Tesseract
5
+ Author-email: Sameer Bajaj <sameer@sameerbajaj.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://sameerbajaj.com/tools/pdf-ocr/
8
+ Project-URL: Website, https://sameerbajaj.com
9
+ Project-URL: Repository, https://github.com/sameerbajaj/pdf-ocr
10
+ Keywords: ocr,pdf,tesseract,document-processing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pytesseract>=0.3.13
23
+ Requires-Dist: pdf2image>=1.17.0
24
+ Requires-Dist: pillow>=10.0.0
25
+ Requires-Dist: click>=8.1.0
26
+ Requires-Dist: rich>=13.0.0
27
+ Requires-Dist: PyPDF2>=3.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: black>=23.0.0; extra == "dev"
31
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # PDF OCR Tool
35
+
36
+ Convert scanned or poorly OCR'd PDFs into searchable PDFs with selectable text using Tesseract OCR.
37
+
38
+ ## Features
39
+
40
+ - 🎯 High-quality OCR using Tesseract 5.x
41
+ - 📄 Creates searchable PDFs with invisible text layer
42
+ - 🎨 Interactive, user-friendly command-line interface
43
+ - âš¡ Fast processing with configurable DPI (default: 300)
44
+ - 🎭 Process entire PDFs or specific page ranges
45
+
46
+ ## Prerequisites
47
+
48
+ Install system dependencies first:
49
+
50
+ **macOS:**
51
+ ```bash
52
+ brew install tesseract poppler
53
+ ```
54
+
55
+ **Linux (Ubuntu/Debian):**
56
+ ```bash
57
+ sudo apt-get install tesseract-ocr poppler-utils
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ### Option 1: Run Directly from GitHub (Easiest - No Installation!)
63
+
64
+ ```bash
65
+ uvx --from git+https://github.com/sameerbajaj/pdf-ocr pdf-ocr
66
+ ```
67
+
68
+ That's it! The tool will run directly without any installation.
69
+
70
+ ### Option 2: Clone and Run Locally
71
+
72
+ ```bash
73
+ # Clone the repository
74
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
75
+ cd pdf-ocr
76
+
77
+ # Run directly
78
+ uvx --from . pdf-ocr
79
+ ```
80
+
81
+ ### Option 3: Install Permanently
82
+
83
+ ```bash
84
+ # Clone and install
85
+ git clone https://github.com/sameerbajaj/pdf-ocr.git
86
+ cd pdf-ocr
87
+ uv pip install -e .
88
+ source .venv/bin/activate
89
+
90
+ # Run from anywhere
91
+ pdf-ocr
92
+ ```
93
+
94
+ ## Usage
95
+
96
+ ### Interactive Mode (Recommended)
97
+
98
+ Simply run the command and follow the friendly prompts:
99
+
100
+ ```bash
101
+ pdf-ocr
102
+ ```
103
+
104
+ The tool will ask you:
105
+ 1. **Which PDF file?** - You can type the path or drag & drop the file
106
+ 2. **Which pages?** - Enter a range like `4-5`, a single page like `7`, or press Enter for all pages
107
+
108
+ ### Command-Line Mode
109
+
110
+ ```bash
111
+ # Process entire PDF
112
+ pdf-ocr document.pdf
113
+
114
+ # Process specific pages
115
+ pdf-ocr document.pdf --pages 4-5
116
+ pdf-ocr document.pdf -p 1-10
117
+
118
+ # Custom output
119
+ pdf-ocr document.pdf --output result.pdf
120
+
121
+ # Save text files too
122
+ pdf-ocr document.pdf --save-text
123
+
124
+ # Higher quality (slower)
125
+ pdf-ocr document.pdf --dpi 400
126
+ ```
127
+
128
+ ## Examples
129
+
130
+ ```bash
131
+ # Process pages 4-5 of a book
132
+ pdf-ocr book.pdf --pages 4-5
133
+
134
+ # Process chapter (pages 20-40) with text export
135
+ pdf-ocr textbook.pdf -p 20-40 --save-text
136
+
137
+ # High-quality scan of a single page
138
+ pdf-ocr scan.pdf --pages 7 --dpi 600
139
+ ```
140
+
141
+ ## Output
142
+
143
+ The tool generates:
144
+ - **`filename_ocr.pdf`** or **`filename_pages4-5_ocr.pdf`** - Searchable PDF with text layer
145
+ - **`filename_pageX.txt`** (optional) - Plain text files if `--save-text` is used
146
+
147
+ All files are saved in the same directory as the input PDF.
148
+
149
+ ## Troubleshooting
150
+
151
+ **Command not found:**
152
+ ```bash
153
+ source .venv/bin/activate
154
+ ```
155
+
156
+ **Tesseract not installed:**
157
+ ```bash
158
+ brew install tesseract # macOS
159
+ sudo apt-get install tesseract-ocr # Linux
160
+ ```
161
+
162
+ **Poppler not installed:**
163
+ ```bash
164
+ brew install poppler # macOS
165
+ sudo apt-get install poppler-utils # Linux
166
+ ```
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ # Setup for development
172
+ git clone https://github.com/yourusername/pdf-ocr-tool.git
173
+ cd pdf-ocr-tool
174
+ uv venv
175
+ source .venv/bin/activate
176
+ uv pip install -e ".[dev]"
177
+
178
+ # Run from source
179
+ python -m pdf_ocr_tool.cli
180
+ ```
181
+
182
+ ## Project Structure
183
+
184
+ ```
185
+ pdf-ocr-tool/
186
+ ├── pdf_ocr_tool/ # Main package
187
+ │ ├── cli.py # Command-line interface
188
+ │ ├── ocr.py # OCR processing
189
+ │ └── pdf_utils.py # PDF generation
190
+ ├── pyproject.toml # Package configuration
191
+ ├── setup.sh # Auto-installer script
192
+ └── README.md # This file
193
+ ```
194
+
195
+ ## License
196
+
197
+ MIT License - see LICENSE file for details.
198
+
199
+ ## Acknowledgments
200
+
201
+ - [Tesseract OCR](https://github.com/tesseract-ocr/tesseract)
202
+ - [pdf2image](https://github.com/Belval/pdf2image)
203
+ - [Rich](https://github.com/Textualize/rich)
204
+
205
+ ---
206
+
207
+ Part of the open-source tools collection by [Sameer Bajaj](https://sameerbajaj.com). Learn more on the [project page](https://sameerbajaj.com/tools/pdf-ocr/).
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pdf_ocr_cli.py
4
+ pyproject.toml
5
+ pdf_ocr_cli.egg-info/PKG-INFO
6
+ pdf_ocr_cli.egg-info/SOURCES.txt
7
+ pdf_ocr_cli.egg-info/dependency_links.txt
8
+ pdf_ocr_cli.egg-info/entry_points.txt
9
+ pdf_ocr_cli.egg-info/requires.txt
10
+ pdf_ocr_cli.egg-info/top_level.txt
11
+ pdf_ocr_tool/__init__.py
12
+ pdf_ocr_tool/cli.py
13
+ pdf_ocr_tool/ocr.py
14
+ pdf_ocr_tool/pdf_utils.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ pdf-ocr = pdf_ocr_tool.cli:main
3
+ pdf-ocr-cli = pdf_ocr_tool.cli:main
@@ -0,0 +1,11 @@
1
+ pytesseract>=0.3.13
2
+ pdf2image>=1.17.0
3
+ pillow>=10.0.0
4
+ click>=8.1.0
5
+ rich>=13.0.0
6
+ PyPDF2>=3.0.0
7
+
8
+ [dev]
9
+ pytest>=7.0.0
10
+ black>=23.0.0
11
+ ruff>=0.1.0
@@ -0,0 +1,2 @@
1
+ pdf_ocr_cli
2
+ pdf_ocr_tool
@@ -0,0 +1,5 @@
1
+ """Command-line interface for PDF OCR Tool."""
2
+ from pdf_ocr_tool.cli import main
3
+
4
+ if __name__ == "__main__":
5
+ main()
@@ -0,0 +1,3 @@
1
+ """PDF OCR Tool - High-quality OCR for scanned PDFs."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,352 @@
1
+ """Command-line interface for PDF OCR tool."""
2
+
3
+ import os
4
+ import sys
5
+ import re
6
+ from pathlib import Path
7
+ from typing import Optional, Tuple
8
+
9
+ import click
10
+ from rich.console import Console
11
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
12
+ from rich.panel import Panel
13
+ from rich.text import Text
14
+ from rich import print as rprint
15
+
16
+ from .ocr import OCRProcessor
17
+ from .pdf_utils import create_searchable_pdf, save_text_files
18
+
19
+
20
+ console = Console()
21
+
22
+
23
+ def parse_page_range(page_range_str: str) -> Tuple[int, int]:
24
+ """
25
+ Parse page range string like '4-5', '1-10', '5' into tuple.
26
+
27
+ Args:
28
+ page_range_str: String like "4-5" or "4" or "1-10"
29
+
30
+ Returns:
31
+ Tuple of (start_page, end_page)
32
+
33
+ Raises:
34
+ ValueError: If format is invalid
35
+ """
36
+ page_range_str = page_range_str.strip()
37
+
38
+ if '-' in page_range_str:
39
+ parts = page_range_str.split('-')
40
+ if len(parts) != 2:
41
+ raise ValueError("Invalid page range format. Use 'start-end' like '4-5' or '1-10'")
42
+
43
+ try:
44
+ start = int(parts[0].strip())
45
+ end = int(parts[1].strip())
46
+ except ValueError:
47
+ raise ValueError("Page numbers must be integers")
48
+
49
+ if start < 1 or end < 1:
50
+ raise ValueError("Page numbers must be positive (starting from 1)")
51
+
52
+ if start > end:
53
+ raise ValueError(f"Start page ({start}) must be less than or equal to end page ({end})")
54
+
55
+ return (start, end)
56
+ else:
57
+ try:
58
+ page = int(page_range_str)
59
+ except ValueError:
60
+ raise ValueError("Invalid page number. Must be an integer")
61
+
62
+ if page < 1:
63
+ raise ValueError("Page numbers must be positive (starting from 1)")
64
+
65
+ return (page, page)
66
+
67
+
68
+ def normalize_path(path_str: str) -> Path:
69
+ """
70
+ Normalize file path, handling backslashes and spaces.
71
+
72
+ Args:
73
+ path_str: Input path string (may contain backslashes from copy-paste)
74
+
75
+ Returns:
76
+ Normalized Path object
77
+ """
78
+ # Remove backslashes used as escape characters (common when copy-pasting macOS paths)
79
+ path_str = path_str.replace('\\ ', ' ')
80
+
81
+ # Expand user home directory
82
+ path_str = os.path.expanduser(path_str)
83
+
84
+ # Convert to Path and resolve
85
+ return Path(path_str).resolve()
86
+
87
+
88
+ def validate_pdf_path(pdf_path: Path) -> None:
89
+ """
90
+ Validate that PDF file exists and is readable.
91
+
92
+ Args:
93
+ pdf_path: Path to PDF file
94
+
95
+ Raises:
96
+ click.ClickException: If file is invalid
97
+ """
98
+ if not pdf_path.exists():
99
+ raise click.ClickException(f"File not found: {pdf_path}")
100
+
101
+ if not pdf_path.is_file():
102
+ raise click.ClickException(f"Not a file: {pdf_path}")
103
+
104
+ if pdf_path.suffix.lower() != '.pdf':
105
+ console.print("[yellow]Warning: File doesn't have .pdf extension[/yellow]")
106
+
107
+ if not os.access(pdf_path, os.R_OK):
108
+ raise click.ClickException(f"File not readable: {pdf_path}")
109
+
110
+
111
+ @click.command()
112
+ @click.argument('pdf_path', type=str, required=False)
113
+ @click.option(
114
+ '--pages', '-p',
115
+ type=str,
116
+ help='Page range to process (e.g., "4-5", "1-10", "7"). Leave empty for all pages.'
117
+ )
118
+ @click.option(
119
+ '--output', '-o',
120
+ type=str,
121
+ help='Output PDF path (default: adds "_ocr" suffix to input filename)'
122
+ )
123
+ @click.option(
124
+ '--dpi',
125
+ type=int,
126
+ default=300,
127
+ help='DPI for image conversion (default: 300, higher = better quality but slower)'
128
+ )
129
+ @click.option(
130
+ '--save-text/--no-save-text',
131
+ default=False,
132
+ help='Also save extracted text to .txt files'
133
+ )
134
+ @click.option(
135
+ '--output-dir',
136
+ type=str,
137
+ help='Directory for output files (default: same as input PDF)'
138
+ )
139
+ @click.version_option(version="1.0.0", prog_name="pdf-ocr")
140
+ def main(
141
+ pdf_path: Optional[str],
142
+ pages: Optional[str],
143
+ output: Optional[str],
144
+ dpi: int,
145
+ save_text: bool,
146
+ output_dir: Optional[str]
147
+ ):
148
+ """
149
+ High-quality OCR tool for scanned PDFs using Tesseract.
150
+
151
+ Convert scanned PDFs into searchable PDFs with selectable text.
152
+
153
+ Examples:
154
+
155
+ # Interactive mode
156
+ pdf-ocr
157
+
158
+ # Process entire PDF
159
+ pdf-ocr document.pdf
160
+
161
+ # Process specific pages
162
+ pdf-ocr document.pdf --pages 4-5
163
+ pdf-ocr document.pdf -p 1-10
164
+
165
+ # Process with custom output
166
+ pdf-ocr document.pdf --output result.pdf
167
+
168
+ # Process with text files
169
+ pdf-ocr document.pdf --save-text
170
+ """
171
+ console.print(Panel.fit(
172
+ "[bold cyan]PDF OCR Tool[/bold cyan]\n"
173
+ "High-quality OCR for scanned PDFs",
174
+ border_style="cyan"
175
+ ))
176
+
177
+ # Interactive mode if no PDF path provided
178
+ if not pdf_path:
179
+ console.print("\n[bold cyan]Step 1: Select your PDF file[/bold cyan]")
180
+ console.print(" • You can type the full path to your PDF")
181
+ console.print(" • Or drag and drop the PDF file into this terminal")
182
+ console.print(" • Press Enter when done\n")
183
+ pdf_path = input("📄 PDF file path: ").strip()
184
+
185
+ if not pdf_path:
186
+ console.print("[red]✗ No PDF path provided. Exiting.[/red]")
187
+ sys.exit(1)
188
+
189
+ # Normalize and validate PDF path
190
+ try:
191
+ pdf_path_obj = normalize_path(pdf_path)
192
+ validate_pdf_path(pdf_path_obj)
193
+ except click.ClickException as e:
194
+ console.print(f"[red]Error: {e.message}[/red]")
195
+ sys.exit(1)
196
+
197
+ console.print(f"\n[green]✓[/green] Found PDF: [bold]{pdf_path_obj.name}[/bold]")
198
+
199
+ # Interactive page range if not provided
200
+ page_range = None
201
+ if pages:
202
+ try:
203
+ page_range = parse_page_range(pages)
204
+ console.print(f"[green]✓[/green] Processing pages: [bold]{page_range[0]}-{page_range[1]}[/bold]")
205
+ except ValueError as e:
206
+ console.print(f"[red]Error: {e}[/red]")
207
+ sys.exit(1)
208
+ else:
209
+ console.print("\n[bold cyan]Step 2: Choose which pages to process[/bold cyan]")
210
+ console.print(" • Enter a page range like: [bold]4-5[/bold] (pages 4 through 5)")
211
+ console.print(" • Or a single page like: [bold]7[/bold] (just page 7)")
212
+ console.print(" • Or press [bold]Enter[/bold] to process the entire PDF\n")
213
+ console.print("[dim]Examples: 4-5, 1-10, 20-25, or just 7[/dim]\n")
214
+ pages_input = input("📖 Which pages? (press Enter for all): ").strip()
215
+
216
+ if pages_input:
217
+ try:
218
+ page_range = parse_page_range(pages_input)
219
+ console.print(f"\n[green]✓[/green] Will process pages: [bold]{page_range[0]} to {page_range[1]}[/bold]")
220
+ except ValueError as e:
221
+ console.print(f"[red]✗ Error: {e}[/red]")
222
+ sys.exit(1)
223
+ else:
224
+ console.print("\n[green]✓[/green] Will process [bold]all pages[/bold] in the PDF")
225
+
226
+ # Determine output directory
227
+ if output_dir:
228
+ out_dir = Path(output_dir).resolve()
229
+ out_dir.mkdir(parents=True, exist_ok=True)
230
+ else:
231
+ out_dir = pdf_path_obj.parent
232
+
233
+ # Determine output PDF path
234
+ if output:
235
+ output_pdf = normalize_path(output)
236
+ else:
237
+ # Generate output filename
238
+ base_name = pdf_path_obj.stem
239
+ if page_range:
240
+ suffix = f"_pages{page_range[0]}-{page_range[1]}_ocr"
241
+ else:
242
+ suffix = "_ocr"
243
+ output_pdf = out_dir / f"{base_name}{suffix}.pdf"
244
+
245
+ console.print(f"[green]✓[/green] Output PDF: [bold]{output_pdf.name}[/bold]")
246
+
247
+ # Initialize OCR processor
248
+ processor = OCRProcessor(dpi=dpi)
249
+
250
+ # Check dependencies
251
+ console.print("\n[bold]Checking dependencies...[/bold]")
252
+ success, message = processor.check_dependencies()
253
+ if not success:
254
+ console.print(f"[red]✗ {message}[/red]")
255
+ sys.exit(1)
256
+ console.print("[green]✓ All dependencies installed[/green]")
257
+
258
+ # Process PDF
259
+ console.print("\n[bold cyan]Starting OCR processing...[/bold cyan]")
260
+
261
+ try:
262
+ with Progress(
263
+ SpinnerColumn(),
264
+ TextColumn("[progress.description]{task.description}"),
265
+ BarColumn(),
266
+ TaskProgressColumn(),
267
+ console=console
268
+ ) as progress:
269
+
270
+ # Convert PDF to images
271
+ task1 = progress.add_task(
272
+ f"[cyan]Converting PDF to images (DPI: {dpi})...",
273
+ total=None
274
+ )
275
+ images = processor.convert_pdf_to_images(str(pdf_path_obj), page_range)
276
+ progress.update(task1, completed=True)
277
+ console.print(f"[green]✓[/green] Converted [bold]{len(images)}[/bold] page(s) to images")
278
+
279
+ # Perform OCR
280
+ task2 = progress.add_task(
281
+ "[cyan]Performing OCR on pages...",
282
+ total=len(images)
283
+ )
284
+
285
+ ocr_results = []
286
+ for idx, image in enumerate(images):
287
+ progress.update(task2, advance=1, description=f"[cyan]OCR on page {idx + 1}/{len(images)}...")
288
+ ocr_text = processor.ocr_image(image)
289
+ ocr_results.append((image, ocr_text))
290
+
291
+ console.print(f"[green]✓[/green] OCR completed for [bold]{len(images)}[/bold] page(s)")
292
+
293
+ # Create searchable PDF
294
+ task3 = progress.add_task(
295
+ "[cyan]Creating searchable PDF...",
296
+ total=len(images)
297
+ )
298
+
299
+ def pdf_progress(current, total):
300
+ progress.update(task3, completed=current)
301
+
302
+ create_searchable_pdf(images, str(output_pdf), pdf_progress)
303
+ console.print(f"[green]✓[/green] Created searchable PDF: [bold]{output_pdf}[/bold]")
304
+
305
+ # Save text files if requested
306
+ if save_text:
307
+ task4 = progress.add_task("[cyan]Saving text files...", total=None)
308
+ start_page = page_range[0] if page_range else 1
309
+ text_files = save_text_files(
310
+ ocr_results,
311
+ str(out_dir),
312
+ pdf_path_obj.stem,
313
+ start_page
314
+ )
315
+ progress.update(task4, completed=True)
316
+ console.print(f"[green]✓[/green] Saved [bold]{len(text_files)}[/bold] text file(s)")
317
+
318
+ # Summary
319
+ file_size = output_pdf.stat().st_size / (1024 * 1024) # MB
320
+
321
+ console.print("\n" + "="*60)
322
+ console.print(Panel.fit(
323
+ f"[bold green]✓ OCR Complete![/bold green]\n\n"
324
+ f"[bold]Output PDF:[/bold] {output_pdf}\n"
325
+ f"[bold]File size:[/bold] {file_size:.2f} MB\n"
326
+ f"[bold]Pages processed:[/bold] {len(images)}\n"
327
+ f"[bold]Status:[/bold] Searchable & selectable text ✓",
328
+ border_style="green",
329
+ title="Success"
330
+ ))
331
+
332
+ # Show sample text
333
+ if ocr_results:
334
+ sample_text = ocr_results[0][1][:200].strip()
335
+ if sample_text:
336
+ console.print(f"\n[dim]Sample text from first page:[/dim]")
337
+ console.print(f"[dim]{sample_text}...[/dim]")
338
+
339
+ except Exception as e:
340
+ console.print(f"\n[red]✗ Error during processing:[/red]")
341
+ console.print(f"[red]{str(e)}[/red]")
342
+
343
+ if "poppler" in str(e).lower():
344
+ console.print("\n[yellow]Install poppler with:[/yellow]")
345
+ console.print(" macOS: [bold]brew install poppler[/bold]")
346
+ console.print(" Linux: [bold]apt-get install poppler-utils[/bold]")
347
+
348
+ sys.exit(1)
349
+
350
+
351
+ if __name__ == '__main__':
352
+ main()
@@ -0,0 +1,135 @@
1
+ """Core OCR processing functionality."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import List, Tuple
6
+ from PIL import Image
7
+ import pytesseract
8
+ from pdf2image import convert_from_path
9
+
10
+
11
+ class OCRProcessor:
12
+ """Handle OCR processing for PDF pages."""
13
+
14
+ def __init__(self, dpi: int = 300, tesseract_config: str = '--oem 3 --psm 3'):
15
+ """
16
+ Initialize OCR processor.
17
+
18
+ Args:
19
+ dpi: Resolution for PDF to image conversion (default: 300)
20
+ tesseract_config: Tesseract configuration string
21
+ """
22
+ self.dpi = dpi
23
+ self.tesseract_config = tesseract_config
24
+
25
+ def check_dependencies(self) -> Tuple[bool, str]:
26
+ """
27
+ Check if required system dependencies are installed.
28
+
29
+ Returns:
30
+ Tuple of (success: bool, message: str)
31
+ """
32
+ # Check Tesseract
33
+ try:
34
+ pytesseract.get_tesseract_version()
35
+ except Exception as e:
36
+ return False, (
37
+ "Tesseract OCR is not installed or not in PATH.\n"
38
+ "Install it with: brew install tesseract (macOS) or apt-get install tesseract-ocr (Linux)"
39
+ )
40
+
41
+ # Check poppler (required by pdf2image)
42
+ try:
43
+ # This will fail if poppler is not installed
44
+ from pdf2image.exceptions import PDFInfoNotInstalledError
45
+ # Try a simple conversion to check if poppler works
46
+ # We'll catch the error if it's not installed
47
+ except ImportError:
48
+ pass
49
+
50
+ return True, "All dependencies are installed."
51
+
52
+ def convert_pdf_to_images(
53
+ self,
54
+ pdf_path: str,
55
+ page_range: Tuple[int, int] = None
56
+ ) -> List[Image.Image]:
57
+ """
58
+ Convert PDF pages to images.
59
+
60
+ Args:
61
+ pdf_path: Path to PDF file
62
+ page_range: Tuple of (start_page, end_page) or None for all pages
63
+
64
+ Returns:
65
+ List of PIL Image objects
66
+ """
67
+ kwargs = {'dpi': self.dpi}
68
+
69
+ if page_range:
70
+ kwargs['first_page'] = page_range[0]
71
+ kwargs['last_page'] = page_range[1]
72
+
73
+ try:
74
+ images = convert_from_path(pdf_path, **kwargs)
75
+ return images
76
+ except Exception as e:
77
+ if "poppler" in str(e).lower() or "pdftoppm" in str(e).lower():
78
+ raise RuntimeError(
79
+ "Poppler is not installed or not in PATH.\n"
80
+ "Install it with: brew install poppler (macOS) or apt-get install poppler-utils (Linux)"
81
+ )
82
+ raise
83
+
84
+ def ocr_image(self, image: Image.Image) -> str:
85
+ """
86
+ Perform OCR on a single image.
87
+
88
+ Args:
89
+ image: PIL Image object
90
+
91
+ Returns:
92
+ Extracted text as string
93
+ """
94
+ return pytesseract.image_to_string(image, config=self.tesseract_config)
95
+
96
+ def ocr_image_to_pdf(self, image: Image.Image) -> bytes:
97
+ """
98
+ Perform OCR on image and return PDF bytes with text layer.
99
+
100
+ Args:
101
+ image: PIL Image object
102
+
103
+ Returns:
104
+ PDF bytes with searchable text layer
105
+ """
106
+ return pytesseract.image_to_pdf_or_hocr(image, extension='pdf')
107
+
108
+ def process_pdf(
109
+ self,
110
+ pdf_path: str,
111
+ page_range: Tuple[int, int] = None,
112
+ progress_callback=None
113
+ ) -> List[Tuple[Image.Image, str]]:
114
+ """
115
+ Process PDF and return images with OCR text.
116
+
117
+ Args:
118
+ pdf_path: Path to PDF file
119
+ page_range: Tuple of (start_page, end_page) or None for all pages
120
+ progress_callback: Optional callback function for progress updates
121
+
122
+ Returns:
123
+ List of tuples (image, ocr_text)
124
+ """
125
+ images = self.convert_pdf_to_images(pdf_path, page_range)
126
+ results = []
127
+
128
+ for idx, image in enumerate(images):
129
+ if progress_callback:
130
+ progress_callback(idx + 1, len(images))
131
+
132
+ ocr_text = self.ocr_image(image)
133
+ results.append((image, ocr_text))
134
+
135
+ return results
@@ -0,0 +1,154 @@
1
+ """PDF generation utilities."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import List
6
+ from PIL import Image
7
+ import pytesseract
8
+
9
+
10
+ def create_searchable_pdf(
11
+ images: List[Image.Image],
12
+ output_path: str,
13
+ progress_callback=None
14
+ ) -> str:
15
+ """
16
+ Create a searchable PDF from images with OCR text layer.
17
+
18
+ Args:
19
+ images: List of PIL Image objects
20
+ output_path: Path for output PDF file
21
+ progress_callback: Optional callback for progress updates
22
+
23
+ Returns:
24
+ Path to created PDF file
25
+ """
26
+ try:
27
+ # Use PyPDF2 to merge multiple pages
28
+ from PyPDF2 import PdfMerger
29
+ except ImportError:
30
+ # Fallback: create single-page or multi-page PDF directly
31
+ return _create_pdf_direct(images, output_path, progress_callback)
32
+
33
+ merger = PdfMerger()
34
+ temp_files = []
35
+
36
+ try:
37
+ for idx, image in enumerate(images):
38
+ if progress_callback:
39
+ progress_callback(idx + 1, len(images))
40
+
41
+ # Create temporary PDF for each page
42
+ temp_pdf = f".temp_page_{idx}_{os.getpid()}.pdf"
43
+ temp_files.append(temp_pdf)
44
+
45
+ # Generate searchable PDF using pytesseract
46
+ pdf_data = pytesseract.image_to_pdf_or_hocr(image, extension='pdf')
47
+
48
+ with open(temp_pdf, 'wb') as f:
49
+ f.write(pdf_data)
50
+
51
+ merger.append(temp_pdf)
52
+
53
+ # Write the merged PDF
54
+ merger.write(output_path)
55
+ merger.close()
56
+
57
+ finally:
58
+ # Clean up temporary files
59
+ for temp_file in temp_files:
60
+ try:
61
+ if os.path.exists(temp_file):
62
+ os.remove(temp_file)
63
+ except Exception:
64
+ pass
65
+
66
+ return output_path
67
+
68
+
69
+ def _create_pdf_direct(
70
+ images: List[Image.Image],
71
+ output_path: str,
72
+ progress_callback=None
73
+ ) -> str:
74
+ """
75
+ Create PDF directly when PyPDF2 is not available.
76
+
77
+ For single page PDFs or fallback method.
78
+ """
79
+ if len(images) == 1:
80
+ # Single page - direct conversion
81
+ if progress_callback:
82
+ progress_callback(1, 1)
83
+
84
+ pdf_data = pytesseract.image_to_pdf_or_hocr(images[0], extension='pdf')
85
+ with open(output_path, 'wb') as f:
86
+ f.write(pdf_data)
87
+ else:
88
+ # Multiple pages - need to combine somehow
89
+ # This is a fallback - try using img2pdf if available
90
+ try:
91
+ import img2pdf
92
+
93
+ # Convert images to bytes
94
+ image_bytes_list = []
95
+ for idx, img in enumerate(images):
96
+ if progress_callback:
97
+ progress_callback(idx + 1, len(images))
98
+
99
+ # Create OCR PDF for this page
100
+ pdf_bytes = pytesseract.image_to_pdf_or_hocr(img, extension='pdf')
101
+ image_bytes_list.append(pdf_bytes)
102
+
103
+ # For now, just save the first one with a warning
104
+ with open(output_path, 'wb') as f:
105
+ f.write(image_bytes_list[0])
106
+
107
+ print("Warning: PyPDF2 not available. Only first page saved.")
108
+ print("Install PyPDF2 for multi-page PDF support: uv pip install PyPDF2")
109
+
110
+ except ImportError:
111
+ # No merge capability - save first page only
112
+ pdf_data = pytesseract.image_to_pdf_or_hocr(images[0], extension='pdf')
113
+ with open(output_path, 'wb') as f:
114
+ f.write(pdf_data)
115
+
116
+ print("Warning: Limited PDF support. Only first page saved.")
117
+ print("Install PyPDF2 for multi-page PDF support: uv pip install PyPDF2")
118
+
119
+ return output_path
120
+
121
+
122
+ def save_text_files(
123
+ ocr_results: List[tuple],
124
+ output_dir: str,
125
+ base_name: str,
126
+ start_page: int = 1
127
+ ) -> List[str]:
128
+ """
129
+ Save OCR text to individual text files.
130
+
131
+ Args:
132
+ ocr_results: List of (image, text) tuples
133
+ output_dir: Directory to save text files
134
+ base_name: Base name for output files
135
+ start_page: Starting page number for naming
136
+
137
+ Returns:
138
+ List of created file paths
139
+ """
140
+ output_dir = Path(output_dir)
141
+ output_dir.mkdir(parents=True, exist_ok=True)
142
+
143
+ created_files = []
144
+
145
+ for idx, (image, text) in enumerate(ocr_results):
146
+ page_num = start_page + idx
147
+ text_file = output_dir / f"{base_name}_page{page_num}.txt"
148
+
149
+ with open(text_file, 'w', encoding='utf-8') as f:
150
+ f.write(text)
151
+
152
+ created_files.append(str(text_file))
153
+
154
+ return created_files
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pdf-ocr-cli"
7
+ version = "1.0.0"
8
+ description = "High-quality OCR tool for scanned PDFs using Tesseract"
9
+ authors = [
10
+ {name = "Sameer Bajaj", email = "sameer@sameerbajaj.com"}
11
+ ]
12
+ readme = "README.md"
13
+ requires-python = ">=3.9"
14
+ license = "MIT"
15
+ keywords = ["ocr", "pdf", "tesseract", "document-processing"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: End Users/Desktop",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ ]
26
+
27
+ dependencies = [
28
+ "pytesseract>=0.3.13",
29
+ "pdf2image>=1.17.0",
30
+ "pillow>=10.0.0",
31
+ "click>=8.1.0",
32
+ "rich>=13.0.0",
33
+ "PyPDF2>=3.0.0",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "pytest>=7.0.0",
39
+ "black>=23.0.0",
40
+ "ruff>=0.1.0",
41
+ ]
42
+
43
+ [project.scripts]
44
+ pdf-ocr = "pdf_ocr_tool.cli:main"
45
+ pdf-ocr-cli = "pdf_ocr_tool.cli:main"
46
+
47
+ [tool.setuptools]
48
+ packages = ["pdf_ocr_tool"]
49
+ py-modules = ["pdf_ocr_cli"]
50
+
51
+ [project.urls]
52
+ Homepage = "https://sameerbajaj.com/tools/pdf-ocr/"
53
+ Website = "https://sameerbajaj.com"
54
+ Repository = "https://github.com/sameerbajaj/pdf-ocr"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+