pdf2epub 0.1.0

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,217 @@
1
+ # PDF2EPUB 📚
2
+
3
+ Convert PDF files to nicely structured Markdown and EPUB format with intelligent layout detection.
4
+
5
+ ## ✨ Features
6
+
7
+ - 📖 Smart layout detection for books and academic papers
8
+ - 🔍 Advanced text extraction and OCR capabilities
9
+ - 📊 Table detection and formatting
10
+ - 🖼️ Image extraction and optimization
11
+ - 📝 Clean markdown output with preserved structure
12
+ - 📱 EPUB generation with customizable styling
13
+ - 🌍 Multi-language support
14
+ - 🚀 GPU acceleration support (NVIDIA & AMD)
15
+ - 🍎 Apple Silicon support
16
+
17
+ ## 🛠️ Dependencies
18
+
19
+ - Python 3.10–3.14 (3.13 recommended, see below)
20
+ - PyTorch (with CUDA/ROCm support for GPU acceleration)
21
+ - marker-pdf==1.10.2
22
+ - transformers==4.57.6
23
+ - markdown==3.10.2
24
+ - latex2mathml==3.81.0
25
+
26
+ ### ⚠️ Python version
27
+
28
+ Python 3.13 is recommended.
29
+
30
+ `marker-pdf` constrains `Pillow<11.0.0`, and Pillow only ships Python 3.14
31
+ wheels from 11.3.0 onward. On Python 3.10–3.13 every dependency installs as a
32
+ prebuilt wheel. On 3.14, pip has to build Pillow from source instead: this
33
+ works, but it is slower and requires a working C toolchain plus the image
34
+ library headers Pillow links against. On Debian/Ubuntu install them first:
35
+
36
+ ```bash
37
+ sudo apt install libjpeg-dev zlib1g-dev libtiff-dev libfreetype6-dev libwebp-dev
38
+ ```
39
+
40
+ Without these headers the install fails with
41
+ `RequiredDependencyException: The headers or library files could not be found for jpeg`.
42
+
43
+ ## 💻 Installation
44
+
45
+ 1. Create and activate a virtual environment.
46
+
47
+ On Linux/Mac:
48
+ ```bash
49
+ python3.13 -m venv .venv
50
+ source .venv/bin/activate
51
+ ```
52
+
53
+ On Windows:
54
+ ```powershell
55
+ py -3.13 -m venv .venv
56
+ .venv\Scripts\activate
57
+ ```
58
+
59
+ 2. Install Python dependencies (this installs PyTorch as well):
60
+ ```bash
61
+ pip install -r requirements.txt
62
+ ```
63
+
64
+ 3. GPU acceleration (optional):
65
+
66
+ PyTorch is installed as a dependency in step 2. On Apple Silicon that wheel
67
+ already supports MPS, so no further action is needed. For a specific CUDA or
68
+ ROCm build, reinstall PyTorch using the selector at
69
+ [pytorch.org/get-started/locally](https://pytorch.org/get-started/locally/).
70
+ For example, for AMD GPUs with ROCm:
71
+ ```bash
72
+ pip uninstall torch torchvision torchaudio
73
+ pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.2
74
+ ```
75
+
76
+ 4. Verify GPU support:
77
+ ```python
78
+ import torch
79
+ print(torch.__version__) # PyTorch version
80
+ print(torch.cuda.is_available()) # Should return True for NVIDIA
81
+ print(torch.backends.mps.is_available()) # Should return True for Apple Silicon
82
+ print(torch.version.hip) # Should print ROCm version for AMD
83
+ ```
84
+
85
+ ### 🐳 Docker
86
+
87
+ A CPU-only image can be built from the included `Dockerfile`:
88
+
89
+ ```bash
90
+ docker build -t pdf2epub .
91
+ ```
92
+
93
+ Run it with your PDFs mounted at `/data` and a model cache volume (marker-pdf
94
+ downloads its models on first run):
95
+
96
+ ```bash
97
+ docker run -it --rm \
98
+ -v "$(pwd)":/data \
99
+ -v pdf2epub-models:/models \
100
+ pdf2epub input.pdf
101
+ ```
102
+
103
+ `-it` is required for EPUB generation because metadata is prompted
104
+ interactively; with `--skip-epub` it can run non-interactively.
105
+
106
+ Tagged releases are also published to
107
+ `ghcr.io/overcuriousity/pdf2epub` by the Docker workflow.
108
+
109
+ ## 🚀 Usage
110
+
111
+ ### Basic Usage
112
+
113
+ Convert a single PDF file:
114
+ ```bash
115
+ python main.py input.pdf
116
+ ```
117
+
118
+ Convert all PDFs in a directory:
119
+ ```bash
120
+ python main.py input_directory/
121
+ ```
122
+
123
+ EPUB generation prompts interactively for metadata (title, author, language,
124
+ and so on; press Enter to accept each default). It therefore needs a terminal —
125
+ run it non-interactively and it will fail with `EOFError`. Use `--skip-epub` to
126
+ produce only markdown without any prompts.
127
+
128
+ ### Advanced Options
129
+
130
+ ```bash
131
+ python main.py [input_path] [output_path] [options]
132
+
133
+ Options:
134
+ --max-pages INT Maximum number of pages to process
135
+ --start-page INT Page number to start from
136
+ --skip-epub Skip EPUB generation, only create markdown
137
+ --skip-md Skip markdown generation, use existing markdown files
138
+ ```
139
+
140
+ If `input_path` is omitted, all PDFs in `./input/` are processed.
141
+
142
+ ### Examples
143
+
144
+ Process a specific range of pages:
145
+ ```bash
146
+ python main.py book.pdf --start-page 10 --max-pages 50
147
+ ```
148
+
149
+ Convert to markdown only:
150
+ ```bash
151
+ python main.py thesis.pdf --skip-epub
152
+ ```
153
+
154
+ ### Output Structure
155
+
156
+ ```
157
+ output_directory/
158
+ ├── document_name/
159
+ │ ├── document_name.md
160
+ │ ├── document_name.epub
161
+ │ ├── document_name_metadata.json
162
+ │ └── images/
163
+ │ ├── image1.png
164
+ │ ├── image2.jpg
165
+ │ └── ...
166
+ ```
167
+
168
+ ## 🤝 Contributing
169
+
170
+ Contributions are welcome! Here's how you can help:
171
+
172
+ 1. Fork the repository
173
+ 2. Create a new branch for your feature
174
+ 3. Commit your changes
175
+ 4. Push to your branch
176
+ 5. Create a Pull Request
177
+
178
+ Please ensure your code follows the existing style and includes appropriate tests.
179
+
180
+ ### Development Setup
181
+
182
+ 1. Clone the repository:
183
+ ```bash
184
+ git clone https://github.com/overcuriousity/pdf2epub.git
185
+ cd pdf2epub
186
+ ```
187
+
188
+ 2. Create a virtual environment:
189
+ ```bash
190
+ python -m venv venv
191
+ source venv/bin/activate # Linux/Mac
192
+ venv\Scripts\activate # Windows
193
+ ```
194
+
195
+ 3. Install development dependencies:
196
+ ```bash
197
+ pip install -r requirements.txt
198
+ ```
199
+
200
+ ## 📄 License
201
+
202
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
203
+
204
+ ## 🐛 Known Issues
205
+
206
+ - Some image embedding might need manual adjustment
207
+ - Some complex mathematical equations might not be perfectly converted
208
+ - Certain PDF layouts with multiple columns may require manual adjustment
209
+ - Font detection might be imperfect in some cases
210
+
211
+ ## 🙏 Acknowledgments
212
+
213
+ This project builds upon several excellent open-source libraries:
214
+ - [marker-pdf](https://github.com/VikParuchuri/marker) for PDF processing
215
+ - [mark2epub](https://github.com/AlexPof/mark2epub) for markdown conversion
216
+ - [PyTorch](https://pytorch.org/) for GPU acceleration
217
+ - [Transformers](https://huggingface.co/transformers) for advanced text processing
@@ -0,0 +1,8 @@
1
+ {
2
+ "repo": "overcuriousity/pdf2epub",
3
+ "ref": "v1.1.0",
4
+ "commit": "5eae669d1c897b4735f369fb2ff4086237db3a81",
5
+ "commitDate": "2026-07-16T18:17:11Z",
6
+ "url": "https://github.com/overcuriousity/pdf2epub/tree/5eae669d1c897b4735f369fb2ff4086237db3a81",
7
+ "syncedAt": "2026-09-07T09:36:39.940Z"
8
+ }
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import sys
4
+ from pathlib import Path
5
+ import modules.pdf2md as pdf2md
6
+ import modules.mark2epub as mark2epub
7
+ import torch
8
+
9
+
10
+
11
+ def main():
12
+ if torch.cuda.is_available():
13
+ print("CUDA is available. Using GPU for processing.")
14
+ elif torch.backends.mps.is_available():
15
+ print("MPS is available. Using Apple Silicon for processing.")
16
+ else:
17
+ print("CUDA is not available. Using CPU for processing.")
18
+
19
+ parser = argparse.ArgumentParser(
20
+ description='Convert PDF files to EPUB format via Markdown'
21
+ )
22
+ parser.add_argument(
23
+ 'input_path',
24
+ nargs='?',
25
+ type=str,
26
+ help='Path to input PDF file or directory (default: ./input/*.pdf)'
27
+ )
28
+ parser.add_argument(
29
+ 'output_path',
30
+ nargs='?',
31
+ type=str,
32
+ help='Path to output directory (default: directory named after PDF)'
33
+ )
34
+ parser.add_argument(
35
+ '--max-pages',
36
+ type=int,
37
+ default=None,
38
+ help='Maximum number of pages to process'
39
+ )
40
+ parser.add_argument(
41
+ '--start-page',
42
+ type=int,
43
+ default=None,
44
+ help='Page number to start from'
45
+ )
46
+ parser.add_argument(
47
+ '--skip-epub',
48
+ action='store_true',
49
+ help='Skip EPUB generation, only create markdown'
50
+ )
51
+ parser.add_argument(
52
+ '--skip-md',
53
+ action='store_true',
54
+ help='Skip markdown generation, use existing markdown files'
55
+ )
56
+
57
+ args = parser.parse_args()
58
+
59
+ # Get input path
60
+ input_path = Path(args.input_path) if args.input_path else pdf2md.get_default_input_dir()
61
+
62
+ # Get queue of PDFs to process
63
+ queue = pdf2md.add_pdfs_to_queue(input_path)
64
+ print(f"Found {len(queue)} PDF files to process")
65
+
66
+ # Process each PDF
67
+ failed = []
68
+ for pdf_path in queue:
69
+ print(f"\nProcessing: {pdf_path.name}")
70
+
71
+ # Get output directory for this PDF
72
+ if args.output_path:
73
+ output_path = Path(args.output_path)
74
+ markdown_dir = output_path / pdf_path.stem
75
+ else:
76
+ markdown_dir = pdf2md.get_default_output_dir(pdf_path)
77
+ output_path = markdown_dir.parent
78
+
79
+ try:
80
+ # Check if markdown directory exists when skipping MD generation
81
+ if args.skip_md:
82
+ if not markdown_dir.exists():
83
+ print(f"Error: Markdown directory not found: {markdown_dir}", file=sys.stderr)
84
+ failed.append(pdf_path.name)
85
+ continue
86
+ print(f"Using existing markdown files from: {markdown_dir}")
87
+
88
+ # Convert PDF to Markdown unless skipped
89
+ if not args.skip_md:
90
+ print("Converting PDF to Markdown...")
91
+ pdf2md.convert_pdf(
92
+ str(pdf_path),
93
+ markdown_dir,
94
+ args.max_pages,
95
+ args.start_page,
96
+ )
97
+
98
+ # Convert Markdown to EPUB unless skipped
99
+ if not args.skip_epub:
100
+ print("Converting Markdown to EPUB...")
101
+ mark2epub.convert_to_epub(markdown_dir, output_path)
102
+
103
+ except Exception as e:
104
+ print(f"Error processing {pdf_path.name}: {str(e)}", file=sys.stderr)
105
+ failed.append(pdf_path.name)
106
+ continue
107
+
108
+ if failed:
109
+ print(
110
+ f"\nFailed to process {len(failed)} of {len(queue)} PDF file(s):",
111
+ file=sys.stderr,
112
+ )
113
+ for name in failed:
114
+ print(f" - {name}", file=sys.stderr)
115
+ sys.exit(1)
116
+
117
+ if __name__ == '__main__':
118
+ main()
File without changes