Aye, ye dinna ken kern

by Michael S. Kaplan, published on 2007/03/02 06:16 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2007/03/02/1786019.aspx

The question was deceptively simple:

I’m trying to use System.Drawing.Graphics.MeasureString to calculate kerning data, but the data I’m getting back isn’t what I’d expect.  Basically, the approach I’ve taken is to use MeasureString to calculate the length of character A, then character B, then AB  - the two of them put together.

Kerning = AB.width – A.width – B.width

When I do this, kerning is always 0.  Is there a parameter or state that I’m missing to set up kerning?  I’ve also tried using MeasureCharacterRanges, but with the same result.  I’m using times new roman font.

I’m trying to do a relatively simple hardware accelerated font system.  I’m using System.Drawing to render a set of characters from a font to a temporary bitmap, which is then copied into a hardware texture. 

When drawn, each character is drawn as two triangles using the correct part of the hardware texture. Each successive character is offset by the width of the previous character. I’d like the system to be able to handle kerning pairs, if possible, but I’m not sure what the best approach is to get this information. 


Clearly the developer asking gave no indication that he was a Scotsman. And although I haven't posted a family tree, there are not many who would mistake me for one either.

But that word kerning tends to being out the inner Scotsman in me, I guess?

Kerning in typography is simply something that narrows the space between characters in a proportional font. It is not the process that (for example) keeps the W and the l from taking up the same amount of space, but it is instead the process that (for example) moves the V and the A closer together since they have that common surface that lets them get much closer like in VA.

(You an look at the Wikipedia article on kerning for more info if you like.)

Mentally I always tend to think of kerning as kind of a static kind of capoeira-style dance between characters that keeps them from touching each other even as it lets them get closer. It might even be fun to try to create a new ClearType font called Capoeira which (with the help of a special shaping engine) would use animations to have the letters move into position in a way that looked somewhat like the martial art.

Or maybe I am just being unrealistic. And you can likely scratch the maybe. :-)

But as it cool as it might be, it is only one process that text goes through that can affect the calculation that the developer was trying to do.

I mean, there are ligatures, combining characters, digraphs, the various contortions that complex scripts being us like reordering, alternate forms, alternate shapes, and so on. In modern typography there is very little text that can calculate the amount of kerning via a simple comparison of the width of a string to the width of its component letters....

It is one of the unfortunate problems with questions that seem simple (perhaps even amusing/charming in a Mr. Scott kind of way if spoken in a polite accent of an engineer from Glasgow!). The answers often indicate that everything is much more complex than was at first believed....

I'll talk more about kerning, and about how one might ideally approach this problem, another day.


This post brought to you by Կ (U+053f, a.k.a. ARMENIAN CAPITAL LETTER KEN)

# Mihai on 2 Mar 2007 12:38 PM:

<<It is one of the unfortunate problems with questions that seem simple


The answers often indicate that everything is much more complex than was at first believed....>>

Unfortunately the usual answer back is "I don't care about all those things you just mentioned, all I care is English"

# Michael S. Kaplan on 2 Mar 2007 2:34 PM:

English does ligatures and even digraphs in some fonts, too. :-)

# RubenP on 3 Mar 2007 8:39 AM:

Isn't the real answer here that System.Drawing doesn't support kerning at all *unless* you're using one of the few predefined 'complex scripts' GDI+ supports? (And the characters of the Latin alphabet are considered 'simple'.) And *that's* why the trick used always returns 0.

But granted, trying to get kerning information *in general* wouldn't work this way, and System.Drawing doesn't have any way to query such information in the right way either, even if it did support using the TrueType 'kern' or OpenType 'gpos' tables.

# Michael S. Kaplan on 3 Mar 2007 11:31 AM:

Kerning does not require complex scripts to do it work....

# RubenP on 3 Mar 2007 6:40 PM:

Well, when fonts like Times New Roman don't kern with GDI+, it's gotta need something special... Perhaps GDI+ retired the TrueType 'kern' tables. Anyway, like the original question suggests, it's not kerning, whatever the reason.

WPF seems to have a much better interface to getting such information, and I bet Uniscribe has even more. But that won't help our Scotsman using System.Drawing, and it certainly won't as easy as the naive approach presented above.

# Dean Harding on 4 Mar 2007 6:01 PM:

Generally, if I'm doing text in a 3D environment (which is what I assume Eli was doing), I'd write the entire line using GDI (or Uniscribe if you want to get fancy) into a texture and use a single quad to display it.

You don't usually have all that much text on the screen at once, so performance is rarely an issue. But you still get pretty good frame coherency - that is, if the text is on screen on frame n, it's quite likely to be on screen in frame n+1 as well, so the performance of this technique is still pretty good.

The main advantage to this, though, is that you don't have to worry about all the kerning, diacritic and ligature support - it's all automatic. Plus you have every Unicode character available to you, not just the ones in your texture!

Please consider a donation to keep this archive running, maintained and free of advertising.
Donate €20 or more to receive an offline copy of the whole archive including all images.

referenced by

2007/08/09 The phantom kern get smashed, but he may invade someone else's space if he does

go to newer or older post, or back to index or month or day