How To Generate Font And Picture Header Files

custom_fonts_displayed

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:

create_new_image

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.

centering_character

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.

indexed_bmp

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.

19 thoughts on “How To Generate Font And Picture Header Files

  1. Jon, I use GIMP option to export C code/headers. It’s more useful than anything because unlike anything, GIMP and C compiler are always at hand. The pixel packing the one that’s required, but writing a code that rearranges a few bits is faster than finding the right tool that does it out of the box.

  2. I’ve never really looked at how all the standard file formats are structured so I never really paid attention to what the convention was, but I thought it was odd that the data was packed to a row of 8 columns. When I did my own stuff like this I’d structure it with packed columns, so that you ended up with heights that were a multiple of 8. I figured that was more intuitive especially considering that’s how most LCD drivers are set up, but admittedly I can see some advantages to both.

  3. I used the “LCD Font Maker” but it still has some issues that irritated me. It was a useful tool though when I had to change LCD but wanted to use the old fonts, the controller on the new LCD took data in funky format also. Coordinates ware from bottom left to top right and ware offset a few pixel’s so bottom 0,0 was infact 4,2. In the end I still ended up touching up the fonts manually editing the hex tables. Specially when your doing gray-scale. It’s just impossible to truly represent what it will look like on the LCD looking at CRT monitor or even another LCD monitor. It might look ok on the monitor and then proceeds to look like @$$ on the LCD.

  4. This is good but I think ImageMagick or GraphicsMagick can be made to do this and either will handle just about any image format. And with these, you can rasterise any font installed on your system. You might still need a bit of script to format it neatly as a header/.asm table and to pack your paletized colors, but you won’t be limited to just bmp’s.

  5. Anyone know if a utility exists that can output a 16-bit rgb (5-6-5 format) hex file from a bmp image?

    The only utilities I’ve been able to find either output a c header (not a binary hex file suitable for flashing), or they don’t support 5-6-5 rgb!

Leave a Reply to xchipCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.