Metadata-Version: 2.4
Name: termframe
Version: 0.1.0
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Multimedia :: Graphics
Requires-Dist: av>=11
Requires-Dist: numpy>=1.21
License-File: LICENSE
Summary: Convert video/image frames to ASCII art (pixel pipeline extracted from tplay). FFmpeg-free; decode with PyAV.
Keywords: ascii-art,terminal,video,ascii
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Repository, https://github.com/maxcurzi/tplay

# termframe

termframe turns video and images into ASCII art in the terminal, with color and
half-block modes. It's a Python library with a Rust core, and it doesn't require
FFmpeg to be installed on your system.

The Rust core does the pixel-to-ASCII conversion (this part is adapted from
[tplay](https://github.com/maxcurzi/tplay), built with [PyO3](https://pyo3.rs)
and [maturin](https://maturin.rs)). Video decoding happens in Python through
[PyAV](https://pyav.org), which bundles FFmpeg inside its own wheels. So the
whole thing installs with pip, and you don't have to install system libraries or
match FFmpeg versions.

## Install

```bash
pip install termframe
```

This also pulls in `av` (PyAV) and `numpy`, both as prebuilt wheels, so there's
no Rust toolchain or FFmpeg install involved.

## Quick start

`AsciiVideo` owns the decode loop, so you iterate over it to get frames:

```python
from termframe import AsciiVideo

video = AsciiVideo("song.mp4", out_width=100, out_height=40,
                   charset="halfblock", pad=True, loop=True)

for frame in video:                       # runs forever while loop=True
    print("\x1b[H" + frame.to_ansi())     # draw the video area
    print("  now playing: My Song, My Artist")
```

It opens the file, decodes, loops, and seeks for you. Draw whatever you want
around each frame. There's a paced player in
[`examples/demo.py`](examples/demo.py).

## `AsciiVideo`

```python
AsciiVideo(path, *, out_width=80, out_height=24, charset="chars3",
           half_block=None, preserve_aspect_ratio=True, char_aspect_ratio=2.0,
           pad=False, smooth=False, loop=False)
```

- Iterable, yields `AsciiFrame` (runs forever when `loop=True`).
- `.fps`, `.dimensions`, `.duration_secs` for source metadata.
- `.seek(seconds)` for an absolute seek (applies on the next frame).
- `.set_size(w, h)` to change the target grid, for example on a terminal resize.
- `.close()`, and it works as a context manager (`with AsciiVideo(...) as v:`).

`path` can be anything FFmpeg opens: local files, HLS/RTSP, or http(s) streams.

## `AsciiFrame`

- `.text`: raw grid characters, row-major, no newlines (`len == width*height`)
- `.width`, `.height`: grid shape, so you can re-slice or composite it yourself
- `.color`: per-cell RGB `bytes` (3 per cell normally, 6 per cell in half-block mode)
- `.half_block`: whether half-block mode was used
- `.to_plain()`: grayscale text with `\n` between rows
- `.to_ansi()`: a truecolor string you can print directly

Charsets: `chars1`, `chars2`, `chars3` (default), `halfblock` (highest fidelity,
2 pixels per cell using foreground and background color), `solid`, `dotted`,
`gradient`, `blackwhite`, `bw_dotted`, `braille`.

Sizing: by default the frame is fitted inside `out_width` by `out_height` while
keeping its aspect ratio (using `char_aspect_ratio`, around 2.0 for typical
terminal cells). Set `pad=True` to center-pad it to exactly that grid if you
want a stable layout, or `preserve_aspect_ratio=False` to stretch it.

## Low-level API

If you decode frames somewhere else (OpenCV, Pillow, a capture device), skip
`AsciiVideo` and call the converter directly:

```python
import termframe

# raw RGB24 bytes: width*height*3, row-major
frame = termframe.frame_to_ascii(rgb_bytes, width=w, height=h,
                                 out_width=100, out_height=40, charset="halfblock")

# or a single image file (PNG/JPEG)
frame = termframe.image_to_ascii("cover.png", out_width=80, out_height=24)
```

## Building from source

You only need the Rust toolchain for this, not FFmpeg:

```bash
pip install maturin
maturin develop --features python     # into the active venv
# or a distributable wheel:
maturin build --release --features python
```

## Using it from Rust

The core is also a regular Rust crate. See `src/converter.rs` for
`rgb_frame_to_ascii`, `image_to_ascii`, `AsciiConfig`, and `AsciiFrame`.

