diff --git a/src/displayapp/fonts/fix_jetbrains_mono_bold_20_zero.py b/src/displayapp/fonts/fix_jetbrains_mono_bold_20_zero.py new file mode 100755 index 00000000..1617c36c --- /dev/null +++ b/src/displayapp/fonts/fix_jetbrains_mono_bold_20_zero.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys + +with open('jetbrains_mono_bold_20.c', 'r') as fd: + src = fd.read() + +zero_area = src.find('U+0030 "0"') +zero_data_start = src[zero_area:].find('\n') + zero_area + 1 +zero_data_end = src[zero_data_start:].find('\n\n') + +curr = src[zero_data_start:zero_data_start+zero_data_end] + +OLD=""" 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, + 0xdf, 0xf7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, + 0x8f, 0xc0,""" +NEW=""" 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7e, + 0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, + 0x8f, 0xc0,""" + +if curr != OLD: + if curr == NEW: + print('Already patched') + sys.exit() + sys.exit('Target differers from expected data') + + +with open('jetbrains_mono_bold_20.c', 'r+') as fd: + fd.seek(zero_data_start) #NOTE: since they are both the same size, this is allowed. Otherwise more editing needs to happen. + fd.write(NEW) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json new file mode 100644 index 00000000..c1ff9594 --- /dev/null +++ b/src/displayapp/fonts/fonts.json @@ -0,0 +1,90 @@ +{ + "fonts": { + "jetbrains_mono_bold_20": { + "sources": [ + { + "font": "JetBrainsMono-Bold.ttf", + "range": "0x20-0x7e, 0x410-0x44f" + }, + { + "font": "FontAwesome5-Solid+Brands+Regular.woff", + "range": "0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015" + } + ], + "bpp": 1, + "size": 20, + "patches": ["./fix_jetbrains_mono_bold_20_zero.py"] + }, + "jetbrains_mono_42": { + "sources": [ + { + "font": "JetBrainsMono-Regular.ttf", + "range": "0x25, 0x30-0x3a" + } + ], + "bpp": 1, + "size": 42 + }, + "jetbrains_mono_76": { + "sources": [ + { + "font": "JetBrainsMono-Regular.ttf", + "range": "0x25, 0x2D, 0x2F, 0x30-0x3a" + } + ], + "bpp": 1, + "size": 76 + }, + "jetbrains_mono_extrabold_compressed": { + "sources": [ + { + "font": "JetBrainsMono-ExtraBold.ttf", + "range": "0x30-0x3a" + } + ], + "bpp": 1, + "size": 80 + }, + "open_sans_light": { + "sources": [ + { + "font": "open_sans_light.ttf", + "symbols": "0123456789" + } + ], + "bpp": 1, + "size": 150 + }, + "lv_font_sys_48": { + "sources": [ + { + "font": "icons_sys_48.ttf", + "range": "0xe902, 0xe904-0xe907, 0xe90b-0xe90c" + } + ], + "bpp": 1, + "size": 48 + }, + "lv_font_navi_80": { + "sources": [ + { + "font": "navigation.ttf", + "range": "0xe900-0xe929" + } + ], + "bpp": 2, + "size": 80, + "compress": true + } + }, + "features": { + "hebrew": { + "jetbrains_mono_bold_20": [ + { + "font": "SimpleCLM-Medium.ttf", + "range": "0x05D0-0x05EA,0x05F3,0x05F4" + } + ] + } + } +} diff --git a/src/displayapp/fonts/generate.py b/src/displayapp/fonts/generate.py new file mode 100644 index 00000000..fea0123b --- /dev/null +++ b/src/displayapp/fonts/generate.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +import io +import sys +import json +import typing +import os.path +import argparse +import subprocess + +class FontArg(object): + def __init__(self, d): + self.font = d['font'] + self.range = d.get('range') + self.symbols = d.get('symbols') + + +def gen_lvconv_line(dest: str, size: int, bpp: int, fonts: typing.List[FontArg], compress:bool=False): + args = ['lv_font_conv', '--size', str(size), '--output', dest, '--bpp', str(bpp), '--format', 'lvgl'] + if not compress: + args.append('--no-compress') + for font in fonts: + args.extend(['--font', font.font]) + if font.range: + args.extend(['--range', font.range]) + if font.symbols: + args.extend(['--symbols', font.symbols]) + + return args + +def main(): + ap = argparse.ArgumentParser(description='auto generate lvGL font files from fonts') + ap.add_argument('config', type=str, help='config file to use') + ap.add_argument('-e', '--enable', type=str, action='append', help='optional feature to enable in font generation', default=[], metavar='features', dest='features') + ap.add_argument('-f', '--font', type=str, action='append', help='Choose specific fonts to generate (default: all)', default=[]) + args = ap.parse_args() + + if not os.path.exists(args.config): + sys.exit(f'Error: the config file {args.config} does not exist.') + if not os.access(args.config, os.R_OK): + sys.exit(f'Error: the config file {args.config} is not accessable (permissions?).') + with open(args.config, 'r') as fd: + data = json.load(fd) + + for enabled_feature in args.features: + if enabled_feature not in data['features']: + sys.exit(f'Error: the requested feature {enabled_feature} does not exist in {args.config}.') + + for (name,font) in data['fonts'].items(): + if args.font and name not in args.font: + continue + sources = font.pop('sources') + if 'patches' in font: + patches = font.pop('patches') + else: + patches = None + for enabled_feature in args.features: + if name in data['features'][enabled_feature]: + sources.extend(data['features'][enabled_feature][name]) + font['fonts'] = [FontArg(thing) for thing in sources] + line = gen_lvconv_line(f'{name}.c', **font) + subprocess.check_call(line) + if patches: + for patch in patches: + subprocess.check_call(patch) + + + +if __name__ == '__main__': + main()