From 6e62fb7d6dbae86633d6ee7b1654261201543285 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Thu, 1 Feb 2024 17:46:30 +0100 Subject: [PATCH] fxconv: PythonExtra support for bopti-fx --- fxconv/fxconv-main.py | 18 +++++++++++++++--- fxconv/fxconv.py | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/fxconv/fxconv-main.py b/fxconv/fxconv-main.py index 7f8e7bb..27188c6 100755 --- a/fxconv/fxconv-main.py +++ b/fxconv/fxconv-main.py @@ -23,6 +23,7 @@ When TYPE is specified (one-shot conversion), it should be one of: --libimg-image Convert to the libimg image format --custom Use a custom converter; you might want to specify an explicit type by adding "custom-type:your_custom_type" (see below) +Custom converters can be specified by: --converters Semicolon-separated list of custom converters (converters.py in the current directory is detected as one per legacy) @@ -31,8 +32,13 @@ syntax (names can contain dots). For example: fxconv -f myfont.png -o myfont.o charset:ascii grid.padding:1 height:7 Some formats differ between platforms so you should specify it when possible: - --fx Casio fx-9860G family (black-and-white calculators) - --cg Casio fx-CG 50 family (16-bit color calculators) + --fx CASIO fx-9860G family (black-and-white calculators) + --cg CASIO fx-CG 50 family (16-bit color calculators) + +Finally, there is some support (non-final) for PythonExtra, in which case the +output file is as Python file instead of an object file. + --py Convert for PythonExtra (some types supported) + --py-compact Use compact bytes notation (shorter, but non-printable) """.strip() # Simple error-warnings system @@ -60,6 +66,7 @@ def main(): target = { 'toolchain': None, 'arch': None, 'section': None } use_custom = False converter_paths = [] + py = { 'enabled': False, 'compact': False } # Parse command-line arguments @@ -69,7 +76,7 @@ def main(): try: longs = ["help", "output=", "toolchain=", "arch=", "section=", "fx", - "cg", "converters="] + types.split() + "cg", "converters=", "py", "py-compact"] + types.split() opts, args = getopt.gnu_getopt(sys.argv[1:], "hsbifo:", longs) except getopt.GetoptError as error: return err(error) @@ -94,6 +101,10 @@ def main(): mode = "custom" elif name == "--converters": converter_paths = [path for path in value.split(";") if path] + elif name == "--py": + py['enabled'] = True + elif name == "--py-compact": + py['compact'] = True # Other names are modes else: mode = name[1] if len(name)==2 else name[2:] @@ -144,6 +155,7 @@ def main(): spec.loader.exec_module(module) converters.append(module.convert) + params["py"] = py fxconv.convert(input, params, target, output, model, converters) if __name__ == "__main__": diff --git a/fxconv/fxconv.py b/fxconv/fxconv.py index 6b9f2e4..b23d90c 100644 --- a/fxconv/fxconv.py +++ b/fxconv/fxconv.py @@ -513,6 +513,11 @@ def convert_bopti_fx(input, params): data[n] = layer[4 * longword + i] n += 1 + if params["py"]["enabled"]: + w, h = img.size + return ["import gint\n", + f"{params['name']} = gint.image({p.id}, {w}, {h}, ", data, ")\n"] + # Generate the object file o = ObjectData() o += header @@ -1155,8 +1160,12 @@ def convert(input, params, target, output=None, model=None, custom=None): else: raise FxconvError(f'unknown resource type \'{t}\'') + # PythonExtra conversion: output a file + if params["py"]["enabled"]: + pyout(o, output, params) # Standard conversions: save to ELF in the natural way - elf(o, output, "_" + params["name"], **target) + else: + elf(o, output, "_" + params["name"], **target) def elf(data, output, symbol, toolchain=None, arch=None, section=None, assembly=None): @@ -1308,6 +1317,35 @@ def elf_multi(vars, output, assembly=None, **kwargs): return elf(None, output, None, assembly=asm, **kwargs) +def pyout(bits, output, params): + # Compact into byte strings to avoid building tuples in the heap; + # MicroPython allows basically anything in literal strings (including + # NUL!), we just have to escape \, \n, \r, and ". + def byteify(c): + if c == ord('"'): + return b'\\"' + if c == ord('\n'): + return b'\\n' + if c == ord('\r'): + return b'\\r' + if c == ord('\\'): + return b'\\\\' + return bytes([c]) + + with open(output, "wb") as fp: + for section in bits: + if isinstance(section, bytearray): + section = bytes(section) + if isinstance(section, bytes): + if params["py"]["compact"]: + fp.write(b'b"') + fp.write(section) + fp.write(b'"') + else: + fp.write(repr(section).encode("utf-8")) + else: + fp.write(section.encode("utf-8")) + # # Meta API #