A full-screen, menu-driven terminal scanner for the Brother MFC-L5850DW
on macOS. You run it in Terminal and drive a numbered menu (BIOS / green-screen
style); there are no flags to memorize. It wraps scanline, which reaches the
scanner through the same macOS service Image Capture uses, so talking to the
scanner over Wi-Fi is handled by the OS rather than by us.
Built for a bulk job: scanning a large archive of mixed single- and multi-page documents into tidy PDFs.
- Scan documents (batch loop): each feeder load becomes one multipage
PDF. Load a document, tap ENTER, it saves
label_001.pdf, then it is ready for the next load. Tap, load, tap. This is the flow for multi-page records. - Split pages: feed a pile and get one PDF per sheet (
label_pNNN.pdf). This is the flow for a stack of single-page items. - Flatbed: a single sheet on the glass.
- Settings: two-sided (duplex), resolution, color vs black and white, blank-page dropping and its sensitivity, and the save folder.
Single-pass duplex scans both sides of every sheet, so single-sided pages come out with a dead blank back. With blank-dropping on (the default), those empty backs are removed automatically. It is deliberately conservative: it only drops pages that are essentially free of ink, so a sparse but real page (a short invoice, a signature page) is always kept. Pages are never re-encoded and a page with real content is never deleted. The tool reports which page numbers it dropped after each scan.
The sensitivity is a percent-of-ink threshold (default 0.15). Truly empty backs measure near 0.00 percent; real pages measure roughly 0.3 percent and up. Raise the threshold to drop more aggressively, lower it to keep more.
In Scan documents, each feeder load is named YYYYMMDD-n automatically
(for example 20260716-1, 20260716-2); there is no name to type. The next
name is shown before you scan and the saved name after. Numbering continues past
any file already saved that day, so a second batch on the same day never
overwrites the first.
Verified on the real scanner, end to end:
scanlineinstalled and reaching the L5850DW (scanline -listshows it).- All
scanlineflags used are confirmed againstscanline -help. - Flatbed and duplex feeder scans produce correct, correctly-ordered PDFs.
- A full Scan documents batch run with blank-drop on was verified page by page: it dropped the empty duplex backs, kept every page with content (including a sparse invoice and both sides of a genuinely double-sided document), and produced a correct multipage PDF. Ready for the bulk job.
- macOS with Python 3 (already present on current macOS). Standard library only.
- scanline: download the signed, notarized installer from
https://github.com/klep/scanline and install it (it places a
scanlinebinary in/usr/local/bin). - poppler:
brew install poppler. Providespdfseparate,pdfunite, andpdftoppm, used to split, recombine, and blank-probe pages without re-encoding them. - macOS
sips(built in), used only for the tiny blank-probe images.
Note on the SANE / scanimage backend: it is not a working fallback on this
machine. The Homebrew build of sane-backends has no eSCL backend, so scanimage
cannot reach a Wi-Fi Brother, and sane-airscan is not in Homebrew. scanline
is the backend here.
The scanner must appear in Apple's Image Capture app first; that is the quick proof macOS can drive it. AirPrint working does not prove scanning works; scanning is a separate service (AirScan / eSCL).
python3 scan.py # opens the full-screen menu
python3 scan.py --dry-run # prints the commands it would run, scans nothing--dry-run walks the menus and prints the exact commands each option would run,
with no scanner and no backend needed.
scan.pyis the whole tool: the screen UI, settings, and the scan pipeline.- Settings persist to
~/.config/scanner-tui/config.json, so you answer the prompts once, not every time. - Scans are saved under
~/Documents/Scans/<date>/. - Each scan runs
scanlineto a temporary native PDF (its page ordering is correct and proven). If nothing needs filtering, that PDF is moved into place as-is. Otherwise it is split per page withpdfseparate, each page is probed for blankness, and the keepers are recombined withpdfunite(multipage) or saved one per page. No page images are re-encoded.
Nothing on a plain sheet marks where one document ends and the next begins, so a mixed pile cannot be auto-split into per-document PDFs. Two workable approaches:
- Sort into a "single-page" pile and a "multi-page" pile. Run the singles through Split pages; run each multi-page document through Scan documents, one document per feeder load.
- Feed each document as its own load in the Scan documents batch loop. The act of loading one document at a time is what marks the boundary.