Ticket #21970: generate_fonts.py

File generate_fonts.py, 3.1 KB (added by tcwan (TC Wan), 15 years ago)

Python script which generates font definitions requiring PIL

Line 
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
7import sys
8
9# Fix the PYTHONPATH for scons builds.
10if sys.platform == 'darwin':
11    sys.path.append('/opt/local/lib/python2.5/site-packages')
12
13try:
14    from PIL import Image
15except ImportError:
16    print "ERROR: Python Imaging Library required for font generation."
17    sys.exit(2)
18
19
20class 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
71def 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
100if __name__ == '__main__':
101    main()