#!/usr/bin/env python3 # converts Hershey fonts into a format easier to consume by the Badger2040 # e-ink badge library - the result can be piped directly into a .hpp file. import argparse from pathlib import Path parser = argparse.ArgumentParser( description="Converts Hershey fonts into the format used by Badger2040." ) parser.add_argument("file", nargs="+", help="input files to convert") options = parser.parse_args() def convert_font(data): # parse hershey font data file, the file format contains one record per # character with the format: # # 2761 8MXP[OZPYQZQ[P]N_ # # first 5 characters: represent the character id (or a dummy value # of 12345). if it is a character id then a separate file contains the # mapping information to convert that into an ascii table entry. if all of # the ids are 12345 then it seems that the files contain 95 entries that # start from ascii character 32 (space) in order # # next 3 characters: number of vertices (including special left/right # bounds value) # # next 2 characters: represent the "left" and "right" offsets for this # character, to convert you must subtract 'R' from them. this pair counts # as the first "vertex" # # subsequent pairs of characters: represent each vertex, as before converted # into numbers by subtracting 'R'. there are vertex count (-1) of these # # note! within the vertex data can be extra newline characters which must # be ignored. vertex_data = [] char_data = {} auto_char_code = 0 # we'll loop, extracting one character per iteration, until all of the # data is consumed while len(data) > 0: char_code = auto_char_code auto_char_code += 1 # extract vertex count vertex_count = int(data[5:8]) vertex_count -= 1 # remove one for the bounds data # extract bounds left = ord(data[8:9]) - ord("R") right = ord(data[9:10]) - ord("R") char_data[char_code] = { "width": right - left, "vertex_count": vertex_count, "first_vertex_offset": len(vertex_data), } # work out expected total length of character data char_data_len = 10 + (vertex_count * 2) # if there are any newlines within this data then remove them before we # move on the parse the vertices while data.find("\n", char_data_len) != -1: data = data.replace("\n", "", 1) for i in range(0, vertex_count): offset = 10 + (i * 2) if data[offset:offset + 2] == " R": # pen up for one x = -128 y = -128 else: x = ord(data[offset + 0:offset + 1]) - ord("R") - left y = ord(data[offset + 1:offset + 2]) - ord("R") vertex_data.append(str(x)) vertex_data.append(str(y)) data = data[char_data_len:] font_name = Path(input_filename).stem # create code for all of the vertices vertex_code = """\ static const int8_t {font_name}_vertices[{count}] = {{ {vertices} }}; """.format( font_name=font_name, count=len(vertex_data), vertices=", ".join(vertex_data) ) # create code for chars and font # # struct hershey_font_glyph_t { # uint32_t width; // character width # uint32_t vertex_count; // number of vertices # int8_t *vertices; // vertex data (indices: even = x, odd = y) # }; chars = [] for i in range(0, 95): if i in char_data: chars.append( " {{.width={width}, .vertex_count={vertex_count}, .vertices=&{font_name}_vertices[{offset}]}}".format( width=char_data[i]["width"], vertex_count=char_data[i]["vertex_count"], font_name=font_name, offset=char_data[i]["first_vertex_offset"], ) ) else: chars.append(" {.width=0, .vertex_count=0, .vertices=nullptr}") # struct hershey_font_t { # hershey_font_glyph_t chars[95]; # }; font_code = """\ static const hershey_font_t {font_name} {{ .chars = {{ {chars} }} }}; """.format( font_name=font_name, chars=",\n".join(chars) ) print(vertex_code) print(font_code) return """ {{ \"{font_name}\", &{font_name} }}""".format(font_name=font_name) # create map of font name to font structure font_list = [] for input_filename in options.file: input_file = open(input_filename, mode="r") data = input_file.read() input_file.close() font_list.append(convert_font(data)) map_code = """\ std::map fonts = {{ {font_list} }}; """.format( font_list=",\n".join(font_list) ) print(map_code)