Font conversions and manipulation
A font can be loaded from a ROM image using the rom_to_font function.
from retrofont.font import rom_to_font
data = open('data/test_font.rom', 'rb').read()
font = rom_to_font(data)
print('Number of character sets:', len(font))
print('Size of a character set:', len(font[0]))
This particular font contains three character sets, each containing 256 glyphs.
Number of character sets: 3
Size of a character set: 256
A font can be converted back to a ROM image using the font_to_rom
function.
from retrofont.font import font_to_rom
data = font_to_rom(font)
print('Size of the ROM image:', len(data))
The serialised ROM image size for this particular font is 6144 bytes.
Size of the ROM image: 6144
A text font can be loaded from a YAML file.
from yaml import safe_load
text_font = safe_load(open('data/test_font.yaml', 'rt'))
print('Size of the first character set:', len(text_font[0]))
A text font does not contain any empty glyphs. The first character set in this particular font contains two glyphs.
Size of the first character set: 2
A text glyph consists of a data field, containing a text representation of
the glyph and an offset field, denoting the position of the glyph in the
character set.
from pprint import PrettyPrinter
pp = PrettyPrinter(indent=2)
pp.pprint(text_font[0][0])
The first non-empty glyph in the first character set of this font, happens to be an ‘A’ that is positioned at offset 65.
{ 'data': [ ' ##### ',
'# # ',
'# # ',
'####### ',
'# # ',
'# # ',
'# # ',
' '],
'offset': 65}
Text fonts can be converted to a normal (binary) font using the
yaml_to_font function.
from retrofont.font import yaml_to_font
font = yaml_to_font(text_font)
print('Size of the first character set:', len(font[0]))
The first character set of this font contains 256 glyphs instead of the two we found in the text tont. Any undefined glyphs have been converted to the empty glyph.
Size of the first character set: 256
Vice versa, fonts can be converted to YAML using the font_to_yaml
function.
from retrofont.font import font_to_yaml
text_font = font_to_yaml(font)
print('Size of the first character set:', len(text_font[0]))
Notice that the empty characters are no longer present in the text font.
Size of the first character set: 2
ROM images do not necessarily contain all glyphs in the same order as they are used. This is particularly noticeable when using a bitmap font as primary font. If the glyphs are not at their standard ASCII position, the terminal may become unusable. This is why system specific configurations are available.
from retrofont.config import read_config, select_system_config
config = read_config()
system_config = select_system_config(config['systems'], 'C64')
pp.pprint(system_config)
{ 'name': 'C64',
'primary': { 'character_blocks': [[32, [32, 96]], [96, [0, 32]]],
'characters': [[64, 0], [95, 100], [124, 93]]}}
See the Systems section for more information about system configuration.
These mappings are converted to a permutation using the
keymap_to_permutation function.
from retrofont.font import keymap_to_permutation
permutation = keymap_to_permutation(system_config['primary'])
print('Character 32 is at position', permutation[32], 'in the ROM image')
print('Character 97 is at position', permutation[97], 'in the ROM image')
print('Character 64 is at position', permutation[64], 'in the ROM image')
The provided mappings are now in a flat permutation list.
Character 32 is at position 32 in the ROM image
Character 97 is at position 1 in the ROM image
Character 64 is at position 0 in the ROM image
A permutation can be used to map a character set using the map_charset
function.
from retrofont.font import map_charset
new_charset = map_charset(font[0], permutation)
print(new_charset[97] == font[0][1])
Similarly, the permutation can be applied to every character set in the font using the map_font function.
from retrofont.font import map_font
new_font = map_font(font, permutation)
print(new_font[0][97] == font[0][1])