Panel2EPUB is a small toolkit and desktop application to convert image folders or CBZ files into fixed-layout EPUB books, with specific support for comics and manga:
-
automatic double-page detection and splitting
-
configurable reading direction (RTL / LTR)
-
smart cover handling (
cover.*file or first image) -
EPUB 3–compatible structure (OPF, TOC, NAV, CSS)
It is designed to generate clean EPUBs that work well on typical e-readers and tablet reading apps.
-
Two input modes
-
Image folder mode
-
One or multiple CBZ files (batch conversion)
-
-
Cover handling
-
If a file named
cover.*(e.g.cover.jpg,cover.png) exists, it is used as cover. -
Otherwise, the first image is used as cover.
-
-
Double-page support
-
Detects potential double-page spreads based on a width/height ratio threshold.
-
Splits double pages vertically into left/right halves.
-
Supports both LTR and RTL mapping:
-
LTR:
_a= left half,_b= right half -
RTL:
_a= right half,_b= left half
-
-
Optionally inserts blank pages to align spreads correctly (
page-spread-left/page-spread-right).
-
-
Reading direction
-
RTLfor manga-style reading. -
LTRfor western comics or standard books. -
Encoded properly in the EPUB spine (
page-progression-direction).
-
-
Fixed-layout EPUB
-
Pre-paginated pages with image-based layout.
-
Per-page viewport equal to the image size (or half-size for double-page splits).
-
Simple CSS for fullscreen display without borders.
-
-
Batch processing for CBZ
-
Multiple CBZ files can be selected at once.
-
Each CBZ is extracted, converted, and its extraction folder is removed afterwards.
-
All resulting EPUB files are written in the chosen output root folder.
-
-
Temporary folder cleanup
-
A
temp/working folder is created under the output root. -
Once the EPUB is created,
temp/is removed automatically.
-
-
Python 3.12.7+ (tested with CPython 3.x)
-
A desktop OS supported by:
-
Tkinter (for the GUI)
-
Pillow (for image manipulation)
-
The code only uses the Python standard library plus Pillow and Pillow’s Image module, which handles image loading, sizing and cropping.
Content of requirements.txt could be:
Pillow>=10.0.0
All other imports are from the standard library:
-
os,shutil,datetime,uuid,zipfile -
xml.sax.saxutils.escape,html.escape -
threading,traceback -
tkinter/tkinter.ttk/tkinter.filedialog/tkinter.messagebox
Note: Tkinter is bundled with the official Python installers on Windows and most Linux distributions. On some minimal Linux setups, you may need to install it via your package manager (for example
python3-tkon Debian/Ubuntu).
Generated EPUBs are, in principle, EPUB 3 fixed-layout compatible.
However, they have only been tested manually with:
-
Thorium Reader (desktop – Windows/macOS/Linux) (GitHub)
-
Open-source EPUB 3 reader focused on accessibility and good support for reflowable and fixed-layout EPUB.
-
GitHub:
https://github.com/edrlab/thorium-reader
-
-
Apple Books on iOS / iPadOS (Apple)
- Built-in Apple e-book app on iPhone/iPad, supporting EPUB (including fixed layout) and PDF.
Other reading apps and devices may:
-
ignore some
rendition:metadata, -
handle spreads differently,
-
or have varying support for fixed-layout EPUB 3.
If you rely on a specific device or app, you should test a few sample books.
panel2epub/
├─ convert_to_epub.py # Core logic: EPUB structure / splitting / OPF / TOC
├─ panel2epub_gui.py # Tkinter GUI (EpubApp)
├─ README.md
├─ requirements.txt
├─ test_book.cbz # Example of input CBZ (optional)
└─ test_book/ # Example input images (optional)
In the codebase described:
-
convert_to_epub.pycontains:-
initial_setup -
copy_images_to_temp_images -
generate_xhtml_pages -
generate_content_opf -
generate_toc_ncx -
generate_nav_xhtml -
generate_style_css -
create_epub_from_temp
-
-
The GUI file (e.g.
panel2epub_gui.py) contains:-
run_pipeline_folder -
run_pipeline_cbz_list -
EpubApp(Tkinter GUI, entry point underif __name__ == "__main__": ...)
-
- Clone the repository
git clone https://github.com/LouisCourrian/Panel2EPUB.git
cd Panel2EPUB- Create and activate a virtual environment (optional but recommended)
On Windows:
python -m venv .venv
.venv\Scripts\activateOn macOS / Linux:
python3 -m venv .venv
source .venv/bin/activate- Install dependencies
pip install -r requirements.txtor simply:
pip install Pillowif you are not using a requirements.txt file.
Assuming your GUI script is named panel2epub_gui.py:
python panel2epub_gui.pyA window titled “Convert to EPUB” should open.
At the top of the window:
-
CBZ file(s)
Batch conversion of one or more.cbzfiles. -
Image folder
Conversion of a single folder containing image files.
-
Click “Browse…” next to Source:
-
In folder mode: select the folder containing your images.
-
In CBZ mode: select one or more
.cbzfiles.
-
The selected path(s) are displayed in the text field.
-
Click “Browse…” next to Output root folder.
-
Choose where:
-
the temporary
temp/working directory will be created, and -
the resulting EPUB file(s) will be saved.
-
By default, this is your current working directory.
-
Only used when Source type = Image folder.
-
This becomes the EPUB title and the base for the output filename.
In CBZ mode, each EPUB title is derived from the CBZ filename.
-
Enter the Author (creator) of the book.
-
This field is required in both modes.
Checkbox text:
Use the first image as cover, or a file named cover.png / cover.jpg / ... if present.
Behaviour:
-
If checked:
-
If a file named
cover.*exists in the image set, it is used as the cover image. -
Otherwise, the first image is used as cover.
-
-
If unchecked:
- No special cover metadata is added (the first page is treated like any other).
-
RTL (manga): right-to-left reading order.
-
LTR: left-to-right reading order.
This affects:
-
the spine
page-progression-direction, and -
how
_a/_bhalves of double pages are mapped to left/right.
Field: Original resolution (w x h)
Example: 1072x1448
-
Used in metadata and as a fallback size when an image’s dimensions cannot be read.
-
Format:
widthxheight.
Field: Double page ratio (w/h ≥)
Example: 1.28
-
If
image_width / image_height >= double_page_ratio, the image is treated as a double-page spread. -
Double pages are split vertically into two halves and handled as a spread.
-
If parsing fails, a default value of
1.3is used.
Field: Spread mode (rendition:spread)
Options:
-
auto -
none -
landscape -
both
This value is written to:
<meta property="rendition:spread">...</meta>in content.opf, which may influence how certain reading apps display spreads.
Field: BookID (folder mode, empty = auto)
-
If provided, it is used as the EPUB’s unique identifier (
dc:identifier). -
If left empty, a value like
urn:uuid:<random-uuid>is generated automatically. -
In CBZ mode, a new BookID is always generated for each CBZ file and this field is ignored.
-
Click “Generate EPUB” to start conversion.
-
The button is disabled while the process runs in a background thread.
-
Log messages appear in the Log area at the bottom.
At the end:
-
On success, a message box shows the path(s) of the generated EPUB file(s).
-
On failure, an error message is shown and the full traceback is printed in the log area.
You can also use the core functions in convert_to_epub.py directly from your own scripts.
from convert_to_epub import (
initial_setup,
copy_images_to_temp_images,
generate_xhtml_pages,
generate_content_opf,
generate_toc_ncx,
generate_nav_xhtml,
generate_style_css,
create_epub_from_temp,
)
import uuid
import os
base_path = os.getcwd()
source_images = "./my_images"
title = "My Comic"
creator = "Author Name"
reading_direction = "rtl"
original_resolution = "1072x1448"
book_id = f"urn:uuid:{uuid.uuid4()}"
spread_mode = "auto"
double_page_ratio = 1.3
# 1) Prepare temp structure
initial_setup(base_path=base_path)
# 2) Copy images
copy_images_to_temp_images(source_folder=source_images, base_path=base_path)
# 3) Generate XHTML pages with double-page detection
fallback_w, fallback_h = 1072, 1448
generate_xhtml_pages(
base_path=base_path,
fallback_width=fallback_w,
fallback_height=fallback_h,
reading_direction=reading_direction,
double_page_ratio=double_page_ratio,
)
# 4) Generate OPF, TOC, NAV, CSS
generate_content_opf(
base_path=base_path,
title=title,
creator=creator,
has_cover=True,
reading_direction=reading_direction,
original_resolution=original_resolution,
book_id=book_id,
spread_mode=spread_mode,
)
generate_toc_ncx(base_path=base_path, book_id=book_id, title=title)
generate_nav_xhtml(base_path=base_path, title=title)
generate_style_css(base_path=base_path)
# 5) Create EPUB (temp folder is removed automatically)
epub_path = create_epub_from_temp(base_path=base_path, title=title)
print("EPUB generated:", epub_path)-
Detection
For each raster image (JPEG/PNG/WebP/etc.):
ratio = width / height
-
If
ratio >= double_page_ratio→ treated as a double-page spread. -
Otherwise → treated as a single page.
-
-
Splitting
For double-page images:
-
The image is split vertically into two halves (left / right).
-
Two new files are created with
_aand_bsuffixes. -
The original file is removed from the images folder.
-
-
Mapping (RTL / LTR)
-
LTR mode:
_a= left half,_b= right half.
-
RTL mode:
_a= right half,_b= left half.
-
-
Spine alignment
-
The system ensures that the first half of the spread appears on the correct side
(left or right), depending on the reading direction. -
If needed, a blank page is inserted before the spread to fix alignment.
-
-
The project targets fixed-layout, image-based EPUBs for comics/manga.
It is not meant for reflowable text EPUBs. -
Behaviour of spreads and
rendition:spreadmetadata can vary between reading systems. -
Tested only with:
-
Thorium Reader (desktop). (edrlab.org)
-
Apple Books on iOS / iPadOS. (Apple)
-
-
SVG images are currently skipped by the XHTML generator (they can be added later if needed).
-
Per-book configuration profiles.
-
Pure CLI mode (no GUI) for batch pipelines.
-
More advanced TOC generation (chapters, volumes, arcs).
-
Better SVG handling.
-
Reader/device-specific presets (Kindle, Kobo, etc.).
This project is released under The Unlicense.
In short: it is public-domain style software – you can copy, modify, redistribute, and use it for any purpose, with no warranty of any kind.
-
Python standard library (zipfile, tkinter, etc.)
-
Pillow for image processing
-
Thorium Reader for being a solid EPUB 3 test reader (GitHub)
-
Apple Books as a convenient EPUB reader on iOS / iPadOS (Apple)
If this project is useful to you and you would like to support it, you can send crypto donations to:
Ethereum address
0xcB27fF7e2A1B0e9BD0CCeDf76Bf0F90ebF4F7b85
Solana (SOL) address
2H38wLmz6RbV7Z9sXnMURxAggST9kSQvRFXZqkppzAFb
Thank you for your support 🙌
