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.

Comments

  1. Jon says:

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

  2. svofski says:

    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.

  3. svofski says:

    Err… I meant “…the pixel packing isn’t always the one that’s required…”

  4. robmora says:

    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.

  5. Roman D says:

    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.

  6. nes says:

    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.

  7. Peter says:

    For Windows, a program called The Dot Factory does something very similar to this.

  8. AVR Freak says:

    Thanks for this detailed tutorial!

  9. Grumpy says:

    Microchip provides a nice little tool in his Graphics Library that converts normal TTF fonts to C arrays or even assembler.

    You just have to decide the height and then doing copy&paste.

  10. MrX says:

    @Jon
    @svofski

    Indeed. GIMP works perfectly for me.

  11. M4CGYV3R says:

    I don’t know if what you’re programming on has object-oriented capabilities, but static variable arrays are the devil.

  12. sneakypoo says:

    I’ll get on this as soon as I can get my LCD to display proper colours :(

  13. xchip says:
  14. robmora says:

    Since the posts asks for pics I figured I’d post some samples of mine (using a different process however).

    That’s blown up to double size, 4 fonts in total (the last two are different sizes of the same font).

  15. Harvie says:

    Have you ever heard about XPM? You can include it into the C code.

    http://en.wikipedia.org/wiki/X_PixMap

    gimp supports it, just click “save as” and type image.xpm to output filename form…

  16. For those with a Windows box, FontMaker is a free download. It does a nice job converting TrueType fonts and/or bitmaps (including grids of characters) in AVR-GCC C headers:

    http://www.eurekelettronica.it/prodotti/touch8/download/download.htm

  17. ben nguyen says:

    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!

  18. Kiril Zyapkov says:

    An export procedure for the Nokia 3310 LCD:

    http://1024.cjb.net/2009/11/graphics-nokia-3310-lcd-avr/

  19. Kevin says:

    This is a very late reply to this thread but it might help someone….checkout this Python plug-in for the gimp:

    http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/67340.aspx

    It creates a C header for a gimp image and its quite easy to modify this to output any format you like.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 93,919 other followers