/
font_generator.py
executable file
·153 lines (128 loc) · 4.33 KB
/
font_generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
# This program by Adam Mayer
# http://www.nycresistor.com/2010/03/22/march-madness-backlog-microcontroller-pixel-font/
from PIL import Image
from optparse import OptionParser
from string import Template
import sys
# pngToFont takes a simple 1-bit image of a pixel font
# and converts it to a chunk of C code that we can use
# in microcontroller code.
# Edit this to reflect the order that characters appear
# in your font. Each character should be seperated by
# one column of white pixels.
char_order = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.!?@/:;()"
# Header and types for font.
# We're a little tight on space, so it's program memory
# for you. Hooray for Harvard architectures.
font_header_templ = Template("""
#include <stdint.h>
#include <avr/pgmspace.h>
typedef struct {
uint8_t offset;
uint8_t len;
} PROGMEM char_entry;
#define FONT_HEIGHT $height
#define FONT_DATA_SIZE $data_size
extern char_entry font_table[128];
extern prog_uint8_t font_data[FONT_DATA_SIZE];
uint8_t get_char_len(uint8_t c);
uint8_t get_char_bit(uint8_t c, uint8_t row, uint8_t column);
""")
font_source_templ = Template("""
#include "$header"
char_entry font_table[128] PROGMEM = {
$font_table
};
prog_uint8_t font_data[FONT_DATA_SIZE] PROGMEM = {
$font_data
};
uint8_t get_char_len(uint8_t c) {
return pgm_read_byte(&(font_table[c].len));
}
uint8_t get_char_bit(uint8_t c, uint8_t row, uint8_t column) {
uint8_t offset = pgm_read_byte(&(font_table[c].offset));
uint8_t col = pgm_read_byte(&(font_data[offset+column]));
return ((col & _BV(row)) == 0)?0:1;
}
""")
def get_column(im,x_offset):
"Get the bitmap column as an int, with black pixels as 1"
(_, height) = im.size
val = 0
for bit in range(height):
if im.getpixel((x_offset,bit)) == 0:
val = val | (1 << bit)
return val
class Character:
def __init__(self,im,x_offset):
self.len = 0
self.seeklen = 0
self.columns = []
column = get_column(im,x_offset)
# Skip leading whitespace
while column == 0:
x_offset = x_offset + 1
column = get_column(im,x_offset)
self.seeklen = self.seeklen + 1
while column != 0:
self.columns.append(column)
self.len = self.len + 1
self.seeklen = self.seeklen + 1
x_offset = x_offset + 1
column = get_column(im,x_offset)
charmap = {}
def png_to_font(im,c_path,h_path):
c_file = open(c_path,"w")
h_file = open(h_path,"w")
x_offset = 0
data_size = 0
# load all the characters from the image file
for char in char_order:
charmap[char] = Character(im,x_offset)
x_offset = x_offset + charmap[char].seeklen + 1
data_size = data_size + charmap[char].len
print "Char " + char + " is len " + str(charmap[char].len) + ", but took " + str(charmap[char].seeklen)
# write out the header
h_file.write(font_header_templ.substitute(
count=len(char_order),
data_size=data_size,
height=im.size[1]))
h_file.close
# build the tables
font_data = ""
font_table = ""
offset = 0
for i in range(128):
char = chr(i)
if charmap.has_key(char):
c = charmap[char]
c.offset = offset
font_table = font_table + " {%d, %d},\n" % (offset,c.len)
font_data = font_data + ",\n".join(map(hex,c.columns)) + ",\n"
offset = offset + c.len
else:
font_table = font_table + " {0,0},\n"
# write out the source
c_file.write(font_source_templ.substitute(
font_table = font_table,
font_data = font_data,
header=h_path))
c_file.close()
def main():
parser = OptionParser(usage="usage: %prog [options] source")
parser.add_option("-o","--output",dest="out_path",
help="output to given base path")
(options,args) = parser.parse_args()
if len(args) != 1:
parser.error("Please provide a single input file.")
image = Image.open(args[0])
image = image.convert("L")
c_path = "font.cpp"
h_path = "font.h"
if (options.out_path):
c_path = options.out_path + ".c"
h_path = options.out_path + ".h"
png_to_font(image,c_path,h_path)
if __name__ == "__main__":
main()