Metadata-Version: 2.5
Name: lvglimg
Version: 0.0.3
Summary: Decode LVGL .bin image files (v8 + v9, NONE/RLE/LZ4/LZ4_HC) to PNG
Project-URL: Homepage, https://github.com/Junbo-Zheng/lvglimg
Project-URL: Issues, https://github.com/Junbo-Zheng/lvglimg/issues
Author-email: Junbo Zheng <3273070@qq.com>
License: Apache-2.0
License-File: LICENSE
Keywords: bin,decoder,embedded,gui,image,lvgl,png
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Requires-Python: >=3.10
Requires-Dist: lz4>=4.0
Requires-Dist: pillow>=10.0
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# lvglimg

[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue.svg)](https://www.python.org/)
[![CI](https://github.com/Junbo-Zheng/lvglimg/actions/workflows/ci.yml/badge.svg)](https://github.com/Junbo-Zheng/lvglimg/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/lvglimg.svg)](https://pypi.org/project/lvglimg/)

Decode LVGL `.bin` image files to PNG — including **v8 + v9** headers and
**NONE / RLE / LZ4 / LZ4_HC** compression.

LVGL's own `LVGLImage.py` is a one-way encoder: it can *write* compressed bins,
but `from_bin` ignores the flags field and cannot decompress them back. `lvglimg`
fills that gap, producing pixel-accurate PNGs from real device asset bins.

- **Self-contained** — depends only on Pillow + lz4. No LVGL source tree, no
  `LVGLImage.py` on disk.
- **All v9 color formats** — L8, indexed (I1/2/4/8), alpha-only (A1/2/4/8),
  RGB565, RGB888, ARGB8888, XRGB8888, ARGB8565, RGB565A8.
- **v8 true-color** — `TRUE_COLOR` (cf=4, RGB565 at the display's native depth) / `TRUE_COLOR_ALPHA` (cf=5, BGRA).
- **CLI + library** — use it on the command line or import the decoder.

## Install

```bash
pip install lvglimg
```

## CLI

```bash
# single file → sibling .png
lvglimg image.bin

# explicit output path
lvglimg image.bin out.png

# batch a directory (recursive) → out/<same subdirs>/*.png
lvglimg assets/ out/
# default: a sibling '<input>_preview/' dir next to the input
lvglimg assets/       # → assets_preview/ (sibling of assets/)
# finds assets/*.bin AND assets/**/<sub>/*.bin; mirrors the subdir layout
# in the output dir (avoids name collisions across folders)
# viewable images in the tree (.jpg/.jpeg/.png/.gif/.bmp/.webp) are copied
# to the output as-is — no decoding, the preview dir holds the full asset set
```

```
$ lvglimg --version
lvglimg 0.0.3
```

## Library

```python
from lvglimg.decoder import decode, decode_file

# from bytes
img = decode(bin_bytes)
img.save("out.png")

# from a file path
img = decode_file("image.bin")
```

`decode()` returns a `PIL.Image.Image` (mode `RGBA`, `RGB`, or `L` depending on
the source format), so you can inspect, transform, or re-encode it however you
like.

## How it works

The LVGL v9 on-disk layout is a 12-byte header followed by a body that may be a
compress block:

```
header: magic(0x19) cf flags w h stride reserved
body  : [method u32][clen u32][raw_len u32][payload]   # iff flags & 0x08
```

`lvglimg` reads the `flags` field to detect compression (the same bit LVGL sets
when encoding), decompresses RLE / LZ4 / LZ4_HC, then unpacks pixels to RGBA
using the same channel layout and `bit_extend` upscaling LVGL renders on-device —
so output matches the display. v8 files (no magic byte) are dispatched to the
4-byte bitfield header path.

> **Note** — v8 support covers `TRUE_COLOR` (cf=4, RGB565 at the display's
> native depth) and `TRUE_COLOR_ALPHA` (cf=5, 4 B/px BGRA), the layouts real
> device asset bins use. Other legacy v8 formats raise a clear error rather than
> silently producing garbage.

## Development

```bash
pip install -e ".[dev]"
pytest            # 21 tests, runs against src/ with no install
ruff check src tests main.py
mypy
./main.py image.bin   # run from source, no install
```

## License

This project is licensed under the Apache License, Version 2.0. See
[LICENSE](LICENSE) or <https://www.apache.org/licenses/LICENSE-2.0> for the
full text.
