Skip to content

Commit

Permalink
Improve icon2glyph syntax and output to avoid some errors
Browse files Browse the repository at this point in the history
  • Loading branch information
nroggeman-ledger committed May 31, 2024
1 parent 3fae7ab commit 3575e2d
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 89 deletions.
14 changes: 11 additions & 3 deletions Makefile.app_params
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
# Command to print ICONNAME hexadecimal bitmap on stdout according to the
# hardware target.
ifneq ($(TARGET),nanos)
ICON_HEX_FILE=icon.hex
#inverse B&W for non Stax
ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_NANOS2))
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --reverse --hexbitmaponly $(ICONNAME)
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --reverse --hexbitmap $(ICON_HEX_FILE) $(ICONNAME)
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --hexbitmaponly $(ICONNAME)
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --hexbitmap $(ICON_HEX_FILE) $(ICONNAME)
endif
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/icon3.py --hexbitmaponly $(ICONNAME)
Expand Down Expand Up @@ -76,9 +77,16 @@ endif
# Consider only one path_slip21 can be added, whereas LedgerBlue seems to
# support multiple, but has the path can hold a " " in it, it mess with the
# foreach, so we choose to restrict to only one path_slip21.

APP_INSTALL_PARAMS = --appName $(APPNAME)
APP_INSTALL_PARAMS += --appVersion $(APPVERSION)
APP_INSTALL_PARAMS += `ICONHEX=\`$(ICONHEX_CMD) 2>/dev/null\` ; [ ! -z "$$ICONHEX" ] && echo "--icon $$ICONHEX"`
ifneq ($(TARGET),nanos)
# icon2glyph outputs its result in a file that needs to be deleted after usage
ICONHEX := $(shell $(ICONHEX_CMD) && cat $(ICON_HEX_FILE) && rm -f $(ICON_HEX_FILE))
else
ICONHEX := $(shell $(ICONHEX_CMD))
endif
APP_INSTALL_PARAMS += --icon $(ICONHEX)
APP_INSTALL_PARAMS += $(foreach curve, $(CURVE_APP_LOAD_PARAMS), --curve $(curve))
APP_INSTALL_PARAMS += $(foreach path, $(PATH_APP_LOAD_PARAMS), --path $(path))
ifneq ($(PATH_SLIP21_APP_LOAD_PARAMS),)
Expand Down
7 changes: 6 additions & 1 deletion Makefile.glyphs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ ifneq (,$(wildcard $(ICONNAME)))
GLYPH_FILES += $(ICONNAME)
endif
ICON_SCRIPT = $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py
GENERATE_GLYPHS_CMD = python3 $(ICON_SCRIPT) $(GLYPH_OPT) --glyphcfile $(GLYPH_FILES)
else # USE_NBGL
Expand All @@ -70,15 +69,21 @@ ICON_SCRIPT = $(BOLOS_SDK)/icon3.py
GENERATE_GLYPHS_CMD = python3 $(ICON_SCRIPT) --factorize --glyphcfile $(GLYPH_FILES)
endif# USE_NBGL
.DELETE_ON_ERROR:
$(GLYPH_DESTH): $(GLYPH_FILES) $(ICON_SCRIPT)
$(L)echo "[GLYPH] Compiling..."
$(L)-mkdir -p $(GLYPH_SRC_DIR)
ifneq ($(USE_NBGL),0)
$(L)python3 $(ICON_SCRIPT) $(GLYPH_OPT) --glyphcheader $(GLYPH_DESTH) --glyphcfile $(GLYPH_DESTC) $(GLYPH_FILES)
else
$(L)rm -f $(GLYPH_DESTC) $(GLYPH_DESTH)
@# Use temporary files to prevent issues when build is interrupted
$(L)python3 $(ICON_SCRIPT) $(GLYPH_OPT) --glyphcheader $(GLYPH_FILES) > $(GLYPH_DESTH)_tmp
$(L)$(GENERATE_GLYPHS_CMD) > $(GLYPH_DESTC)_tmp
$(L)mv $(GLYPH_DESTC)_tmp $(GLYPH_DESTC)
$(L)mv $(GLYPH_DESTH)_tmp $(GLYPH_DESTH)
endif
#add dependency for generation
$(GLYPH_DESTC): $(GLYPH_DESTH)
172 changes: 87 additions & 85 deletions lib_nbgl/tools/icon2glyph.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,99 +252,83 @@ def compute_regular_icon_data(no_comp: bool, im: Image, bpp, reverse) -> Tuple[b
return is_file, image_data

# glyphs.c/.h chunk files generators
def create_source_files(source_filename: str, header_filename: str):
source_file = open(source_filename, 'w')
source_file.write('/* Automatically generated by icon2glyph.py */\n\n')
source_file.write('#include "{0}"\n\n'.format(os.path.basename(header_filename)))

header_file = open(header_filename, 'w')
header_file.write('/* Automatically generated by icon2glyph.py */\n\n')
header_file.write("#pragma once\n\n")
header_file.write('#include "app_config.h"\n')
header_file.write('#include "nbgl_types.h"\n')
header_file.write('\n')

def print_glyphfile_top(add_include: bool, apps: bool):
print("#include \"app_config.h\"")
if add_include:
if apps:
print("#include \"apps_glyphs.h\"")
else:
print("#include \"glyphs.h\"")
print(
"""\
#ifdef HAVE_NBGL
#include \"nbgl_types.h\"
#else
#include <stdint.h>
#endif
""")


def print_glyphcfile_data(image_name, bpp, image_data):
print("uint8_t const C_{0}_bitmap[] = {{".format(image_name))
for i in range(0, len(image_data), 16):
print(" " + ", ".join("0x{0:02x}".format(c)
for c in image_data[i:i+16]) + ",")
print("};")
print("""#ifdef HAVE_NBGL
const nbgl_icon_details_t C_{0} = {{ GLYPH_{0}_WIDTH, GLYPH_{0}_HEIGHT, NBGL_BPP_{1}, GLYPH_{0}_ISFILE, C_{0}_bitmap }};
#endif // HAVE_NBGL
""".format(image_name, bpp))
return source_file, header_file


def print_glyphcheader_data(image_name, bpp, width, height, is_file, image_data):
def write_image_source_data(source_file, image_name, bpp, width, height, is_file, image_data):
if is_file:
is_file = 'true'
else:
is_file = 'false'
source_file.write('uint8_t const C_{0}_bitmap[] = {{\n'.format(image_name))
for i in range(0, len(image_data), 16):
source_file.write(" " + ", ".join("0x{0:02x}".format(c)
for c in image_data[i:i+16]) + ",\n")
source_file.write('};\n')
source_file.write(f'const nbgl_icon_details_t C_{image_name} = {{ {width}, {height}, NBGL_BPP_{bpp}, {is_file}, C_{image_name}_bitmap }};\n\n')

print("""#ifndef GLYPH_{0}_BPP
#define GLYPH_{0}_WIDTH {1}
#define GLYPH_{0}_HEIGHT {2}
#define GLYPH_{0}_ISFILE {3}
#define GLYPH_{0}_BPP {4}""".format(image_name, width, height, is_file, bpp))
print(" extern uint8_t const C_{0}_bitmap[{1:d}];".format(

def write_image_header_data(header_file, image_name, image_data):
header_file.write("extern uint8_t const C_{0}_bitmap[{1:d}];\n".format(
image_name, len(image_data)))
print(""" #ifdef HAVE_NBGL
extern const nbgl_icon_details_t C_{0};
#endif // HAVE_NBGL
#endif // GLYPH_{0}_BPP
""".format(image_name))
header_file.write("extern const nbgl_icon_details_t C_{0};\n\n".format(image_name))


def main():
parser = argparse.ArgumentParser(
description='Generate source code for NBGL icons.')
description='Generate source code for icons, in NBGL format.')
parser.add_argument('image_file', help="""
Icons to process.
Images that will be transformed through rotation or symmetry
must be suffixed by '_nocomp' (example: image_nocomp.png)
""", nargs='+')
parser.add_argument('--hexbitmaponly', action='store_true')
parser.add_argument('--glyphcheader', action='store_true')
parser.add_argument('--glyphcfile', action='store_true')
parser.add_argument('--hexbitmap', help="If set, the script generates in given file the hex bitmap (for app icon)")
parser.add_argument('--glyphcheader', help="Name of the generated source (glyphs.c)")
parser.add_argument('--glyphcfile', help="Name of the generated header (glyphs.h)")
parser.add_argument('--init_id', help="Initial ID of the glyph list", type=int, default=0)
parser.add_argument('--reverse', help="Reverse B&W for 1BPP icons", action='store_true')
parser.add_argument('--apps', help="to set to generate apps glyphs", action='store_true')
args = parser.parse_args()

# Print C header
if args.glyphcfile or args.glyphcheader:
print_glyphfile_top(args.glyphcfile, args.apps)

processed_image_names = []
for file in args.image_file:
try:
# Get image name
image_name = os.path.splitext(os.path.basename(file))[0]

# if image name has already been done, then don't do it twice
if image_name in processed_image_names:
continue
processed_image_names.append(image_name)

# Open image in luminance format
opened = open_image(file)
if opened is not None:
im, bpp = opened
else:
continue

if args.hexbitmaponly:
# Prepare and print app icon data
_, image_data = compute_app_icon_data(im, bpp, args.reverse)
print(binascii.hexlify(image_data).decode('utf-8'))
else:
# ensure that glyphcheader and glyphcfile are both set or unset
if (args.glyphcfile is not None and args.glyphcheader is None) or (args.glyphcfile is None and args.glyphcheader is not None):
print('glyphcheader and glyphcfile must be provided at the same time')
exit(-1)


if args.glyphcfile is not None:
# create source and header
source, header = create_source_files(args.glyphcfile, args.glyphcheader)

processed_image_names = []
id = args.init_id
for file in args.image_file:
try:
# Get image name
image_name = os.path.splitext(os.path.basename(file))[0]

# if image name has already been done, then don't do it twice
if image_name in processed_image_names:
continue
processed_image_names.append(image_name)

# Open image in luminance format
opened = open_image(file)
if opened is not None:
im, bpp = opened
else:
continue

# Prepare and print regular icon data
width, height = im.size

Expand All @@ -357,21 +341,39 @@ def main():

is_file, image_data = compute_regular_icon_data(no_comp, im, bpp, args.reverse)

if args.glyphcfile:
print_glyphcfile_data(image_name, bpp, image_data)
write_image_source_data(source, image_name, bpp, width, height, is_file, image_data)

if args.glyphcheader:
print_glyphcheader_data(
image_name, bpp, width, height, is_file, image_data)

except Exception as e:
sys.stderr.write(
"Exception while processing {}: {}\n".format(file, e))
try:
traceback.print_tb()
except:
pass
write_image_header_data(header, image_name, image_data)
id += 1

except Exception as e:
sys.stderr.write(
"Exception while processing {}: {}\n".format(file, e))
try:
traceback.print_tb()
except:
pass
else:
if args.hexbitmap is None:
print('something must be set')
exit(-1)
if len(args.image_file) != 1:
print('only one icon can be processed in hexbitmap mode')
exit(-1)
file = args.image_file[0]
# Get image name
image_name = os.path.splitext(os.path.basename(file))[0]

# Open image in luminance format
opened = open_image(file)
if opened is not None:
im, bpp = opened

# Prepare and print app icon data
_, image_data = compute_app_icon_data(im, bpp, args.reverse)
with open(args.hexbitmap, 'w') as out_file:
out_file.write(binascii.hexlify(image_data).decode('utf-8'))
#print(binascii.hexlify(image_data).decode('utf-8'))

if __name__ == "__main__":
main()

0 comments on commit 3575e2d

Please sign in to comment.