Skip to main content

manga-page-splitter

Split scanned manga double-page spreads into single pages, in right-to-left reading order.

Scanned manga is usually distributed as one image per printed spread: two pages side by side, separated by the fold of the book. That is fine for reading, but it is awkward for anything that has to work page by page — e-ink readers, translation tooling, OCR, re-binding a volume into a single PDF with a sane page count. This package does the boring part: it finds the fold, cuts the spread in two, and hands you the pages in the order they are meant to be read.

Installation

pip install manga-page-splitter

The only runtime dependency is Pillow.

Quick start

from manga_page_splitter import split_file

# Writes page_001.png and page_002.png into ./pages
written = split_file("spread.png", "pages")
print(written)

From the command line:

manga-page-splitter spread.png -o pages

Reading order

Japanese manga is read from the right page to the left one, so by default the right half of the spread is emitted first. For comics that read left-to-right, pass right_to_left=False or --ltr:

pages = split_spread(spread, gutter=400, right_to_left=False)
manga-page-splitter spread.png --ltr

Finding the gutter

gutter is the x coordinate the spread is cut at. You can supply it yourself, but you usually do not have to: detect_gutter scans a band around the horizontal centre of the image and returns the lightest column in it. On a real scan the fold is printed with no artwork across it, so it is almost always the cleanest vertical strip near the middle.

from manga_page_splitter import detect_gutter

x = detect_gutter("spread.png")
if x is None:
    print("no clean fold found — pass an explicit gutter")
else:
    print(f"cutting at x={x}")

The search is configurable:

Parameter Default Meaning
search_ratio 0.12 Half-width of the scanned band, as a fraction of the image width
threshold 200 Grayscale value below which a pixel counts as ink
min_ink_ratio 0.02 A column is only accepted if its ink count is at most this fraction of the height

Raise min_ink_ratio for noisy scans, lower it to demand a genuinely clean fold. When nothing in the band qualifies, detect_gutter returns None and split_spread raises GutterNotFoundError rather than guessing — a wrong cut silently corrupts a whole chapter, so failing loudly is the better default. Pass gutter=<x> to force a position.

To check a folder of scans before committing to a batch:

manga-page-splitter scans/*.png --detect-only

Trimming the margins

Scans usually carry a white or grey margin, and a few millimetres of the facing page. trim=True (or --trim) crops each page to the content box, using the colour of the four corners as the background:

pages = split_spread("spread.png", trim=True, padding=4)

padding keeps a few pixels of breathing room around the artwork, which is usually what you want if the pages are headed for a reader that adds its own margins.

API

Function Purpose
detect_gutter(image, ...) Return the x coordinate of the fold, or None
split_spread(image, gutter=None, right_to_left=True, trim=False, padding=0) Return the two page images in reading order
split_result(image, ...) Same, plus the gutter and image size that were used
split_file(path, out_dir, ...) Split one file and write the pages to disk
split_many(paths, out_dir, ...) Split a batch, one sub-directory per source file
trim_borders(image, tolerance=8, padding=0) Crop the uniform border from a single page

Every function accepts either a PIL.Image.Image or a path. split_result returns a frozen SplitResult with pages, gutter, size, detected and a count property.

Command line reference

manga-page-splitter IMAGE [IMAGE ...] [-o DIR] [-g X] [--ltr] [--trim]
                    [--padding N] [--prefix STEM] [--format FMT]
                    [--quality N] [--batch] [--detect-only] [-q]

Exit codes: 0 on success, 1 for I/O or argument errors, 2 when no gutter could be found.

Batch use

# Each scan gets its own folder: pages/chapter01/page_001.png, ...
manga-page-splitter scans/*.png -o pages --batch --trim

In Python, split_many does the same and returns one list of paths per source file.

Notes and limits

  • Only two-page spreads are handled. A single page passed in will either be cut in the wrong place or rejected, depending on how much ink sits in the centre band.
  • The gutter search assumes the fold is roughly centred. Heavily cropped scans where one page takes two thirds of the width need an explicit gutter.
  • Colour profiles are preserved; nothing is re-encoded unless you ask for a lossy --format.
  • Pages are written in reading order, numbered from 001, so the file names themselves sort correctly.

Cutting a spread in two is the first step of a scanlation workflow; the harder half is the text. Mee Manga Translator takes the separated pages and translates the dialogue while keeping the original layout, which pairs well with the --trim output above.

License

MIT. See LICENSE.

Metadata

Release files for manga-page-splitter 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for manga-page-splitter 1.0.0
File Size Uploaded
manga_page_splitter-1.0.0.tar.gz 16.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for manga-page-splitter 1.0.0
File Interpreter ABI Platform
manga_page_splitter-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.8 kB

Release files / manga_page_splitter-1.0.0.tar.gz

Download URL manga_page_splitter-1.0.0.tar.gz
Size 16.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d83b88eb45247afc040a707ac545cac02acde2b34c6c40e801dd5661aded2429
BLAKE2b-256 checksum
How to use checksums
04b514084f3946e215ac15202b4c3f54c0e3f9dc3b55b1ef09fbb3d0d6dbcafe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / manga_page_splitter-1.0.0-py3-none-any.whl

Download URL manga_page_splitter-1.0.0-py3-none-any.whl
Size 11.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
75bf3e0bfa90fcb6ab3b58647831d18e9dff091ca96f267d8b8567f86047a06d
BLAKE2b-256 checksum
How to use checksums
c611f61cf331702a87a86301fd72b63e52a970264059897ba0b24b00f59a5cc3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page