In Part 1 of this series, I gave a brief overview of the various font formats, kerning data, and how they are handled in XNA. In Part 2, I’d like to talk about my solution, and what was required to make it work.
To reiterate from my previous post, the basic goal of my font kerning project was to extract horizontal kerning data from font files of various formats, and save it in an organized, easily usable format.
The first step was to get my hands on a tool that could extract the raw data from a font file. It took a surprising amount of digging, but I finally stumbled across a program called “ttx.cmd”, which is a simple command line program contained within the Adobe Font Developer Kit for Open Type (AFDKO). This tool dumps out a raw xml file with all kinds of kerning and style data. You can see from the screenshot below that my tool requires the AFDKO to be installed on your machine.
The next step was making sense of the output, and converting it into a format that could be easily consumed from within XNA. This was the tricky part. In order to explain this fully, you’ll need some basic background on how kerning values are stored within font files.
How Kerning Values are Stored:
- Over time, the way fonts are built have changed. Previously, fonts used a KERN table. This table held all of the necessary kerning information for each font. However, a newer GPOS table is now used in most newer fonts. It’s also possible that both a KERN and a GPOS table can exist in a single font.
- The initial font I was trying to use for the first Ryamar game was LithosPro-Regular.otf. This contained a GPOS table only. Therefore, as of July 9, 2013, my FontKernalizer only supports the GPOS table parsing, and this web page will primarily talk about the GPOS table.
How to Extract the KERN or GPOS Table:
- Various font programs have the ability to read these tables. Font Lab Studio 5 was the best program I could find. However, the data it provided was not easily parsable, and I was restricted in what I could access and how I could automate the parsing process.
- The best method for obtaining kerning data is to use “ttx.cmd”, which is a simple command line program contained within the Adobe Font Developer Kit for Open Type (AFDKO).
- This program can be run from the command line on any .ttf or .otf font file, and can output all font data into xml files. The data provided by this tool includes much more than simply the kerning data. It can output all tables (GSUB, etc). You can run ttx.cmd on the font file to see what tables are available, and you can specify which ones you want to dump to an xml file. For more information on the AFDKO and all of the tools included, see the AFDKO overview page.
How to Read the GPOS Table:
- The overviews below give great information about the table. The adobe document is complex, but very helpful.
- http://partners.adobe.com/public/developer/opentype/index_table_formats2.html
- http://fontforge.org/gposgsub.html
Putting it all together
Once I understood how to read the data dump, I was able to parse the xml and massage the data into a more usable format. After that, the final piece of the puzzle was to convert the Adobe glyph name to both a windows character number and a unicode value. This was done using the Adobe Font Glyphs Chart. Note that there are two charts – an older one and a newer one. The FontKernalizer program supports both.
It was a long journey, but I was finally able to create an xml file that looked something like this:
- <Glyph>
- <Character>65</Character>
- <CharacterAsReadableString>A</CharacterAsReadableString>
- <GlyphString>A</GlyphString>
- <UnicodeNumericValue>0041</UnicodeNumericValue>
- <CoverageOffset>0</CoverageOffset>
- <Class1Index>4</Class1Index>
- <Class2Index>77</Class2Index>
- </Glyph>
- <Glyph>
- <Character>198</Character>
- <CharacterAsReadableString>Æ</CharacterAsReadableString>
- <GlyphString>AE</GlyphString>
- <UnicodeNumericValue>00C6</UnicodeNumericValue>
- <CoverageOffset>0</CoverageOffset>
- <Class1Index>0</Class1Index>
- <Class2Index>77</Class2Index>
- </Glyph>
- <Glyph>
- <Character>193</Character>
- <CharacterAsReadableString>Á</CharacterAsReadableString>
- <GlyphString>Aacute</GlyphString>
- <UnicodeNumericValue>00C1</UnicodeNumericValue>
- <CoverageOffset>0</CoverageOffset>
- <Class1Index>4</Class1Index>
- <Class2Index>77</Class2Index>
- </Glyph>
The classes were stored later in the file, and looked something like this:
- <GlyphClass1List>
- <GlyphClass1>
- <Index>0</Index>
- <GlyphClass2>
- <Index>4</Index>
- <XAdvance>32</XAdvance>
- </GlyphClass2>
- </GlyphClass1>
- </GlyphClass1List>
Success! I serialized the entire thing as xml, and was easily able to load it up within my XNA project. All I had to do in XNA was draw each character one at a time, and check the surrounding characters to see if an adjustment needed to be made. Awesome.
- float horizontalOffset = GetKerningPair(char firstChar, char secondChar).xadvance;
Although the FontKernalizer accomplished what I needed it to, there were still a lot of unsupported features:
Reading that list leaves me feeling bittersweet. Ultimately, the FontKernalizer was only a partial success. I certainly learned a lot, but if I could do everything over again, I would have put some more effort into researching a tool like FreeType. Fonts are a complex beast. Don’t make the mistake I did and assume something that sounds simple, like retrieving a font’s kerning data, will truly be an easy task.
Part 1 | Part 2