For those interested in the workings of a modern font engine, be aware that this is a simplified model. As such you should probably see Freetype's documentation on glyphs.

Fonts of Variable Width

Variable width fonts are one of many things that make a graphical interface more pleasant to use. Instead of taking as much horizontal space for an "i" or a "w", each character takes a width corresponding to its shape. Additionally, specific character combinations can be further adjusted by a process called kerning. Kerning allows a "V" to come close to an "A", but sit further away from a "Y".

Corner, Left, Width, and Advance

A font image stores a bunch of consecutive letters, all squished together. Arialbd16 looks like this, when magnified:

To get to the beginning (upper-left corner) of each character, we have to look up a pixel offset, which we call Corner.

Each character in one of our fonts has three more numbers describing it and it alone. It has a width which describes the size of the character in our source image. It has a left margin, which tells us how far from the previous character's right margin we need to move. And it has a distance from the left margin which we should advance to get to the right margin.

Left, Width, Advance values for ArialBD16 'c' through 'm'
LetterLeftWidthAdvance
c179
d1810
e189
f065
g0910
h1810
i124
j-144
k189
l124
m11214

[Zoom by 2x or 4x]

This rendering of the string "cdefghijklm" shows what these values really mean. Each vertical red line represents a base position of a letter. The distance from it to the next blue line is the left margin of a letter. The left margin is indicated with green arrows. Each pair of vertical blue lines represents a width of a letter. The width is indicated with purple arrows. Each pair of red vertical lines also represents the advance for the letter they surround. The advance is indicated with light-blue arrows.

Note that the left margins of 'f' and 'g' are zero, (light green arrows) and 'j' is negative (orange arrows). This does indicate no movement, and leftwards movement, respectively. Further note that in all cases, the advance value is applied from the base position (red lines), even in the case of 'j' and its negative left margin.

Width tells you the size of the rectangle to copy from the source image but Advance tells you how big the rectangle it takes in the destination image. For example, 'l' has a width of 2 pixels, which allows you to pull the 'l' out but not grab the 'k' or the 'm'. Then its Advance of 4 pixels gives it some breathing room.

The Width of 'f' is greater than its Advance, and thus the rectangles for 'f' and 'g' overlap ('g' has a Left of 0). This has the opposite effect, effectively taking away some room on the right side of the 'f'. None of these special cases listed here require special casing in the code. Instead they make good cases to check to verify a properly working implementation.

All this information is stored in the font data file, discussed below

Kerning

Kerning is a method of fine-tuning character positions. While the above use of Left, Width, and Advance will allow you to draw a perfectly usable string, there are often cases where considerable improvement is possible. Within a given letter's Width-wide rectangle, there is often unused space. For example, the upper-left and upper-right corners of an 'A', the lower-left and lower-right corners of a 'V' or a 'T', or the upper area of most lowercase characters.

When corresponding unused space exists in adjacent letters, the second letter can be brought in towards the first. The characters "AV" can be drawn closer together than the characters "AA" in many fonts. In this case the entry for "AV" might hold a value like -2, and when drawing a 'V' after an 'A', this -2 should be added to the starting location for 'V'. Unlike the Left-margin, this moves the entire character and all subsequent characters over.

Since this information is also font-specific, it is also stored in the font data file.

Anti-aliasing

Now that characters are being positioned as ideally as possible, there is one last thing to address: sub-pixel outlines. The above images have a lot of grey pixels. At such a large size, they look ugly, but at their original size, they help maintain the readibility of each letter.

This information is stored in the alpha channel of the font image. When the alpha channel is 255, the pixel is at full intensity. When it's 0, the pixel is transparent, and the original destination pixel should be used. When it's anywhere inbetween, the color is linearly interpolated between the full intensity pixel of our desired font color and the original destination pixel, just like alpha compositing.

The trick here is to run an alpha composition of the font's alpha channel and the desired RGB for this character or string, with the destination pixel's RGB (destination alpha is always ignored).

Font Data

The information necessary to implement all the above kerning is stored in a companion file. The files arialbd16.png and arialbd16.dat hold the font image, and font data respectively. The image is a horizontal juxtaposition of all characters, like the subset above. The data file has three sections:

The image itself is a series of dwords, each holding an RGBA value (R[ed] in the lowest byte, A[lpha] in the highest byte), organized with consecutive rows following eachother like the graphics screen is organized. The equation Offset=[_FontOff]+(Row*Width+Column)*DataSize will be used often.

The above position values are all signed, and assume that the font data file has been loaded into memory at offset [_FDatOff], and the font image file has been loaded at offset [_FontOff].

Available Fonts

Pregenerated fonts in this format (PNG with accompanying DAT files) are available in varfont.zip (897k), which by default expands all files in its current directory. It has Arial, Courier New, Georgia, Times New Roman, and Verdana in plain, bold, and italic styles in the font-heights 12, 16, 24, and 32 pixels. Note that the font-height is not the height of the corresponding image.