AI-powered image upscaler accelerated on Apple Metal (MPS).
metalgrow runs super-resolution on Apple Silicon GPUs through PyTorch's MPS
backend, with graceful fallbacks to CUDA and CPU. It runs learned backbones
(Real-ESRGAN, SwinIR) behind one stable API, with a bicubic baseline that
needs no weights, and has print-oriented tools for scans and line art:
metadata preservation, descreening, ink mode and 1-bit masters.
- π Apple Metal first β PyTorch MPS backend, zero config on Apple Silicon
- π Portable β automatic fallback to CUDA / CPU when MPS isn't available
- π§© Pluggable backbones β bicubic, Real-ESRGAN (x2/x4, anime x4), SwinIR (x2/x4)
- π§± Tiled inference β process arbitrarily large images with feathered overlap blending
- π Batch mode β upscale whole directories or globs with a progress bar
- π¨οΈ Print-aware β
--preserve-metadatakeeps grayscale mode, the ICC profile, and a rescaled DPI tag intact - ποΈ Ink mode β
--alpha-mode inkupscales ink-on-transparent line art through its coverage, so the SR model sees the drawing instead of a flat colour plane - β¬ 1-bit masters β
metalgrow bitmapwrites Group 4 line-art TIFFs at 1200 ppi (resampled before thresholding, so edges stay smooth) - π° Descreen β
--descreenremoves halftone screens (moirΓ©) from scanned print before upscaling, leaving text and linework untouched - π¦ Model registry β
metalgrow modelsmanages cached weights with sha256 verification - π§ͺ Tested β pytest suite covering the CPU baseline, tiling, batch mode, and registry
- Python 3.11+
- macOS with Apple Silicon for MPS acceleration (optional β CPU/CUDA also work)
From PyPI:
pip install metalgrowFrom source:
git clone https://github.com/joaodotwork/metalgrow.git
cd metalgrow
uv venv && source .venv/bin/activate
uv pip install -e .Or with plain pip:
python -m venv .venv && source .venv/bin/activate
pip install -e .Single file:
metalgrow info
metalgrow upscale input.jpg out.png --scale 2
metalgrow upscale input.jpg out.png --scale 4 --device mps --backbone realesrgan-x4Whole directory or glob (writes to a target directory, mirroring filenames):
metalgrow upscale ./photos ./photos-upscaled --scale 2 --backbone realesrgan-x2
metalgrow upscale "./photos/*.png" ./out --scale 2 --skip-existing| Flag | Default | Description |
|---|---|---|
--scale, -s |
2.0 |
Upscale factor (1.01β8.0); learned backbones run their native factor then resample to this exact target |
--device, -d |
auto |
auto | mps | cuda | cpu |
--backbone, -b |
bicubic |
bicubic | realesrgan-x{2,4} | realesrgan-anime-x4 | swinir-x{2,4} |
--dtype |
fp32 |
fp32 | fp16 (fp16 is MPS-only and noisier) |
--tile |
backbone hint | Tile size in input px for tiled inference (0 disables) |
--tile-pad |
backbone hint | Context padding per tile edge (covers backbone receptive field) |
--skip-existing |
off | Batch mode: skip outputs that already exist |
--preserve-metadata, -p |
off | Keep grayscale mode, embedded ICC profile, and a rescaled DPI tag (for print / preflight workflows) |
--workers, -j |
4 |
Batch mode: parallel I/O workers (inference stays serial) |
--descreen |
off | Remove halftone screens (moirΓ©) from scanned print before the backbone runs |
--descreen-strength |
1.0 |
Notch depth, 0β1 |
--alpha-mode |
separate |
ink upscales single-colour line art through its alpha (and knocks out paper); auto detects it |
--dpi |
off | Write this DPI tag instead of the source's rescaled one |
Newspaper and magazine scans carry the printer's halftone dot screen, which
SR backbones sharpen into moirΓ©. --descreen removes it first. Detection is
local and only touches regions that actually contain a dot lattice β type,
rules and blank paper come back unchanged. See
ADR 0002 for how it works.
# descreen + upscale, keeping DPI / ICC / grayscale for print
metalgrow upscale scan.tif out.tif --descreen -p --scale 1.5 -b swinir-x2
# descreen only, no resize
metalgrow descreen scan.tif clean.tif -p# ink-on-transparent drawings: 4x, coverage-aware, tagged 300 dpi
metalgrow upscale ./drawings ./png -s 4 -b realesrgan-x4 --alpha-mode ink -p --dpi 300
# then 1-bit Group 4 masters at 1200 ppi, same physical size
metalgrow bitmap ./png ./tiffSee ADR 0003 for how ink mode works.
metalgrow models list
metalgrow models download realesrgan-x4
metalgrow models rm realesrgan-x4Weights cache to ~/.cache/metalgrow/ by default; override with the
METALGROW_CACHE_DIR env var. Every download is sha256-verified.
See docs/models.md for a quality / speed / memory
comparison (with benchmark numbers) and guidance on which backbone to pick,
or docs/usage.md for the full CLI / library reference.
from PIL import Image
from metalgrow import Upscaler
upscaler = Upscaler(backbone="realesrgan-x2", device="auto") # auto | mps | cuda | cpu
result = upscaler.upscale(
Image.open("input.jpg").convert("RGB"),
scale=2.0,
tile=256, # optional β backbone has sensible defaults
tile_pad=16,
)
result.save("out.png")src/metalgrow/
device.py # device auto-selection (MPS β CUDA β CPU)
upscaler.py # Upscaler class + tiled inference with overlap blending
batch.py # directory / glob batch mode
descreen.py # local FFT notch filter for halftone screens
metadata.py # ICC / DPI / grayscale capture + reapply
ink.py # single-ink detection + coverage matte (ink mode)
bitmap.py # 1-bit line-art masters
weights.py # weight registry, sha256 verification, cache management
cli.py # typer CLI (upscale, descreen, bitmap, info, models)
backbones/ # bicubic, realesrgan, swinir; plugin registry
tests/
docs/
usage.md # CLI recipes, library API, env vars, pitfalls
models.md # backbone comparison, benchmark snapshot, tiling
benchmarks.md # full (device Γ backbone Γ scale) tables
architecture.md # module layout, data flow, extension points
adr/ # design decisions (backbone dependency, descreen, ink mode)
- Integrate a learned SR backbone (Real-ESRGAN default)
- Tiled inference for large images
- Batch / directory mode
- Model registry + weight download
- Second backbone family (SwinIR)
- GitHub Actions CI (lint + test on macOS + Linux)
- Benchmarks: MPS vs CPU (CUDA pending GPU runner)
- PyPI releases (trusted publishing)
- Print workflows: metadata preservation, descreen, ink mode, 1-bit masters
- CUDA benchmarks
- Integration tests against real weights
Issues and PRs are welcome. Please run ruff and pytest before opening a PR.
MIT β see LICENSE.
Made with π© on Apple Silicon.