Metadata-Version: 2.4
Name: sextants
Version: 0.2.0
Summary: Convert raster images to teletext / viewdata block-mosaic graphics via an optimal per-row dynamic-programming solver
Keywords: teletext,viewdata,videotex,mode7,saa5050,mosaic,sextants,bbc-micro
Author: Robert Smallshire
Author-email: Robert Smallshire <robert@smallshire.org.uk>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Graphics
Requires-Dist: numpy>=2.0
Requires-Dist: pillow>=10.0
Requires-Dist: click>=8.1
Requires-Dist: tqdm>=4.66
Requires-Dist: numba>=0.60 ; extra == 'fast'
Requires-Python: >=3.11
Project-URL: Homepage, https://github.com/rob-smallshire/sextants
Provides-Extra: fast
Description-Content-Type: text/markdown

# sextants

Convert raster images (JPEG, PNG, …) to **teletext / viewdata block-mosaic
graphics** — the 40×25 character page rendered by the SAA5050 and its relatives
(BBC Micro Mode 7, Ceefax/Oracle teletext, Prestel viewdata, CEPT videotex).

The name comes from Unicode's own term for the 2×3 sub-pixel mosaic cell these
displays draw — the *sextants* of the "Symbols for Legacy Computing" block
(U+1FB00…). Each cell is six sub-pixels sharing a two-colour sub-palette, and a
colour change is an in-band control code that costs a whole cell. Encoding an
image well is therefore a constrained optimisation, not a simple resample —
which is what this library does, row by row, with an optimal dynamic-programming
solver.

## Attribution

**sextants is a derivative work of [image2mode7 / image2teletext] by
Kieran Connell.** The conversion algorithm at its heart — the per-row
dynamic-programming solver, the sub-pixel error model, and the preprocessing
pipeline — is Kieran's work, used here under its MIT licence. This project
repackages that code as an installable, `src`-layout Python library with a split
module structure, a Click CLI, and a test suite, and is the basis for further
development. Please see [`LICENSE`](LICENSE) for the full notice.

[image2mode7 / image2teletext]: https://github.com/kieranhj/image2mode7

## Install

```sh
uv add sextants           # or: pip install sextants
```

Optional numba acceleration for the DP solver:

```sh
uv add "sextants[fast]"
```

## Library usage

```python
from PIL import Image
from sextants import convert, render_preview

page = convert(Image.open("photo.jpg"), preset="photo")  # 1000-byte teletext page
Path("photo.bin").write_bytes(page)                       # load at &7C00 on a BBC Micro

render_preview(page).save("preview.png")                  # what it looks like on-screen
```

`convert(img, preset=None, **overrides)` is the preset-aware entry point;
`convert_image(...)` exposes every knob directly. Presets bundle sensible
preprocessing options for common sources:

| Preset | For |
| --- | --- |
| `photo` | Portraits, landscapes, general photos |
| `clean` | Safe universal default; light denoise + snap for unknown/BBS images |
| `smooth` | Noisy JPEGs, soft gradients |
| `vivid` / `graphic` / `flat` | Punchy colour, logos/cartoons, bold posterised |
| `retro` / `art` | Authentic Ceefax look, hand-crafted teletext-art look |
| `level1` | Source is already a Mode 7 / Level 1 teletext image |
| `dark` / `tv` / `crt` | Exposure lift; LCD (PAR 1.2); CRT (PAR 1.22) |

## Command line

```sh
sextants photo.jpg -o photo.bin --preset photo
sextants photo.jpg --preview preview.png --url    # also print an edit.tf URL
sextants --help
```

The output is a raw 1000-byte page (25 rows × 40 bytes of teletext character
codes). It loads directly at `&7C00` on a BBC Micro, or paste the `--url` into
[edit.tf](http://edit.tf).

## Development

```sh
uv sync            # create the environment
uv run pytest      # run the test suite
```

## Licence

MIT — see [`LICENSE`](LICENSE). Original algorithm © 2020 Kieran Connell;
packaging and modifications © 2026 Robert Smallshire.
