mirror of
https://github.com/apache/nuttx.git
synced 2025-05-08 22:32:04 +08:00

Adds Kconfig-selected splashscreen options used when the driver is first registered * Includes a new Python script in ./tools to create RLE bitmap files * Includes default NS logo btimaps in 320x320, 160x160 and 80x80 resolutions along with their PNG files Signed-off-by: Tim Hardisty timh@jti.uk.com>
257 lines
8.8 KiB
Python
Executable File
257 lines
8.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# tools/splashscreen_converter.py
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership. The
|
|
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance with the
|
|
# License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
|
|
"""This script converts from any image type supported by
|
|
Python imaging library to the RLE-encoded format used by
|
|
the framebuffer splashscreen feature.
|
|
"""
|
|
|
|
from PIL import Image
|
|
|
|
|
|
def get_palette(img, maxcolors=256):
|
|
"""Returns a list of colours. If there are too many colours in the image,
|
|
the least used are removed.
|
|
"""
|
|
|
|
colors = img.getcolors(65536)
|
|
colors.sort(key=lambda c: -c[0])
|
|
return [c[1] for c in colors[:maxcolors]]
|
|
|
|
|
|
def write_palette(outfile, palette, type):
|
|
"""Write the palette to the output file."""
|
|
|
|
if type == "ARGB":
|
|
outfile.write("#ifdef CONFIG_VIDEO_FB_SPLASHSCREEN_BPP32\n")
|
|
outfile.write("static const fb_pixel_t palette[] =\n")
|
|
outfile.write("{\n")
|
|
|
|
for i in range(0, len(palette), 4):
|
|
for r, g, b, a in palette[i : i + 4]:
|
|
outfile.write(" MKRGB(%d, %d, %d, %d),\n" % (a, r, g, b))
|
|
|
|
outfile.write("};\n")
|
|
outfile.write("#endif\n\n")
|
|
|
|
elif type == "RGB":
|
|
outfile.write("#if defined(CONFIG_VIDEO_FB_SPLASHSCREEN_BPP24) || \\\n")
|
|
outfile.write(" defined(CONFIG_VIDEO_FB_SPLASHSCREEN_BPP16) || \\\n")
|
|
outfile.write(" defined(CONFIG_VIDEO_FB_SPLASHSCREEN_BPP8)\n")
|
|
outfile.write("static const fb_pixel_t palette[] =\n")
|
|
outfile.write("{\n")
|
|
|
|
for i in range(0, len(palette), 4):
|
|
for r, g, b in palette[i : i + 4]:
|
|
outfile.write(" MKRGB(%d, %d, %d),\n" % (r, g, b))
|
|
|
|
outfile.write("};\n")
|
|
outfile.write("#endif\n\n")
|
|
|
|
else:
|
|
outfile.write("#if defined(CONFIG_VIDEO_FB_SPLASHSCREEN_GREY) || \\\n")
|
|
outfile.write(" defined(CONFIG_VIDEO_FB_SPLASHSCREEN_MONO)\n")
|
|
outfile.write("static const fb_pixel_t palette[] =\n{\n};\n")
|
|
outfile.write("#endif\n\n")
|
|
|
|
|
|
def quantize(color, palette):
|
|
"""Return the color index to closest match in the palette."""
|
|
try:
|
|
return palette.index(color)
|
|
except ValueError:
|
|
# No exact match, search for the closest
|
|
def distance(color2):
|
|
return sum([(a - b) ** 2 for a, b in zip(color, color2)])
|
|
|
|
return palette.index(min(palette, key=distance))
|
|
|
|
|
|
def encode_row(img, palette, y, type):
|
|
"""RLE-encode one row of image data."""
|
|
|
|
color = None
|
|
entries = []
|
|
repeats = 0
|
|
|
|
for x in range(0, img.width):
|
|
if type == "BPP32" or type == "BPP24" or type == "BPP16":
|
|
c = quantize(img.getpixel((x, y)), palette)
|
|
else:
|
|
c = img.getpixel((x, y))
|
|
if c == color and repeats < 255:
|
|
repeats += 1
|
|
else:
|
|
if color is not None:
|
|
entries.append((repeats, color))
|
|
|
|
repeats = 1
|
|
color = c
|
|
|
|
if color is not None:
|
|
entries.append((repeats, color))
|
|
|
|
return entries
|
|
|
|
|
|
def write_image(outfile, img, palette, suffix):
|
|
"""Write the image contents to the output file."""
|
|
|
|
if suffix == "BPP24" or suffix == "BPP16":
|
|
outfile.write("#if defined(CONFIG_VIDEO_FB_SPLASHSCREEN_BPP24) || \\")
|
|
outfile.write("\n defined(CONFIG_VIDEO_FB_SPLASHSCREEN_BPP16)\n")
|
|
else:
|
|
outfile.write("#ifdef CONFIG_VIDEO_FB_SPLASHSCREEN_%s\n" % suffix)
|
|
outfile.write("static const struct splscr_bitmap_s bitmap[] =\n")
|
|
outfile.write("{")
|
|
for y in range(0, img.height):
|
|
entries = encode_row(img, palette, y, suffix)
|
|
for r, c in entries:
|
|
outfile.write("\n")
|
|
row = " {%d, %d}," % (r, c)
|
|
outfile.write(row)
|
|
|
|
outfile.write(("/* End of row %3d */" % (y + 1)).rjust(78 - len(row), " "))
|
|
|
|
outfile.write("\n};\n")
|
|
outfile.write("#endif /* CONFIG_VIDEO_FB_SPLASHSCREEN_%s */\n\n" % suffix)
|
|
|
|
|
|
def write_descriptor(outfile, name):
|
|
outfile.write("const struct palette_bitmap_s g_%s =\n" % name)
|
|
outfile.write("{\n")
|
|
lw = len(str(img.width))
|
|
lh = len(str(img.height))
|
|
outfile.write(" %d," % img.width)
|
|
outfile.write(
|
|
("/* width in pixels */\n").rjust(
|
|
76 - lw, " "
|
|
)
|
|
)
|
|
outfile.write(" %d," % img.height)
|
|
outfile.write(
|
|
("/* height in pixels */\n").rjust(
|
|
76 - lh, " "
|
|
)
|
|
)
|
|
outfile.write(
|
|
(
|
|
" palette, /* Colour palette */\n"
|
|
).rjust(76, " ")
|
|
)
|
|
outfile.write(
|
|
(
|
|
" bitmap, /* Pointer to the start of the RLE data */\n"
|
|
).rjust(76, " ")
|
|
)
|
|
outfile.write("};\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import os.path
|
|
import sys
|
|
|
|
if len(sys.argv) < 3:
|
|
print("Usage: splashscreen_converter.py image.xxx output_directory out.c")
|
|
print(
|
|
"\t- image.xxx\t\tis the image file (e.g. logo.png) in a format supported by PIL"
|
|
)
|
|
print("\t- output_directory\tis where the output file will be saved.")
|
|
print("\t- out.c\t\t\tis the name of the output file.")
|
|
print("\t\t\t\t- If out.c is not specified it will default to fb_splash.c,")
|
|
print("\t\t\t\t which is the name required for custom splashscreens")
|
|
sys.exit(1)
|
|
elif len(sys.argv) == 3:
|
|
path = sys.argv[2]
|
|
filename = "fb_splash.c"
|
|
else:
|
|
path = os.path.relpath(sys.argv[2])
|
|
filename = sys.argv[3]
|
|
img = Image.open(sys.argv[1]).convert("RGBA")
|
|
file = os.path.realpath(path + "/" + filename)
|
|
outfile = open(file, "w")
|
|
palette_argb = get_palette(img)
|
|
palette_rgb = get_palette(img.convert("RGB"))
|
|
outfile.write(
|
|
"""/****************************************************************************
|
|
* %(file)s
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* Script-generated framebuffer splashscreen bitmap file.
|
|
* Generated from %(src)s
|
|
* by splashscreen_converter.py
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/video/fb.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
"""
|
|
% {"file": path + "/" + filename, "src": os.path.relpath(sys.argv[1])}
|
|
)
|
|
|
|
name = "splscr"
|
|
|
|
write_palette(outfile, palette_argb, "ARGB")
|
|
write_palette(outfile, palette_rgb, "RGB")
|
|
write_palette(outfile, None, None)
|
|
write_image(outfile, img, palette_argb, "BPP32")
|
|
write_image(outfile, img.convert("RGB"), palette_rgb, "BPP24")
|
|
write_image(outfile, img.convert("L"), None, "GREY")
|
|
write_image(outfile, img.convert("1"), None, "MONO")
|
|
write_descriptor(outfile, name)
|
|
outfile.write(
|
|
"""
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
"""
|
|
)
|
|
print("Created %s from %s" % (file, sys.argv[1]))
|