Thursday, 10 November 2011

Using unix consolefonts in your programs

If you're running linux or another unix-style system, then you probably have a little-known directory in '/usr/share/consolefonts'.

This contains 'font files' that can be used with the 'setfont' command to change the default font at the linux console (not on xterm or rxvt or anything like that, at the actual 'text mode' console). If you're looking for how to do that, it's as simple as:

setfont drdos8x16
setfont cybercafe

where the 'name' of the font is it's filename without path or extensions (setfont knows to look in /usr/share/consolefonts).

This post is about how to decode these font-files for use in your own graphics programs.

These fonts have a very simple format, being little more than a collection of bitmaps (not .bmp format, but actual bitmaps, i.e. collections of bytes where every bit is a monocrhome 'pixel' that's on or off). If you're messing about with low-level graphics, they are an easy way of doing text.

There's 3 types of font in the console font directory.

1: Raw Fonts

These usually have the file extension '.fnt' (or .fnt.gz if gzipped). They contain an array of 8x16 bitmaps, or 'glyphs' of the characters in the font. The bitmaps are arranged so that they map to the ascii character set, so to find the bitmap for ascii character 'A' which has an ascii value of 65, you would just get the 65th bitmap in the array. As each character is 8x16, and so 16 lines of 8 bits, or 16 bytes, so you just calculate the position in the bitmap array as '<ascii value> * 16'.

Thus, the first byte of the file is the first 'line' of 8 pixels in the first character. For each bit that is set in those eight bytes, you should set or 'color' a pixel in an image, and leave blank those pixels that match to unset bits in the byte. The second byte is the second line of the character, and so on.

2: PSF Fonts

These are very similar to 'Raw' fonts, except they have a header. This header starts:

Byte 0: 0x36
Byte 1: 0x04
Byte 2: 'Mode' (256 characters or 512 characters)
Byte 3: Character Height

The first two bytes are just for identifiying the file type, and the 'Mode' byte says how many characters are stored in the font-file. If the first bit of this byte is set, then there are 512 characters, otherwise it's 256. The final header byte is the character height, allowing you to have glyphs that are 8x8, or 8x12 or 8x128, or whatever. Notice though, that for basic PSF fonts, the width of the character is still always 8 bits, or one byte.

After this 4-byte header the font is just the same as 'raw' fonts, except you have to consider that each glyph is as many bytes long as the 'Character Height' setting says.

3: PSF2 Fonts

The most advanced type of console font, it seems, are an extended version of 'PSF' fonts, called 'PSF2' fonts. These have an enhanced header:

Byte0: 0x72
Byte1: 0xb5
Byte2: 0x4a
Byte3: 0x86
unsigned int version;
unsigned int headersize; /* offset of bitmaps in file */
unsigned int flags;
unsigned int length; /* number of glyphs */
unsigned int charsize; /* number of bytes for each character */
unsigned int charheight;
unsigned int charwidth;

After the first 4 identifying bytes all the information is unsigned 4-byte integers. Everything does pretty much what it says. As now both the character width and character height can change, so you can no-longer calculate glyph positions in the file with 'lines * NoOfLines', but you can use the helpful 'charsize' value. Thus the glyph bitmap for a given character is found at 'headersize + <ascii value> * charsize'. 'length' tells you how many characters are in the file, and 'charwidth' now means you have to consider that each line of a character might use less than one byte, or stray across two or more bytes. However, the bitmap data is padded to a byte boundary, so if a font has a width of '12', or 'a byte and a half' it will still use 2 bytes for every line in every character.

Some of the default fonts distributed with the linux 'kbd' package (arm8.fnt, cybercafe.fnt) look surprisingly good when used on charts and the like, and they're about the easiest font-type to use in your own programs without turning to libraries like 'Freetype'.

No comments:

Post a Comment