Skip to content

theburke9/LVGLImage.py

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

🖼️ LVGLImage.py

A command-line tool and Python library for converting PNG images into LVGL binary (.bin) or C array (.c) image assets.

Supports LVGL v8 and LVGL v9 output via a single --lvgl-version flag.


✨ Features

  • 🎨 Converts PNG to all major LVGL color formats (RGB565, ARGB8888, indexed, alpha-only, …)
  • 📦 Optional compression: RLE or LZ4 (v9 only)
  • 🔢 Stride alignment control (--align)
  • 🔀 Pre-multiplied alpha output (--premultiply)
  • 🌫️ Dithering for RGB565 gradients (--rgb565dither)
  • 🗃️ Batch conversion of entire folders
  • 🔄 Round-trip support: .bin.png and .png.bin/.c
  • 🏷️ LVGL v8 and v9 targets via --lvgl-version

📦 Requirements

pip install pypng lz4

💡 For indexed-color quantization, install pngquant:

sudo apt install pngquant      # Debian / Ubuntu
brew install pngquant          # macOS

🚀 Quick Start

# LVGL v9 (default) — RGB565 binary
python3 LVGLImage.py --cf RGB565 --ofmt BIN image.png

# LVGL v9 — ARGB8888 C array
python3 LVGLImage.py --cf ARGB8888 --ofmt C image.png

# LVGL v8 — RGB565 C array
python3 LVGLImage.py --cf RGB565 --ofmt C --lvgl-version 8 image.png

# LVGL v8 — indexed I8 binary
python3 LVGLImage.py --cf I8 --ofmt BIN --lvgl-version 8 image.png

# Batch convert a folder (v9, LZ4 compressed)
python3 LVGLImage.py --cf RGB565 --ofmt BIN --compress LZ4 ./assets/

⚙️ Options

Option Default Description
--cf I8 Color format (see list below)
--ofmt BIN Output format: BIN, C, or PNG
--lvgl-version 9 Target LVGL version: 8 or 9
--compress NONE Compression: NONE, RLE, LZ4 (v9 only)
--align 1 Stride alignment in bytes
--background 0x000000 Background color for formats without alpha
--premultiply off Pre-multiply RGB by alpha
--rgb565dither off Dithering for RGB565 gradients
--nemagfx off NEMA-compatible I8 palette layout
-o, --output ./output Output folder
--name Override output variable/file name (single file only)
-v, --verbose off Enable debug logging

🎨 Supported Color Formats

✅ LVGL v9 and v8

Format Description v8 macro
RGB565 16-bit RGB LV_IMG_CF_TRUE_COLOR (depth=16)
RGB888 24-bit RGB LV_IMG_CF_TRUE_COLOR (depth=24)
XRGB8888 32-bit RGB (no alpha) LV_IMG_CF_TRUE_COLOR (depth=32)
ARGB8888 32-bit RGBA LV_IMG_CF_TRUE_COLOR_ALPHA (depth=32)
RGB565A8 16-bit RGB + separate alpha map LV_IMG_CF_TRUE_COLOR_ALPHA (depth=16)
I1 / I2 / I4 / I8 Indexed (palette) LV_IMG_CF_INDEXED_xBIT
A1 / A2 / A4 / A8 Alpha-only LV_IMG_CF_ALPHA_xBIT
RAW / RAW_ALPHA Raw pass-through LV_IMG_CF_RAW / LV_IMG_CF_RAW_ALPHA

⚠️ LVGL v9 only (no v8 equivalent)

Format Description
L8 8-bit grayscale
AL88 8-bit grayscale + alpha
ARGB8565 24-bit ARGB (565 color + 8-bit alpha)
RGB565_SWAPPED Big-endian RGB565
ARGB8888_PREMULTIPLIED Pre-multiplied ARGB8888

🚫 Using a v9-only format with --lvgl-version 8 raises a ParameterError.


🔢 LVGL v8 vs v9 — Key Differences

Aspect LVGL v8 LVGL v9
Struct type lv_img_dsc_t lv_image_dsc_t
CF macro prefix LV_IMG_CF_* LV_COLOR_FORMAT_*
Header size 4 bytes (bitfield) 12 bytes
stride field ❌ implicit ✅ explicit
flags field ❌ absent ✅ present
Magic byte ❌ none 0x19
Compression ❌ not supported ✅ RLE / LZ4

📐 Generated C Array — v9 Example

const lv_image_dsc_t my_image = {
  .header = {
    .magic = LV_IMAGE_HEADER_MAGIC,
    .cf = LV_COLOR_FORMAT_RGB565,
    .flags = 0,
    .w = 100,
    .h = 100,
    .stride = 200,
    .reserved_2 = 0,
  },
  .data_size = sizeof(my_image_map),
  .data = my_image_map,
  .reserved = NULL,
};

📐 Generated C Array — v8 Example

/* Generated for LVGL v8 — lv_img_dsc_t */
const lv_img_dsc_t my_image = {
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.always_zero = 0,
  .header.reserved = 0,
  .header.w = 100,
  .header.h = 100,
  .data_size = sizeof(my_image_map),
  .data = my_image_map,
};

⚠️ Known Limitations

  • Indexed formats in v8 — The palette data layout differs between v8 (ncolors × sizeof(lv_color_t) bytes, depth-dependent) and v9 (4 bytes BGRA per entry). Generated indexed images may need manual palette adjustment for v8.

  • Compression + v8 — Raises ParameterError. LVGL v8 uses a different compression mechanism incompatible with v9's RLE/LZ4 headers.

  • Reading v8 .bin filesTRUE_COLOR (cf=4) is decoded as RGB565 and TRUE_COLOR_ALPHA (cf=5) as ARGB8888 by default (ambiguous without knowing LV_COLOR_DEPTH at build time).


🐍 Python API

from LVGLImage import LVGLImage, ColorFormat, CompressMethod

# Convert PNG → LVGL v9 binary
img = LVGLImage().from_png("icon.png", cf=ColorFormat.RGB565)
img.adjust_stride(align=4)
img.to_bin("icon.bin")                        # LVGL v9 (default)
img.to_bin("icon_v8.bin", lvgl_version=8)    # LVGL v8

# Convert PNG → C array
img.to_c_array("icon.c")                      # LVGL v9
img.to_c_array("icon_v8.c", lvgl_version=8)  # LVGL v8

# Pre-multiply alpha
img = LVGLImage().from_png("icon.png", cf=ColorFormat.ARGB8888)
img.premultiply()
img.to_bin("icon_pm.bin")

# Round-trip: bin → png
img = LVGLImage().from_bin("icon.bin")
img.to_png("icon_back.png")

📄 License

See the LVGL project for licensing information.

About

LVGLImage compatible with LVGL v8 and v9

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages