How to generate font and picture header files
posted Sep 29th 2009 1:00pm by Mike Szczysfiled under: tool hacks

Displaying custom fonts or images on an LCD screen using a microcontroller usually requires quite a bit of work. We’ve used some readily available tools to make this a bit easier for your next project. Our python script will convert BMP files into a header file ready for use with AVR microcontrollers. We’ll walk you through it after the break.
For this tutorial we will be using the GNU Image Manipulation Program in conjunction with Python. We are working on an Ubuntu 9.04 system but because these are cross-platform tools you should be able to do this on any OS.
What the script does:
The Python script takes one or more 1-bit color palette indexed BMP images, cuts out the header and any unused column data, and outputs a header file with the information stored in a one dimensional array in PROGMEM. This data can then be read out of the array and manipulated in the AVR code for use in whatever format you need for your display. This can be used for generating fonts, or converting larger images.
Generate the BMP files:

Open the GIMP and create a new file with the dimensions that you require. Height is up to you, but the width should be in multiples of 8 to correspond to the 8-bit wide storage scheme. In this case, we’re interested in generating a set of fonts that will display in a 24×30 pixel area.

Using the font tool, select your desired font and add your character. Adjust the size and location until if fills the canvas. You should make sure that the Antialiasing checkbox of the font tool is not selected.

BMP files are saved from bottom to top, we need to invert the image for our purposes. Do this by clicking the Image menu, go to Transform, and select “Flip Vertically”. We also need to make this an indexed image. To do so, click on the Image menu at the top, go to Mode and select “Indexed…”. From this menu, choose “Use black and white(1-bit) palette”. Now save the file as a BMP image. In our case, we saved it as 4.bmp. Repeat this for each character you wish to include in your new font header file.
Use the script:
Download our bmp2header.py file.
$ python bmp2header.py *.bmp Please enter how many bytes (8-bits) wide the image data needs to be: 3 Generating header file with a byte width of: 3 bytes Successfully generated: my_header.h
Run the file, with your BMP images as the command line arguments. You will be asked to input the desired column width for the images. Our example image is 24 pixels wide so we want header data to be 3 bytes wide (24-pixels/8-bits = 3 bytes). You can see from the output that my_header.h was successfully created by the script.
Here are the contents of that file (in this case, data for the ’4′ character):
#include <avr/pgmspace.h>
static const char PROGMEM my_header[]={
//4
0x1f, 0x00, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x80, 0x00,
0x3f, 0x81, 0xfc,
0x3f, 0x81, 0xfc,
0x3f, 0x81, 0xfc,
0x3f, 0xff, 0xfc,
0x3f, 0xff, 0xfc,
0x3f, 0xff, 0xfc,
0x3f, 0xff, 0xfc,
0x00, 0x01, 0xfc,
0x00, 0x01, 0xfc,
0x00, 0x01, 0xfc,
0x00, 0x01, 0xfc,
0x00, 0x01, 0xfc,
0x00, 0x01, 0xfc
};
In the header file, each BMP that is processed by the script will have its filename appended as a comment before the HEX output. Our data for 4.bmp is displayed in 3 columns of bytes with 30 rows. This matches up with the 24×30 aspect ratio we were looking for. If you have an output much larger than this, you either didn’t used a 1-bit indexed image, or something when wrong when the script asked you to input your column width.
Accessing data from the header file:
Covering how to use this header data is beyond the scope of this tutorial. Below is the code we used to write to the display in the image at the top of this article. Our screen is written to by declaring the area we want to write to, then sending a stream of bit data for that area. We provide this for reference purposes only:
#include my_header.h
void Other_Num(unsigned char num, unsigned char x, unsigned char y)
{
//Setup screen area for writing:
LCD_Out(0x2A, 1);
LCD_Out(x, 0);
LCD_Out(x+23, 0);
LCD_Out(0x2B, 1);
LCD_Out(y, 0);
LCD_Out(y+29, 0);
LCD_Out(0x2C, 1);
unsigned char temp;
for (unsigned char i=0; i<90; i++) //Read one column of char at a time
{
temp = pgm_read_byte((char *)((int)my_header + (i + (90*num)))); //Get column from progmem
for (unsigned char k=0; k<8; k++)
{
if (temp & 1<<(7-k)) LCD_Out(blue, 0);
else LCD_Out(white, 0);
}
}
}
Conclusion
Using this method make generating font sets quit a bit easier. We were able to generate five different numeric sets (0-9) in about 45 mintues. We hope this helps with your next project. Don’t forget to include pictures of your new fonts in the comments.








Just curious, does anyone use the GIMP option to export C code/headers? If so, what are your thoughts on these two methods?