import json import cv2 import numpy as np """ dd if=mobitec-1682-r7-bib-01979-r3.bin of=mobitec-1682-r7-bib-01979-r3-fonts.bin skip=64 bs=1024 dd if=mobitec-01682-r7-bib-01369-r9.bin of=mobitec-01682-r7-bib-01369-r9-fonts.bin skip=64 bs=1024 dhex mobitec-1682-r7-bib-01979-r3-fonts.bin mobitec-01682-r7-bib-01369-r9-fonts.bin """ src = "mobitec-1682-r7-bib-01979-r3" src = "mobitec-01682-r7-bib-01369-r9" with open("firmware/%s.bin" % src, "rb") as fh: buf = fh.read()[65536:] def scan_fonts(buf): """ Font start markers seem to be ascii character a..z followed by at least 60 nulls """ font_index = buf[0] assert font_index == 0x61 prev = 0 done = False while not done: needle = b"%c" % (font_index + 1) needle += 50 * b"\x00" try: font_offset = buf.index(needle) except ValueError: break font_body = buf[prev:] done = True else: font_body = buf[prev:font_offset] if done: break font_marker_length = len(needle) font_body = font_body[font_marker_length:] while font_body.startswith(b"\x00"): font_body = font_body[1:] font_marker_length += 1 yield font_index, font_body, font_marker_length prev = font_offset font_index += 1 meta = [] for font_index, font_body, font_marker_length in scan_fonts(buf): print() print("Parsing font %02x" % font_index) # Looks like yet another marker assert font_body[0] == 3 assert font_body[1] == 1 # Look up table consists of 95 16-bit integers glyph_offsets = np.frombuffer(font_body[2:192], dtype=np.uint16) prev = 0 slices = [] errors = set() for index, glyph_offset in enumerate(glyph_offsets): if glyph_offset != 0: glyph_offset -= font_marker_length print("Found %d undecoded bytes between lookup table and first glyph" % len(font_body[192:192 + glyph_offset])) break characters_present = "" for index, glyph_offset in enumerate(glyph_offsets): if glyph_offset == 0: characters_present += "_" # No glyph meta.append(None) continue else: # The index goes from space (32) up to ~ (126) character = chr(index + 32) characters_present += "+" # Glyphs are relative to the font marker start glyph_offset -= font_marker_length try: height, width = font_body[glyph_offset], font_body[glyph_offset + 1] except IndexError: print("Failed to look up glyph for %s", repr(character)) else: jah = np.frombuffer((font_body[glyph_offset + 2:])[::-1], dtype=np.uint8)[::-1] a = np.unpackbits(jah, axis=0) try: img = a[:width * 16].reshape((width, 16, 1)) img = np.hstack([img[:, 8:, :], img[:, :8, :]]) meta.append({ "width": width, "height": height, "bitmap": img.tolist() }) img = 255 * img slices.append(img) except ValueError: pass else: blank_image = np.zeros((1, 16, 1), np.uint8) blank_image[::] = 0 slices.append(blank_image) if glyph_offset <= prev: print("Glyph offsets not ordered") prev = glyph_offset print("Glyphs present:", characters_present) img = np.vstack(slices) img = np.flip(np.swapaxes(img, 1, 0), 0) s = img.shape * np.array(5) img = cv2.resize(img, dsize=(s[1], s[0]), interpolation=cv2.INTER_NEAREST) cv2.imwrite("samples/%s-%02x.png" % (src, font_index), img) with open("samples/%s-%02x.json" % (src, font_index), "w") as fh: fh.write(json.dumps({"glyphs": meta}))