font_to_py.py Add --charset option.

pull/16/head
Peter Hinch 2018-08-20 07:45:39 +01:00
rodzic c341ee9bd2
commit 7f4f840dda
2 zmienionych plików z 53 dodań i 18 usunięć

Wyświetl plik

@ -55,13 +55,25 @@ Example usage to produce a file `myfont.py` with height of 23 pixels:
* -l or --largest Ordinal value of largest character to be stored. Default 126.
* -e or --errchar Ordinal value of character to be rendered if an attempt is
made to display an out-of-range character. Default 63 (ASCII "?").
* -c or --charset Option to restrict the characters in the font to a specific
set. See below.
The -c option reduces the size of the font file. If the font file is frozen as
bytecode this will not reduce RAM usage but it will conserve flash. An example
usage for a digital clock font:
```shell
font_to_py.py Arial.ttf 20 arial_clock.py -c 1234567890:
```
If a character set is specified, `--smallest` and `--largest` should not be
specified: these values are computed from the charcater set.
Any requirement for arguments -xr will be specified in the device driver
documentation. Bit reversal is required by some display hardware.
Note that producing extended ASCII characters (ordinal value > 127) from ttf
files seems unreliable. If the expected results are not achieved, use an otf
font. This appears to be a limitation of the `freetype` library.
There have been reports that producing extended ASCII characters (ordinal
value > 127) from ttf files is unreliable. If the expected results are not
achieved, use an otf font. This may be a limitation of the `freetype` library.
### Output

Wyświetl plik

@ -255,13 +255,22 @@ class Glyph(object):
# height (in pixels) of all characters
# width (in pixels) for monospaced output (advance width of widest char)
class Font(dict):
def __init__(self, filename, size, minchar, maxchar, monospaced, defchar):
def __init__(self, filename, size, minchar, maxchar, monospaced, defchar, charset):
super().__init__()
self._face = freetype.Face(filename)
self.minchar = minchar
self.maxchar = maxchar
self.monospaced = monospaced
self.def_charset = charset
if defchar is None: # Binary font
self.charset = [chr(char) for char in range(minchar, maxchar + 1)]
else:
elif charset == '':
self.charset = [chr(defchar)] + [chr(char) for char in range(minchar, maxchar + 1)]
else:
n = sorted([ord(x) for x in chr(defchar) + charset])
self.minchar = n[0]
self.maxchar = n[-1]
self.charset = [chr(defchar)] + [chr(char) if chr(char) in charset else '' for char in range(n[0], n[-1] + 1)]
self.max_width = self.get_dimensions(size)
self.width = self.max_width if monospaced else 0
for char in self.charset: # Populate dictionary
@ -330,10 +339,13 @@ class Font(dict):
data = bytearray()
index = bytearray((0, 0))
for char in self.charset:
width = self[char][1]
data += (width).to_bytes(2, byteorder='little')
data += bytearray(self.stream_char(char, hmap, reverse))
index += (len(data)).to_bytes(2, byteorder='little')
if char == '':
index += (len(data)).to_bytes(2, byteorder='little')
else:
width = self[char][1]
data += (width).to_bytes(2, byteorder='little')
data += bytearray(self.stream_char(char, hmap, reverse))
index += (len(data)).to_bytes(2, byteorder='little')
return data, index
def build_binary_array(self, hmap, reverse, sig):
@ -347,7 +359,7 @@ class Font(dict):
# PYTHON FILE WRITING
STR01 = """# Code generated by font-to-py.py.
# Font: {}
# Font: {}{}
version = '0.2'
"""
@ -372,30 +384,34 @@ def write_func(stream, name, arg):
# filename, size, minchar=32, maxchar=126, monospaced=False, defchar=ord('?'):
def write_font(op_path, font_path, height, monospaced, hmap, reverse, minchar, maxchar, defchar):
def write_font(op_path, font_path, height, monospaced, hmap, reverse, minchar, maxchar, defchar, charset):
try:
fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar)
fnt = Font(font_path, height, minchar, maxchar, monospaced, defchar, charset)
except freetype.ft_errors.FT_Exception:
print("Can't open", font_path)
return False
try:
with open(op_path, 'w') as stream:
write_data(stream, fnt, font_path, monospaced, hmap, reverse, minchar, maxchar)
write_data(stream, fnt, font_path, hmap, reverse)
except OSError:
print("Can't open", op_path, 'for writing')
return False
return True
def write_data(stream, fnt, font_path, monospaced, hmap, reverse, minchar, maxchar):
def write_data(stream, fnt, font_path, hmap, reverse):
height = fnt.height # Actual height, not target height
stream.write(STR01.format(os.path.split(font_path)[1]))
minchar = fnt.minchar
maxchar = fnt.maxchar
charset = fnt.def_charset
st = '' if charset == '' else ' Char set: {}'.format(charset)
stream.write(STR01.format(os.path.split(font_path)[1], st))
stream.write('\n')
write_func(stream, 'height', height)
write_func(stream, 'max_width', fnt.max_width)
write_func(stream, 'hmap', hmap)
write_func(stream, 'reverse', reverse)
write_func(stream, 'monospaced', monospaced)
write_func(stream, 'monospaced', fnt.monospaced)
write_func(stream, 'min_ch', minchar)
write_func(stream, 'max_ch', maxchar)
data, index = fnt.build_arrays(hmap, reverse)
@ -487,6 +503,11 @@ if __name__ == "__main__":
help = 'Ordinal value of error character default %(default)i ("?")',
default = 63)
parser.add_argument('-c', '--charset',
type = str,
help = 'Character set. e.g. 1234567890: to restrict for a clock display.',
default = '')
args = parser.parse_args()
if not args.infile[0].isalpha():
quit('Font filenames must be valid Python variable names.')
@ -501,7 +522,7 @@ if __name__ == "__main__":
if os.path.splitext(args.outfile)[1].upper() == '.PY':
quit('Binary file must not have a .py extension.')
if args.smallest != 32 or args.largest != 126 or args.errchar != ord('?'):
if args.smallest != 32 or args.largest != 126 or args.errchar != ord('?') or args.charset:
quit(BINARY)
print('Writing binary font file.')
@ -522,11 +543,13 @@ if __name__ == "__main__":
if args.errchar < 0 or args.errchar > 255:
quit('--errchar must be between 0 and 255')
if args.charset and (args.smallest != 32 or args.largest != 126):
print('WARNING: specified smallest and largest values ignored.')
print('Writing Python font file.')
if not write_font(args.outfile, args.infile, args.height, args.fixed,
args.xmap, args.reverse, args.smallest, args.largest,
args.errchar):
args.errchar, args.charset):
sys.exit(1)
print(args.outfile, 'written successfully.')