import sys, os, math
from PIL import Image, ImageDraw, ImageFont
import framebuf
current_path = os.path.abspath(os.path.dirname(__file__))

def my_get_char_data(char_str, block_w, block_h, fnt, position_offset=(0, 0), invert=False, ascii_width = bytearray(0x7E+1 - 0x21)):
    byts = char_str.encode("utf8")
    if len(byts) == 1 and byts[0] >= 0x21 and byts[0] <= 0x7E:
        ascii_offset = byts[0] - 0x21
        block_size = math.ceil(block_w / 8) * block_h
        char_left, char_top, char_right, char_bottom = fnt.getbbox(char_str)
        char_width = char_right - char_left
        ascii_width[ascii_offset] = char_width # record ascii width
        # print("ch", char_str, "width", char_width, "offset", ascii_offset)
        char_x_offset = char_left
        char_y_offset = char_top
        char_offset = (position_offset[0] + char_x_offset, position_offset[1] + char_y_offset)
        # draw char
        fnt_img = Image.new("1", (block_w, block_h), color=255)
        fnt_draw = ImageDraw.Draw(fnt_img)
        try:
            fnt_draw.text(char_offset, char_str, fill=0, font=fnt, anchor="lt", spacing=0)
        except: pass
        # draw framebuffer
        buffer = bytearray(block_size)
        frame = framebuf.FrameBuffer(buffer, block_w, block_h, framebuf.MONO_HLSB)
        for y in range(block_h):
            for x in range(block_w):
                pixel = fnt_img.getpixel((x, y))
                pixel = 1 if ((pixel == 0) ^ invert) else 0
                frame.pixel(x, y, pixel)
        return buffer, fnt_img

def main():
    block_width = 8
    block_height = 8
    if len(sys.argv) > 1:
        font_path = sys.argv[1]
    else:
        font_path = os.path.join(current_path, "quan.ttf")
    offset= (0, 0)
    preview_path = os.path.join(current_path, "pix{}x{}.png".format(block_width, block_height))
    c_output_path = os.path.join(current_path, "pix{}x{}.h".format(block_width, block_height))
    font_size = 8
    ascii_width = bytearray(0x7E+1 - 0x21) # 0x20 ascii space
    # generate font
    font_data = bytearray()
    font = ImageFont.truetype(font_path, font_size)
    preview = Image.new("1", (block_width*16, block_height*math.ceil((0x7F - 0x21)/16)), color=255)
    preview_x_count = 0
    preview_y_count = 0
    for unic in range(0x21, 0x7E+1): # ascii
        try:
            char = bytes([unic]).decode("ascii")
        except:
            continue
        data, img = my_get_char_data(char, block_width, block_height, font, offset, False, ascii_width)
        font_data.extend(data)
        preview.paste(img, (preview_x_count * block_width, preview_y_count * block_height))
        preview_x_count += 1
        if preview_x_count >= 16:
            preview_x_count = 0
            preview_y_count += 1

    # preview.save(preview_path)
    
    # write out
    with open(c_output_path, "wt") as f:
        f.write("#pragma once\n")
        f.write("#include <stdint.h>\n")
        f.write("\n")
        f.write(f"const uint8_t FONT_QUAN_{block_width}_{block_height}[] = {{")
        for i, byte in enumerate(font_data):
            if i % 16 == 0:
                f.write("\n   ")
            f.write(f" 0x{byte:02X},")
        f.write("\n};\n")
        f.write(f"const uint8_t FONT_QUAN_ASCII_WIDTH_{block_width}_{block_height}[] = {{")
        for i, byte in enumerate(ascii_width):
            if i % 16 == 0:
                f.write("\n   ")
            f.write(f" 0x{byte:02X},")
        f.write("\n};\n")
        f.write("\n")
        f.close()

if __name__ == "__main__":
    main()