Each font in a .fon file is one FONT resource (see
NE container), and a .fnt file
is the same data on its own. It holds one face at one size: a header, a character table
with each glyph’s width and position, the glyph data, and the face name. All numbers are
little-endian, and offsets count from the start of the resource (or of the
.fnt file). Microsoft documented the format in its Windows 3.x SDK and
Device Development Kit; version 2.0 is used by Windows 2.x and 3.x fonts, and version
3.0 added 32-bit offsets for fonts over 64 KB.
Header
Version 2.0 headers are 118 bytes; version 3.0 adds six fields, making 148.
| Offset | Size | Name | Meaning |
|---|---|---|---|
0 | 2 | dfVersion | 0x0200 for version 2.0, 0x0300 for 3.0. |
2 | 4 | dfSize | Size of the whole font in bytes. |
6 | 60 | dfCopyright | Copyright text, padded with zeros. |
66 | 2 | dfType | Raster or vector, and how the font is held. |
68 | 2 | dfPoints | Nominal size in points. |
70 | 2 | dfVertRes | Vertical resolution the font was designed for, dots per inch. |
72 | 2 | dfHorizRes | Horizontal resolution, dots per inch. |
74 | 2 | dfAscent | Distance from the top of the character cell to the baseline, in pixels. |
76 | 2 | dfInternalLeading | Space for accents inside the cell height (may be 0). |
78 | 2 | dfExternalLeading | Extra space the application should add between lines (may be 0). |
80 | 1 | dfItalic | Bit 0 set for an italic font. |
81 | 1 | dfUnderline | Bit 0 set for an underlined font. |
82 | 1 | dfStrikeOut | Bit 0 set for a struck-out font. |
83 | 2 | dfWeight | 1 to 1000; 400 regular, 700 bold (see weights). |
85 | 1 | dfCharSet | Character set. |
86 | 2 | dfPixWidth | Raster: width of every glyph if the font is fixed-width, or 0 if widths vary. Vector: width of the grid the glyphs were drawn on. |
88 | 2 | dfPixHeight | Raster: height of every glyph bitmap (the cell height). Vector: height of the grid. |
90 | 1 | dfPitchAndFamily | Bit 0 set if widths vary; bits 4 to 7 the family. |
91 | 2 | dfAvgWidth | Average glyph width; for a proportional font, the width of “X”. |
93 | 2 | dfMaxWidth | Width of the widest glyph. |
95 | 1 | dfFirstChar | First character code in the font. |
96 | 1 | dfLastChar | Last character code. |
97 | 1 | dfDefaultChar | Glyph to show for codes outside the font, counted from dfFirstChar. |
98 | 1 | dfBreakChar | The word-break (space) character, counted from dfFirstChar; normally 32 − dfFirstChar. |
99 | 2 | dfWidthBytes | Raster: bytes in one row of the whole font’s bitmap if all glyphs were laid side by side; always even. Not used for vector fonts. |
101 | 4 | dfDevice | Offset of the device name (a zero-terminated string), or 0 for a font usable on any device. |
105 | 4 | dfFace | Offset of the face name, a zero-terminated string. |
109 | 4 | dfBitsPointer | Filled in by Windows with the bitmap’s address when loaded; 0 in the file. |
113 | 4 | dfBitsOffset | Offset of the glyph data (or, if dfType bit 2 is set, a fixed memory address). |
117 | 1 | dfReserved | Not used. |
118 | 4 | dfFlags | Version 3.0: glyph format flags. |
122 | 2 | dfAspace | Version 3.0: A space (before the glyph) for the whole font. |
124 | 2 | dfBspace | Version 3.0: B space (the glyph itself) for the whole font. |
126 | 2 | dfCspace | Version 3.0: C space (after the glyph) for the whole font. |
128 | 4 | dfColorPointer | Version 3.0: offset of a colour table, or 0 for none. |
132 | 16 | dfReserved1 | Version 3.0: not used, 0. |
The character table follows at offset 118 (version 2.0) or 148 (version 3.0). Microsoft advised setting the version 3.0 fields to 0, and only the fixed and proportional glyph formats were ever supported.
Code values
dfType
| Bit | Meaning |
|---|---|
| 0 | 0 raster (bitmap) font, 1 vector (stroke) font. |
| 1 | Reserved, 0. |
| 2 | The glyph data is at a fixed memory address given by dfBitsOffset, not in the file. |
| 3 to 6 | Reserved, 0. |
| 7 | The font was realised by a device driver rather than by Windows. |
| 8 to 15 | For device drivers’ own use; 0 in ordinary fonts. |
Pitch and family
| Value of bits 4–7 | Family | Meaning |
|---|---|---|
0x00 | FF_DONTCARE | Unknown or no preference. |
0x10 | FF_ROMAN | Proportional, with serifs (MS Serif). |
0x20 | FF_SWISS | Proportional, without serifs (MS Sans Serif). |
0x30 | FF_MODERN | Fixed pitch (Courier, Terminal). |
0x40 | FF_SCRIPT | Like handwriting. |
0x50 | FF_DECORATIVE | Novelty fonts. |
Bit 0 is set when glyph widths vary (proportional) and clear for a fixed-pitch font.
MS Sans Serif, for example, has 0x21.
Character sets
| Value | Name | Value | Name |
|---|---|---|---|
| 0 | ANSI_CHARSET (Windows Western) | 161 | GREEK_CHARSET |
| 1 | DEFAULT_CHARSET | 162 | TURKISH_CHARSET |
| 2 | SYMBOL_CHARSET | 163 | VIETNAMESE_CHARSET |
| 77 | MAC_CHARSET | 177 | HEBREW_CHARSET |
| 128 | SHIFTJIS_CHARSET (Japanese) | 178 | ARABIC_CHARSET |
| 129 | HANGUL_CHARSET (Korean) | 186 | BALTIC_CHARSET |
| 130 | JOHAB_CHARSET (Korean) | 204 | RUSSIAN_CHARSET (Cyrillic) |
| 134 | GB2312_CHARSET (simplified Chinese) | 222 | THAI_CHARSET |
| 136 | CHINESEBIG5_CHARSET (traditional Chinese) | 238 | EASTEUROPE_CHARSET |
| 255 | OEM_CHARSET (the PC’s DOS code page) |
The values are those of the Windows CharacterSet list, which
LOGFONT and Windows metafiles use as well.
Weights
100 thin, 200 extra-light, 300 light, 400 normal, 500 medium, 600 semi-bold,
700 bold, 800 extra-bold, 900 heavy (the FW_ names of Windows).
dfFlags (version 3.0)
| Value | Name | Glyph format |
|---|---|---|
0x0001 | DFF_FIXED | Fixed-width glyphs. |
0x0002 | DFF_PROPORTIONAL | Proportional glyphs. |
0x0004 | DFF_ABCFIXED | Fixed-width with A, B and C spacing. |
0x0008 | DFF_ABCPROPORTIONAL | Proportional with A, B and C spacing. |
0x0010 | DFF_1COLOR | One bit per pixel, 8 pixels a byte. |
0x0020 | DFF_16COLOR | Four bits per pixel, 2 pixels a byte. |
0x0040 | DFF_256COLOR | One byte per pixel. |
0x0080 | DFF_RGBCOLOR | RGB quads. |
Character table
A raster font has one entry for each code from dfFirstChar to
dfLastChar, plus one more: (dfLastChar −
dfFirstChar) + 2 entries. The extra last entry describes a blank glyph
that is not part of the character set.
| Version and format | Entry | Size |
|---|---|---|
| 2.0 raster | uint16 geWidth, uint16 geOffset | 4 bytes |
3.0 DFF_FIXED, DFF_PROPORTIONAL | uint16 geWidth, uint32 geOffset | 6 bytes |
3.0 DFF_ABCFIXED, DFF_ABCPROPORTIONAL | geWidth, geOffset, then geAspace, geBspace, geCspace as 16.16 fixed-point values | not settled |
| 3.0 colour formats | geWidth, geOffset, uint16 geHeight, geAspace, geBspace, geCspace | not settled |
| Vector, fixed pitch | uint16 offset of the glyph’s strokes, with a final extra offset marking the end | 2 bytes |
| Vector, proportional | uint16 offset, uint16 width | 4 bytes |
geWidth is the glyph’s width in pixels (its advance) and
geOffset the offset of its bitmap from the start of the font. Microsoft’s
description of the ABC and colour entries is inconsistent about whether
geCspace is two or four bytes, and no font using them is known, so their
exact size is not stated here.
Raster glyphs
Each glyph is dfPixHeight rows tall and geWidth pixels
wide, stored column by column in strips 8 pixels wide:
- The first
dfPixHeightbytes are the leftmost 8 pixels of each row, from the top row down; the most significant bit is the leftmost pixel, and a set bit is a foreground pixel. - The next
dfPixHeightbytes are pixels 8 to 15 of each row, and so on, so a glyph takes ⌈width ÷ 8⌉ × height bytes. Unused bits on the right are 0. - Glyphs are stored one after another in character order.
Vector glyphs
A vector glyph is a list of pen movements in a cell of
dfPixWidth × dfPixHeight units, starting at the cell’s
top-left corner. Each movement is a signed x, y pair relative to the last point,
with x to the right and y downwards; the pen draws a line for each move. A pair
preceded by the value −128 (one-byte values) or −32768 (two-byte values) is a move
with the pen up. Values are one byte each unless dfPixHeight or
dfMaxWidth is over 128, when they are two bytes. A glyph’s length is the
difference between its offset and the next glyph’s.
Example
The first font in SSERIFEE.FON (MS Sans Serif for Central European
languages, Microsoft copyright 1987–98), whose resource starts at file offset
0x4A0:
000004A0 00 02 C3 0F 00 00 28 63 29 20 43 6F 70 79 72 69 ......(c) Copyri
…
000004E0 2E 00 00 00 08 00 60 00 60 00 0B 00 02 00 00 00 ......`.`.......
000004F0 00 00 00 90 01 EE 00 00 0D 00 21 05 00 0B 00 20 ..........!....
00000500 FF 61 00 E7 00 00 00 00 00 B5 0F 00 00 00 00 00 .a..............
00000510 00 FA 03 00 00 BD 03 00 FA 03 03 00 07 04 05 00 ................
| Offset | Bytes | Meaning |
|---|---|---|
0 | 00 02 | Version 2.0. |
2 | C3 0F 00 00 | 4,035 bytes long. |
66 | 00 00 | Raster font. |
68 | 08 00 60 00 60 00 | 8 points at 96 × 96 dpi. |
74 | 0B 00 02 00 00 00 | Ascent 11, internal leading 2, external leading 0. |
83 | 90 01 EE | Weight 400; character set 238, Central European. |
86 | 00 00 0D 00 21 | Proportional (width 0); 13 pixels tall; pitch and family 0x21, variable pitch, Swiss. |
91 | 05 00 0B 00 | Average width 5, widest glyph 11. |
95 | 20 FF 61 00 | Codes 32 to 255; default glyph 32 + 97 = 129; break character 32. |
99 | E7 00 | 231 bytes per font-wide row. |
101 | 00 00 00 00 B5 0F 00 00 | No device name; face name at 0xFB5, which reads “MS Sans Serif”. |
113 | FA 03 00 00 | Glyph data at 0x3FA = 1,018, right after the 118-byte header and 225 four-byte entries. The reserved byte after it happens to be BD. |
118 | 03 00 FA 03 | Code 32 (space): 3 pixels wide, bitmap at 0x3FA. |
122 | 03 00 07 04 | Code 33 (!): 3 wide, at 0x407, 13 bytes later. |
The entry for “A” (code 65, entry 33 at offset 250) is 07 00 B4 05: 7
pixels wide, at 0x5B4. Being under 8 pixels wide it takes one byte per
row, 13 bytes:
00 ........
00 ........
10 ...#....
10 ...#....
28 ..#.#...
28 ..#.#...
44 .#...#..
44 .#...#..
7C .#####..
82 #.....#.
82 #.....#.
00 ........
00 ........
The last of the 225 entries, after the one for code 255, is
08 00 A8 0F: the extra blank glyph, 8 pixels wide.