kopia lustrzana https://github.com/peterhinch/micropython-font-to-py
Add c_to_python_font.py.
rodzic
dcc97abc3f
commit
eebd7307af
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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};
|
|
@ -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};
|
|
@ -0,0 +1,7 @@
|
|||
# Filenames for media player icons
|
||||
default.c
|
||||
play.c # Test
|
||||
stop.c
|
||||
pause.c
|
||||
back.c
|
||||
fwd.c
|
|
@ -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 |
|
@ -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};
|
|
@ -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};
|
|
@ -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};
|
|
@ -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:
|
||||
|
|
Ładowanie…
Reference in New Issue