circuitpython/tools/gen_display_resources.py
Scott Shawcroft c17f147be9
A variety of displayio improvements
This changes a number of things in displayio:
* Introduces BuiltinFont and Glyph so the built in font can be used by libraries. For boards with
  a font it is available as board.TERMINAL_FONT. Fixes #1172
* Remove _load_row from Bitmap in favor of bitmap[] access. Index can be x/y tuple or overall index. Fixes #1191
* Add width and height properties to Bitmap.
* Add insert and [] access to Group. Fixes #1518
* Add index param to pop on Group.
* Terminal no longer takes unicode character info. It takes a BuiltinFont instead.
* Fix Terminal's handling of [###D vt100 commands used when up arrowing into repl history.
* Add x and y positions to Group plus scale as well.
* Add bitmap accessor for BuiltinFont
2019-02-11 20:55:05 -08:00

187 lines
5.3 KiB
Python

import argparse
import os
import struct
import sys
sys.path.append("bitmap_font")
sys.path.append("../../tools/bitmap_font")
from adafruit_bitmap_font import bitmap_font
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
parser.add_argument('--font', type=str,
help='Font path', required=True)
parser.add_argument('--extra_characters', type=str,
help='Unicode string of extra characters')
parser.add_argument('--sample_file', type=argparse.FileType('r'),
help='Text file that includes strings to support.')
parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
args = parser.parse_args()
class BitmapStub:
def __init__(self, width, height, color_depth):
self.width = width
self.rows = [b''] * height
def _load_row(self, y, row):
self.rows[y] = bytes(row)
f = bitmap_font.load_font(args.font, BitmapStub)
real_bb = [0, 0]
# Load extra characters from the sample file.
sample_characters = set()
if args.sample_file:
for line in args.sample_file:
# Skip comments because we add additional characters in our huffman comments.
if line.startswith("//"):
continue
for c in line.strip():
sample_characters.add(c)
# Merge visible ascii, sample characters and extra characters.
visible_ascii = bytes(range(0x20, 0x7f)).decode("utf-8")
all_characters = visible_ascii
for c in sample_characters:
if c not in all_characters:
all_characters += c
if args.extra_characters:
all_characters.extend(args.extra_characters)
filtered_characters = all_characters
# Try to pre-load all of the glyphs. Misses will still be slow later.
f.load_glyphs(set(all_characters))
# Get each glyph.
for c in all_characters:
g = f.get_glyph(ord(c))
if not g:
print("Font missing character:", c, ord(c))
filtered_characters = filtered_characters.replace(c, "")
continue
x, y, dx, dy = g["bounds"]
if g["shift"][1] != 0:
raise RuntimeError("y shift")
real_bb[0] = max(real_bb[0], x - dx)
real_bb[1] = max(real_bb[1], y - dy)
tile_x, tile_y = real_bb
total_bits = tile_x * len(all_characters)
total_bits += 32 - total_bits % 32
bytes_per_row = total_bits // 8
b = bytearray(bytes_per_row * tile_y)
for x, c in enumerate(filtered_characters):
g = f.get_glyph(ord(c))
start_bit = x * tile_x + g["bounds"][2]
start_y = (tile_y - 2) - (g["bounds"][1] + g["bounds"][3])
for y, row in enumerate(g["bitmap"].rows):
for i in range(g["bounds"][0]):
byte = i // 8
bit = i % 8
if row[byte] & (1 << (7-bit)) != 0:
overall_bit = start_bit + (start_y + y) * bytes_per_row * 8 + i
b[overall_bit // 8] |= 1 << (7 - (overall_bit % 8))
extra_characters = ""
for c in filtered_characters:
if c not in visible_ascii:
extra_characters += c
c_file = args.output_c_file
c_file.write("""\
#include "shared-bindings/displayio/Palette.h"
#include "supervisor/shared/display.h"
""")
c_file.write("""\
uint32_t terminal_transparency[1] = {0x00000000};
// These colors are RGB 565 with the bytes swapped.
uint32_t terminal_colors[1] = {0xffff0000};
displayio_palette_t supervisor_terminal_color = {
.base = {.type = &displayio_palette_type },
.opaque = terminal_transparency,
.colors = terminal_colors,
.color_count = 2,
.needs_refresh = false
};
""")
c_file.write("""\
displayio_tilegrid_t supervisor_terminal_text_grid = {{
.base = {{ .type = &displayio_tilegrid_type }},
.bitmap = (displayio_bitmap_t*) &supervisor_terminal_font_bitmap,
.pixel_shader = &supervisor_terminal_color,
.x = 16,
.y = 0,
.bitmap_width_in_tiles = {0},
.width_in_tiles = 1,
.height_in_tiles = 1,
.total_width = {1},
.total_height = {2},
.tile_width = {1},
.tile_height = {2},
.tiles = NULL,
.needs_refresh = false,
.inline_tiles = false
}};
""".format(len(all_characters), tile_x, tile_y))
c_file.write("""\
const uint32_t font_bitmap_data[{}] = {{
""".format(bytes_per_row * tile_y // 4))
for i, word in enumerate(struct.iter_unpack(">I", b)):
c_file.write("0x{:08x}, ".format(word[0]))
if (i + 1) % (bytes_per_row // 4) == 0:
c_file.write("\n")
c_file.write("""\
};
""")
c_file.write("""\
const displayio_bitmap_t supervisor_terminal_font_bitmap = {{
.base = {{.type = &displayio_bitmap_type }},
.width = {},
.height = {},
.data = (uint32_t*) font_bitmap_data,
.stride = {},
.bits_per_value = 1,
.x_shift = 5,
.x_mask = 0x1f,
.bitmask = 0x1,
.read_only = true
}};
""".format(len(all_characters) * tile_x, tile_y, bytes_per_row / 4))
c_file.write("""\
const displayio_builtinfont_t supervisor_terminal_font = {{
.base = {{.type = &displayio_builtinfont_type }},
.bitmap = &supervisor_terminal_font_bitmap,
.width = {},
.height = {},
.unicode_characters = (const uint8_t*) "{}",
.unicode_characters_len = {}
}};
""".format(tile_x, tile_y, extra_characters, len(extra_characters.encode("utf-8"))))
c_file.write("""\
terminalio_terminal_obj_t supervisor_terminal = {
.base = { .type = &terminalio_terminal_type },
.font = &supervisor_terminal_font,
.cursor_x = 0,
.cursor_y = 0,
.tilegrid = &supervisor_terminal_text_grid
};
""")