The sprites are 6×7 including a 1px margin on the right and bottom edges. The margin is occasionally tapped into by descenders (g, j, p, q, ƒ, Ç, φ, џ, comma, semicolon, etc.), box-drawing characters, and other symbols that just wouldn't consistently compress below 6×7 (↔, ↨, √, etc.).
I have crafted thus far all characters in IBM 437, Windows-1252, and the Macintosh Cyrillic codepage.
(Original work; hereby published under a dual license CC0+WTFPL.)
Could be useful for very small LCD displays, or for fitting an entire movie script on your monitor at once.
It is not finished yet; my next goal is to figure out how to create one of these so I can actually use the thing… then I'll worry about adding more characters. (Fontforge is waay too sophisticated for this use-case, though, so it has ended up screwing up the font every time I tried to render an .obt file: the letters all had "shaved tops", and the UI element to set their height manually was greyed-out. Hmm…)
Appendices
Compiler
from PIL import Image
import struct, csv, gzip
# USAGE:
# python3 make_psf.py 6x7 cp437_tinyfont.gif unicode_cp437.tsv 437-Handmade5x6.psf2.gz && setfont -v 437-Handmade5x6.psf2.gz
# python3 make_psf.py 6x7 cp437_tinyfont.gif unicode_x1252.tsv x1252-Handmade5x6.psf2.gz && setfont -v x1252-Handmade5x6.psf2.gz
PSF2_MAGIC = b'\x72\xb5\x4a\x86'
PSF2_HAS_UNICODE_TABLE = 0b1
PSF2_MAXVERSION = 0
PSF2_SEPARATOR = b'\xFF'
PSF2_STARTSEQ = b'\xFE'
psf2_header = struct.Struct('<4sIiIII2I')
# PCF IS WIP NOT YET IMPLEMENTED #
# https://fontforge.org/docs/techref/pcf-format.html
PCF_MAGIC = b'\x01FCP'
PCF_PROPERTIES = 0b000000001
PCF_ACCELERATORS = 0b000000010
PCF_METRICS = 0b000000100
PCF_BITMAPS = 0b000001000
PCF_INK_METRICS = 0b000010000
PCF_BDF_ENCODINGS = 0b000100000
PCF_SWIDTHS = 0b001000000
PCF_GLYPH_NAMES = 0b010000000
PCF_BDF_ACCELERATORS = 0b100000000
PCF_DEFAULT_FORMAT = 0x000
PCF_INKBOUNDS = 0x200
PCF_ACCEL_W_INKBOUNDS = 0x100
PCF_COMPRESSED_METRICS = 0x100
PCF_GLYPH_PAD_MASK = 0b000011
PCF_BYTE_MASK = 0b000100
PCF_BIT_MASK = 0b001000
PCF_SCAN_UNIT_MANK = 0b110000
pcf_header_1 = struct.Struct('<4sI')
pcf_header_2 = struct.Struct('<IIII')
def im2glyphs(im, w, h):
for y in range(0, im.height, h):
for x in range(0, im.width, w):
yield im.crop((x, y, x+w, y+h))
def _makeheader(glyphs, *, ver=PSF2_MAXVERSION, flags=0):
n = len(glyphs)
assert len(set(glyph.size for glyph in glyphs)) == 1
w, h = glyphs[0].size
glyphsize = h * ((w + 7) // 8)
#glyphsize = -(w * h // -8)
return psf2_header.pack(PSF2_MAGIC, ver, psf2_header.size, flags, n, glyphsize, h, w)
def _makebody(glyphs):
assert len(set(glyph.size for glyph in glyphs)) == 1
for glyph in glyphs:
yield glyph.convert('1').tobytes()
def _makeuctable(unicodemap):
for position in unicodemap:
for sequence in position:
yield PSF2_STARTSEQ
yield sequence.encode("utf-8")
yield PSF2_SEPARATOR
def makepsf2(size, im, out, unicodemap=None):
global glyphs # for debugging, run python -i
glyphs = list(im2glyphs(im, *size))
flags = 0
if unicodemap is not None:
flags |= PSF2_HAS_UNICODE_TABLE
else:
assert len(glyphs) == 256
out.write(_makeheader(glyphs, flags=flags))
for chunk in _makebody(glyphs):
out.write(chunk)
if unicodemap is not None:
for chunk in _makeuctable(unicodemap):
out.write(chunk)
if __name__ == '__main__':
import sys
size = map(int, sys.argv[1].split('x'))
im = Image.open(sys.argv[2])
with open(sys.argv[3], 'r') as f:
r = csv.reader(f, delimiter='\t')
unicodemap = list(r)
if unicodemap[0][0] == '':
unicodemap[0][0] = '\u0000'
if unicodemap[255][0] == '\x20' and unicodemap[0x20][0] == '\x20':
unicodemap[255][0] = '\u00A0'
with gzip.open(sys.argv[4], 'wb') as f:
makepsf2(size, im, f, unicodemap)
datafiles
CP437 Unicode Table
""
☺
☻
♥
♦
♣
♠
•
◘
○
◙
♂
♀
♪ 𝅘𝅥𝅮
♫
☼
► ▶ ▸
◄
↕ ᛨ
‼
¶
§
▬
↨
↑ ᛏ
↓
→
←
∟
↔
▲
▼
" "
! ǃ ⵑ
""""
#
$
% ٪ ⁒
&
' ʻ ʹ ˈ ʹ ᑊ ꞌ
( ❲
) ❳
* ∗ 𐌟
+
, ¸ ؍ ‚ ꓹ
- ˗ ‐ ‑
. ܁ ܂ ․ ꓸ 𝅭
/ ᜵ ∕ 〳 𝈺
0
1
2
3 З Ӡ
4
5
6 б
7
8
9
: ː ˸ ։ ׃ ܃ ܄ ः ઃ ᛬ ᠃ ᠉ ⁚ ∶ ꓽ ꞉ ︰ :
; ;
< ᐸ 𝈶
=
> ᐳ 𖼿 𝈷
?
@
A Α А
B Β В
C Ϲ С
D
E Ε Е
F
G
H Η Н
I Ι І Ӏ
J Ј
K Κ К
L
M Μ М
N Ν
O Ο О
P Ρ Р
Q Ԛ
R
S Ѕ Ꚃ
T Τ Т
U
V
W Ԝ
X Χ Х
Y Υ Ү
Z Ζ
[
\
]
^ ˄ ˆ
_
`
a а
b
c с
d
e е
f
g
h һ
i і
j ј
k κ
l
m
n
o ο о
p р
q ԛ
r
s ѕ
t
u
v
w ԝ
x х
y γ у ү
z
{
| ӏ
}
~
⌂ 🏠
Ç
ü
é
â
ä ӓ
à
å
ç ς ҫ
ê
ë ё
è ѐ
ï ϊ ї
î
ì
Ä Ӓ
Å Å
É
æ ӕ
Æ Ӕ
ô
ö ӧ
ò
û
ù
ÿ ӱ
Ö Ӧ
Ü
¢
£
¥
₧
ƒ
á
í
ó
ú
ñ
Ñ
ª
º
¿
⌐
¬
½
¼
¡
«
»
░
▒
▓
│
┤
╡
╢
╖
╕
╣
║
╗
╝
╜
╛
┐
└
┴
┬
├
─
┼
╞
╟
╚
╔
╩
╦
╠
═
╬
╧
╨
╤
╥
╙
╘
╒
╓
╫
╪
┘
┌
█
▄
▌
▐
▀
α
ß β
Γ Г Г
π
Σ
σ
µ μ
τ ꚍ
Φ Ф
Θ Ѳ Ө
Ω Ω
δ
∞ ꚙ
φ
ε є ɛ
∩
≡ Ξ
±
≥
≤
⌠
⌡
÷
≈
°
∙
· 𐩐 ٠ ۰
√
ⁿ
²
■
" "
x1252 Unicode Table
○
■
↑ ᛏ
↓
→
←
║
═
╔
╗
╚
╝
░
▒
► ▶ ▸
◄
│
─
┌
┐
└
┘
├
┤
┴
┬
♦
┼
█
▄
▀
▬
" "
! ǃ ⵑ
""""
#
$
% ٪ ⁒
&
' ʻ ʹ ˈ ʹ ᑊ ꞌ
( ❲
) ❳
* ∗ 𐌟
+
, ¸ ؍ ꓹ
- ˗ ‐ ‑
. ܁ ܂ ․ ꓸ 𝅭
/ ᜵ ∕ 〳 𝈺
0
1
2
3 З Ӡ
4
5
6 б
7
8
9
: ː ˸ ։ ׃ ܃ ܄ ः ઃ ᛬ ᠃ ᠉ ⁚ ∶ ꓽ ꞉ ︰ :
; ;
< ᐸ 𝈶
=
> ᐳ 𖼿 𝈷
?
@
A Α А
B Β В
C Ϲ С
D
E Ε Е
F
G
H Η Н
I Ι І Ӏ
J Ј
K Κ К
L
M Μ М
N Ν
O Ο О
P Ρ Р
Q Ԛ
R
S Ѕ Ꚃ
T Τ Т
U
V
W Ԝ
X Χ Х
Y Υ Ү
Z Ζ
[
\
]
^
_
`
a а
b
c с
d
e е
f
g
h һ
i і
j ј
k κ
l
m
n
o ο о
p р
q ԛ
r
s ѕ
t
u
v
w ԝ
x х
y γ у ү
z
{
| ӏ
}
~
€
‚
ƒ
„
…
†
‡
ˆ ˄
‰
Š
‹
Œ
Ž
‘
’
“
”
•
–
—
˜
™
š
›
œ
ž
Ÿ
¡
¢
£
¤
¥
¦
§
¨
©
ª
«
¬
""
®
¯
°
±
²
³
´
µ μ
¶
·
¸
¹
º
»
¼
½
¾
¿
À
Á
Â
Ã
Ä Ӓ
Å Å
Æ Ӕ
Ç
È
É
Ê
Ë
Ì
Í
Î
Ï
Đ
Ñ
Ò
Ó
Ô
Õ
Ö
×
Ø
Ù
Ú
Û
Ü
Ý
Þ
ß
à
á
â
ã
å
ä ӓ
æ ӕ
ç ς ҫ
è ѐ
é
ê
ë
ì
í
î
ï
ð ∂
ñ
ò
ó
ô
õ
ö
÷
ø
ù
ú
û
ü
ý
þ
ÿ



Might have to reverse-engineer the format https://gitlab.freedesktop.org/xorg/app/fonttosfnt