Add c_to_python_font.py.

pull/45/head
Peter Hinch 2022-01-14 14:48:04 +00:00
rodzic dcc97abc3f
commit eebd7307af
11 zmienionych plików z 227 dodań i 4 usunięć

Wyświetl plik

@ -33,13 +33,14 @@ The resultant file is usable with two varieties of display device drivers:
# 2. Solution
This comprises three components, links to docs below:
This comprises four components, links to docs below:
1. [font_to_py.py](./FONT_TO_PY.md) This utility runs on a PC and converts a
font file to Python source. See below.
1. [font_to_py.py](./FONT_TO_PY.md) This utility runs on a PC and converts an
industry standard font file to Python source. See below.
2. [Writer and CWriter classes](./writer/WRITER.md) These facilitate rendering
text to a monochrome or colour display having a suitable device driver.
3. [Device driver notes](./writer/DRIVERS.md). Notes for authors of display
3. [Creating icon fonts](./icon_fonts/README.md)
4. [Device driver notes](./writer/DRIVERS.md). Notes for authors of display
device drivers. Provides details of the font file format and information on
ensuring comptibility with the `Writer` classes.

164
c_to_python_font.py 100755
Wyświetl plik

@ -0,0 +1,164 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2022 Peter Hinch
import sys
from font_to_py import ByteWriter, var_write, write_func, STR02, STR02H
STR01 = """# Code generated by c_to_python_font.py.
# Char set: {}
# Cmd: {}
version = '0.10'
"""
class Glyph:
dstart = 0 # Start index of next glyph
def __init__(self):
self.width = 0
self.height = 0
def populate(self, fn, data, idx):
try:
with open(fn, "r") as f:
s = f.readline()
elements = s.split(" ")
if elements[1].endswith("width"):
self.width = int(elements[2])
data.extend((self.width).to_bytes(2, 'little'))
else:
return False
s = f.readline()
elements = s.split(" ")
if elements[1].endswith("height"):
self.height = int(elements[2])
else:
return False
s = f.readline()
if not s.startswith("static"):
return False
while s := f.readline():
if (lb := s.find("}")) != -1:
s = s[:lb] # Strip trailing };
p = s.strip().split(',')
if not p[-1]:
p = p[: -1]
z = [int(x, 16) for x in p]
data.extend(bytearray(z))
# index points to start of current data block
idx.extend((Glyph.dstart).to_bytes(2, 'little'))
Glyph.dstart += ((self.width - 1)//8 + 1) * self.height + 2
except OSError:
return False
return True
class Font:
def __init__(self):
self.glyphs = []
self.height = 0
self.max_width = 0
self.data = bytearray()
self.index = bytearray()
def __getitem__(self, glyph_index):
return self.glyphs[glyph_index]
def populate(self, filename="filenames.txt"):
try:
with open(filename, "r") as f:
while fn := f.readline().strip(): # Get current C file
if (lc := fn.find("#")) != -1:
if (fn := fn[:lc].strip()) == "":
continue
g = Glyph()
if g.populate(fn, self.data, self.index):
if ht := self.height:
if ht != g.height:
print(f"Fatal: file {fn} height is {g.height} while font height is {ht}")
return False
else:
self.height = g.height
self.glyphs.append(g)
self.max_width = max(self.max_width, g.width)
else:
print('Failed to read', fn)
return False
except OSError:
print("Failed to read", filename)
return False
return True
def output(self, stream):
minchar = ord("A")
nglyphs = len(self.glyphs) - 1 # Number less default glyph
maxchar = minchar + nglyphs - 1
st = ""
for z in range(nglyphs):
st = "".join((st, chr(minchar + z)))
cl = ' '.join(sys.argv)
stream.write(STR01.format(st, cl))
write_func(stream, 'height', self.height)
write_func(stream, 'baseline', self.height)
write_func(stream, 'max_width', self.max_width)
write_func(stream, 'hmap', True)
write_func(stream, 'reverse', True) # ????
write_func(stream, 'monospaced', False)
write_func(stream, 'min_ch', minchar)
write_func(stream, 'max_ch', maxchar)
bw_font = ByteWriter(stream, '_font')
bw_font.odata(self.data)
bw_font.eot()
bw_index = ByteWriter(stream, '_index')
bw_index.odata(self.index)
bw_index.eot()
stream.write(STR02.format(minchar, maxchar))
stream.write(STR02H.format(self.height))
def make_font(infile="filenames.txt", outfile="icofont.py"):
try:
with open(outfile, "w") as f:
font = Font()
if font.populate(infile):
font.output(f)
else:
return # Failed
except OSError:
print(f"Failed to open {outfile} for writing.")
print(f"{outfile} successfully written.")
def version_check():
n = sys.implementation.name
v = sys.implementation.version
if n == "cpython":
if v[0] == 3:
return v[1] >= 8
return v[0] > 3
return False # Requires CPython
usage = """Convert a set of C bitmaps to a Python font file. Usage:
c_to_python_font.py [infile [outfile]]
infile contains a list of C bitmap files, one per line.
outfile is the name of the output Python font.
Default args:
infile: filenames.txt
outfile: icofont.py
e.g.
$ ./c_to_python_font.py my_file_list.txt my_font.py
"""
if __name__ == "__main__":
a = sys.argv
if len(a) >= 2 and a[1] in ("--help", "-h", "help"):
print(usage)
elif not version_check():
print("This script requires Python 3.8 or above.")
else:
infile = a[1] if len(a) >= 2 else "filenames.txt"
outfile = a[2] if len(a) >= 3 else "icofont.py"
make_font(infile, outfile)

Wyświetl plik

@ -0,0 +1,8 @@
#define back_width 19
#define back_height 19
static unsigned char back_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04,
0x80, 0x03, 0x06, 0xc0, 0x83, 0x07, 0xf0, 0xc3, 0x07, 0xf8, 0xe3, 0x07,
0xfe, 0xfb, 0x07, 0xff, 0xff, 0x07, 0xfe, 0xfb, 0x07, 0xf8, 0xf3, 0x07,
0xf0, 0xc3, 0x07, 0xc0, 0x83, 0x07, 0x80, 0x03, 0x07, 0x00, 0x02, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Wyświetl plik

@ -0,0 +1,8 @@
#define default_width 19
#define default_height 19
static unsigned char default_bits[] = {
0x01, 0x00, 0x04, 0x02, 0x00, 0x02, 0x04, 0x00, 0x01, 0x08, 0x80, 0x00,
0x10, 0x40, 0x00, 0x20, 0x20, 0x00, 0x40, 0x10, 0x00, 0x80, 0x08, 0x00,
0x00, 0x05, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x80, 0x08, 0x00,
0x40, 0x10, 0x00, 0x20, 0x20, 0x00, 0x10, 0x40, 0x00, 0x08, 0x80, 0x00,
0x04, 0x00, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00, 0x04};

Wyświetl plik

@ -0,0 +1,7 @@
# Filenames for media player icons
default.c
play.c # Test
stop.c
pause.c
back.c
fwd.c

8
icon_fonts/fwd.c 100644
Wyświetl plik

@ -0,0 +1,8 @@
#define fwd_width 19
#define fwd_height 19
static unsigned char fwd_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00,
0x03, 0x0e, 0x00, 0x0f, 0x1e, 0x00, 0x1f, 0x7e, 0x00, 0x3f, 0xfe, 0x00,
0xff, 0xfe, 0x03, 0xff, 0xff, 0x07, 0xff, 0xff, 0x07, 0xff, 0xfe, 0x03,
0x7f, 0xfe, 0x00, 0x1f, 0x3e, 0x00, 0x0f, 0x0e, 0x00, 0x07, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 31 KiB

Wyświetl plik

@ -0,0 +1,8 @@
#define pause_width 19
#define pause_height 19
static unsigned char pause_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00,
0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00,
0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00,
0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00, 0xf8, 0xf8, 0x00,
0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Wyświetl plik

@ -0,0 +1,8 @@
#define play_width 19
#define play_height 19
static unsigned char play_bits[] = {
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x7e, 0x00, 0x00,
0xfe, 0x01, 0x00, 0xfe, 0x07, 0x00, 0xfe, 0x1f, 0x00, 0xfe, 0x7f, 0x00,
0xfe, 0xff, 0x01, 0xfe, 0xff, 0x07, 0xfe, 0xff, 0x01, 0xfe, 0x7f, 0x00,
0xfe, 0x1f, 0x00, 0xfe, 0x07, 0x00, 0xfe, 0x01, 0x00, 0x7e, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};

Wyświetl plik

@ -0,0 +1,8 @@
#define stop_width 19
#define stop_height 19
static unsigned char stop_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00,
0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00,
0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00,
0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00, 0xfc, 0xff, 0x00,
0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Wyświetl plik

@ -369,6 +369,9 @@ Save this modified font under a new name. Then run `font_to_py` to create a
Python font in a chosen size and comprising only those characters (`-c ABCDE`).
Instantiate the buttons with e.g. `text="A"`.
Alternatively icons can be created as bitmaps and converted to Python font
files as [described here](../icon_fonts/README.md).
# 4. Notes
Possible future enhancements: