Files
LoLshield/extras/font_generator.py
T

154 lines
4.3 KiB
Python
Executable File

#!/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()