nano-force-esp32-neo/tools/convert_icons.py
2025-11-15 09:07:39 +08:00

68 lines
2.2 KiB
Python

# Convert PNG/JPG icons to custom RGB565 raw format with header
# Output file format (little-endian): [uint16 width][uint16 height][pixels: width*height*2 bytes]
# Usage: python tools/convert_icons.py --src assets/icons_src --dst data/icons --size 48 48
import argparse
import os
from PIL import Image
def rgb888_to_rgb565(r, g, b):
# Swap r/b to match display byte order used in utils::rgbTo565
r, b = b, r
r5 = (r * 31) // 255
g6 = (g * 63) // 255
b5 = (b * 31) // 255
return (r5 << 11) | (g6 << 5) | b5
def convert_one(src_path, dst_path, out_w, out_h):
img = Image.open(src_path).convert('RGBA')
img = img.resize((out_w, out_h), Image.LANCZOS)
# Premultiply against black background for simple alpha handling
bg = Image.new('RGBA', (out_w, out_h), (0, 0, 0, 255))
img = Image.alpha_composite(bg, img)
# Write header + pixels
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
with open(dst_path, 'wb') as f:
f.write(bytes([out_w & 0xFF, (out_w >> 8) & 0xFF, out_h & 0xFF, (out_h >> 8) & 0xFF]))
px = img.load()
for y in range(out_h):
for x in range(out_w):
r, g, b, a = px[x, y]
c = rgb888_to_rgb565(r, g, b)
f.write(bytes([c & 0xFF, (c >> 8) & 0xFF]))
print(f"Converted: {src_path} -> {dst_path}")
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--src', default='assets/icons_src', help='Source icon folder')
parser.add_argument('--dst', default='data/icons', help='Destination folder in LittleFS data')
parser.add_argument('--size', nargs=2, type=int, default=[48, 48], help='Output icon size WxH')
args = parser.parse_args()
out_w, out_h = args.size
mapping = {
'timer': 'timer.r565',
'web': 'web.r565',
'game': 'game.r565',
}
for name, out_file in mapping.items():
src_file = os.path.join(args.src, f'{name}.png')
if not os.path.exists(src_file):
print(f"WARN: missing {src_file}, skip")
continue
dst_file = os.path.join(args.dst, out_file)
convert_one(src_file, dst_file, out_w, out_h)
print('Done. You can now upload FS: pio run -t uploadfs')
if __name__ == '__main__':
main()