2016-03-26 22:46:18 +00:00
|
|
|
#!/usr/bin/env python3
|
2017-10-01 17:52:43 +00:00
|
|
|
|
|
|
|
# script used to generate /embed/extmod/modtrezorui/font_*_*.c
|
|
|
|
|
|
|
|
|
2016-03-26 22:46:18 +00:00
|
|
|
import freetype
|
|
|
|
|
2016-03-27 11:36:27 +00:00
|
|
|
MIN_GLYPH = ord(' ')
|
|
|
|
MAX_GLYPH = ord('~')
|
2016-03-26 22:46:18 +00:00
|
|
|
|
2017-10-11 21:05:08 +00:00
|
|
|
FONT_BPP = 4
|
2017-10-01 18:29:23 +00:00
|
|
|
|
2016-10-18 13:05:55 +00:00
|
|
|
# metrics explanation: https://www.freetype.org/freetype2/docs/glyphs/metrics.png
|
|
|
|
|
2017-06-13 14:50:03 +00:00
|
|
|
|
2016-03-26 22:46:18 +00:00
|
|
|
def process_face(name, style, size):
|
2016-10-18 13:05:55 +00:00
|
|
|
print('Processing ... %s %s %s' % (name, style, size))
|
2016-03-26 22:46:18 +00:00
|
|
|
face = freetype.Face('/usr/share/fonts/truetype/%s-%s.ttf' % (name, style))
|
|
|
|
face.set_pixel_sizes(0, size)
|
2016-10-18 13:05:55 +00:00
|
|
|
fontname = '%s_%s_%d' % (name.lower(), style.lower(), size)
|
|
|
|
with open('font_%s.h' % fontname, 'wt') as f:
|
|
|
|
f.write('#include <stdint.h>\n\n')
|
2018-07-18 10:17:51 +00:00
|
|
|
f.write('extern const uint8_t* const Font_%s_%s_%d[%d + 1 - %d];\n' % (name, style, size, MAX_GLYPH, MIN_GLYPH))
|
2016-10-18 13:05:55 +00:00
|
|
|
with open('font_%s.c' % fontname, 'wt') as f:
|
|
|
|
f.write('#include "font_%s.h"\n\n' % fontname)
|
2016-03-26 22:46:18 +00:00
|
|
|
f.write('// first two bytes are width and height of the glyph\n')
|
2018-07-18 10:17:51 +00:00
|
|
|
f.write('// third, fourth and fifth bytes are advance\n')
|
|
|
|
f.write('// bearingX and bearingY of the horizontal metrics of the glyph\n')
|
2016-03-26 22:46:18 +00:00
|
|
|
f.write('// rest is packed 4-bit glyph data\n\n')
|
2018-07-18 10:17:51 +00:00
|
|
|
f.write('// clang-format off\n\n')
|
2016-03-26 22:46:18 +00:00
|
|
|
for i in range(MIN_GLYPH, MAX_GLYPH + 1):
|
|
|
|
c = chr(i)
|
2018-02-08 14:04:33 +00:00
|
|
|
face.load_char(c, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_NORMAL)
|
2016-03-26 22:46:18 +00:00
|
|
|
bitmap = face.glyph.bitmap
|
|
|
|
metrics = face.glyph.metrics
|
2018-02-08 14:04:33 +00:00
|
|
|
assert metrics.width // 64 == bitmap.width
|
|
|
|
assert metrics.height // 64 == bitmap.rows
|
|
|
|
assert metrics.width % 64 == 0
|
|
|
|
assert metrics.height % 64 == 0
|
|
|
|
assert metrics.horiAdvance % 64 == 0
|
|
|
|
assert metrics.horiBearingX % 64 == 0
|
|
|
|
assert metrics.horiBearingY % 64 == 0
|
2017-06-13 14:50:03 +00:00
|
|
|
assert bitmap.width == bitmap.pitch
|
|
|
|
assert len(bitmap.buffer) == bitmap.pitch * bitmap.rows
|
2018-02-07 17:38:29 +00:00
|
|
|
width = bitmap.width
|
|
|
|
rows = bitmap.rows
|
2018-02-08 14:04:33 +00:00
|
|
|
advance = metrics.horiAdvance // 64
|
|
|
|
bearingX = metrics.horiBearingX // 64
|
|
|
|
# the following code is here just for some letters (listed below)
|
|
|
|
# not using negative bearingX makes life so much easier; add it to advance instead
|
|
|
|
if c in 'jy}),/' and bearingX < 0:
|
2018-02-07 17:38:29 +00:00
|
|
|
advance += -bearingX
|
|
|
|
bearingX = 0
|
2018-02-08 14:04:33 +00:00
|
|
|
bearingY = metrics.horiBearingY // 64
|
|
|
|
assert advance >= 0 and advance <= 255
|
2018-02-07 17:38:29 +00:00
|
|
|
assert bearingX >= 0 and bearingX <= 255
|
|
|
|
assert bearingY >= 0 and bearingY <= 255
|
|
|
|
print('Loaded glyph "%c" ... %d x %d @ %d grays (%d bytes, metrics: %d, %d, %d)' % (c, bitmap.width, bitmap.rows, bitmap.num_grays, len(bitmap.buffer), advance, bearingX, bearingY))
|
|
|
|
f.write('/* %c */ static const uint8_t Font_%s_%s_%d_glyph_%d[] = { %d, %d, %d, %d, %d' % (c, name, style, size, i, width, rows, advance, bearingX, bearingY))
|
2016-03-26 22:46:18 +00:00
|
|
|
buf = list(bitmap.buffer)
|
2016-03-27 21:30:35 +00:00
|
|
|
if len(buf) > 0:
|
2017-10-01 18:29:23 +00:00
|
|
|
if FONT_BPP == 2:
|
|
|
|
for _ in range(4 - len(buf) % 4):
|
|
|
|
buf.append(0)
|
|
|
|
buf = [((a & 0xC0) | ((b & 0xC0) >> 2) | ((c & 0xC0) >> 4) | ((d & 0xC0) >> 6)) for a, b, c, d in [buf[i:i + 4] for i in range(0, len(buf), 4)]]
|
|
|
|
elif FONT_BPP == 4:
|
|
|
|
if len(buf) % 2 > 0:
|
|
|
|
buf.append(0)
|
|
|
|
buf = [((a & 0xF0) | (b >> 4)) for a, b in [buf[i:i + 2] for i in range(0, len(buf), 2)]]
|
2016-03-27 21:30:35 +00:00
|
|
|
f.write(', ' + ', '.join(['%d' % x for x in buf]))
|
2016-03-26 22:46:18 +00:00
|
|
|
f.write(' };\n')
|
2016-03-27 21:30:35 +00:00
|
|
|
f.write('\nconst uint8_t * const Font_%s_%s_%d[%d + 1 - %d] = {\n' % (name, style, size, MAX_GLYPH, MIN_GLYPH))
|
2016-03-26 22:46:18 +00:00
|
|
|
for i in range(MIN_GLYPH, MAX_GLYPH + 1):
|
2016-03-27 21:30:35 +00:00
|
|
|
f.write(' Font_%s_%s_%d_glyph_%d,\n' % (name, style, size, i))
|
2016-03-26 22:46:18 +00:00
|
|
|
f.write('};\n')
|
|
|
|
|
2017-09-05 21:15:47 +00:00
|
|
|
|
2016-03-30 16:30:22 +00:00
|
|
|
process_face('Roboto', 'Regular', 20)
|
2016-10-18 13:05:55 +00:00
|
|
|
process_face('Roboto', 'Bold', 20)
|
|
|
|
process_face('RobotoMono', 'Regular', 20)
|