1 | #!/usr/bin/env python |
---|
2 | # |
---|
3 | # "Compile" a font image into a C include file containing the binary |
---|
4 | # representation of the font, ready for displaying. |
---|
5 | # |
---|
6 | |
---|
7 | import sys |
---|
8 | |
---|
9 | # Fix the PYTHONPATH for scons builds. |
---|
10 | if sys.platform == 'darwin': |
---|
11 | sys.path.append('/opt/local/lib/python2.5/site-packages') |
---|
12 | |
---|
13 | try: |
---|
14 | from PIL import Image |
---|
15 | except ImportError: |
---|
16 | print "ERROR: Python Imaging Library required for font generation." |
---|
17 | sys.exit(2) |
---|
18 | |
---|
19 | |
---|
20 | class Font(object): |
---|
21 | def __init__(self, font_file): |
---|
22 | # Extract the character size from the filename |
---|
23 | size = font_file.split('.')[-2] |
---|
24 | y, x = size.split('x') |
---|
25 | try: |
---|
26 | self.charx = int(x) |
---|
27 | self.chary = int(y) |
---|
28 | if self.chary != 8: |
---|
29 | raise ValueError |
---|
30 | except ValueError: |
---|
31 | print "ERROR: unparseable font size %s" % size |
---|
32 | sys.exit(1) |
---|
33 | |
---|
34 | # Open the image and check that its dimensions make sense |
---|
35 | self.img = Image.open(font_file).convert('1') |
---|
36 | |
---|
37 | if ((self.img.size[0] % self.charx) != 0 or |
---|
38 | (self.img.size[1] % self.chary) != 0): |
---|
39 | print "ERROR: Font image for %s font has non-multiple dimensions" % size |
---|
40 | sys.exit(1) |
---|
41 | |
---|
42 | # Remember how many font char rows and cols there are |
---|
43 | self.rows = self.img.size[1] / self.chary |
---|
44 | self.cols = self.img.size[0] / self.charx |
---|
45 | |
---|
46 | def _get_block_coords(self, x, y): |
---|
47 | return (x * self.charx, |
---|
48 | y * self.chary, |
---|
49 | (x+1) * self.charx, |
---|
50 | (y+1) * self.chary) |
---|
51 | |
---|
52 | def _byteify(self, scanline): |
---|
53 | byte = 0 |
---|
54 | for x in xrange(8): |
---|
55 | if not scanline[x]: # Invert the value to get the correct |
---|
56 | # NXT encoding. |
---|
57 | byte |= 1 << x |
---|
58 | return byte |
---|
59 | |
---|
60 | def chars(self): |
---|
61 | for y in xrange(self.rows): |
---|
62 | for x in xrange(self.cols): |
---|
63 | block_coords = self._get_block_coords(x, y) |
---|
64 | font_block = list(self.img.crop(block_coords).getdata()) |
---|
65 | scanlines = [] |
---|
66 | for x in xrange(len(font_block)/self.charx): |
---|
67 | scanlines.append(font_block[x*self.charx:(x+1)*self.charx]) |
---|
68 | scanlines = zip(*scanlines) |
---|
69 | yield [self._byteify(l) for l in scanlines] |
---|
70 | |
---|
71 | def main(): |
---|
72 | if len(sys.argv) != 4: |
---|
73 | print "Usage: %s <font file> <template file> <output file>" |
---|
74 | sys.exit(1) |
---|
75 | |
---|
76 | font_file = sys.argv[1] |
---|
77 | template_file = sys.argv[2] |
---|
78 | output_file = sys.argv[3] |
---|
79 | |
---|
80 | font = Font(font_file) |
---|
81 | |
---|
82 | font_chars = [] |
---|
83 | for scanlines in font.chars(): |
---|
84 | font_chars.append(', '.join(['0x%02X' % x for x in scanlines])) |
---|
85 | font_data = '\n '.join(['{ %s },' % c for c in font_chars]) |
---|
86 | |
---|
87 | f = open(template_file) |
---|
88 | template = f.read() |
---|
89 | f.close() |
---|
90 | |
---|
91 | template = template.replace( |
---|
92 | '@@FONT_SIZE@@', '%dX%d' % (font.chary, font.charx)) |
---|
93 | template = template.replace('@@FONT_WIDTH@@', '%d' % font.charx) |
---|
94 | template = template.replace('@@FONT_DATA@@', font_data) |
---|
95 | |
---|
96 | f = open(output_file, 'w') |
---|
97 | f.write(template) |
---|
98 | f.close() |
---|
99 | |
---|
100 | if __name__ == '__main__': |
---|
101 | main() |
---|