Better performance for labels with outline font in UIKit

| 2 Comments

For games performance is key. But also style and visual appearance are important, especially in iOS games. And sometimes your local artist comes with a great idea: He wants to have outlines around the labels. “Great!”, you might think, “This won’t be a hard job!” — You are right. To achieve an outline around a label in iOS, you can use one of the many approaches out there.
The bandwidth reaches from utilising the shadow properties of UILabel (UILabel with Stroke, THLabel), which works for iOS 4.0+, till the attributed text, which was introduced in iOS 6.0 (UILabels in iOS 6).
The last is the most efficient solution in terms of performance. But each of these approaches reduces the performance when the labels get drawn. You can feel this in a game or application, if you scroll a long list, that contains many labels with an outline. The feeling is even worse, if labels get updated really fast.

This was not acceptable, especially not in our game, where we want to have the best performance that is possible. Therefore I searched around a lot and profiled every of the before mentioned approaches. The result was not satisfying. None of them was performant enough. So, what else?
One of the last options was to create 2 labels on top of each other. This seemed to be a good solution, but in fact it looked strange. This was because the second label with a slightly bigger font size was scaled from the anchor point of the UILabel. In this example below it was at the center:

Two labels on top of each other

Two labels on top of each other

Again, no useful solution. Hmmm…
Fortunately an other game team at Wooga was researching too and Kamil Chmurzynski and Lucas Bellett came up with a great solution of the 2-label-approach. The idea is to have a dedicated outline font instead of using only a bigger version of the normal font. They use a tool named ‘Font Forge’ to create proper outline fonts. The tool itself is really powerful and you can do advanced stuff, if you have enough knowledge in font science.
I was curious and started to create an outline font for our project. After some traps and mistakes and discussions with Kamil and Lucas, I wrote down all the necessary steps and built a simple prototype. And the result looks like this:

Label with outline

Label with outline

Spectacular, this works great! In one specific situation, which was my test case, I measured that this approach is 5.5 times faster then the one we had before (and this was already the fastest of the previously mentioned approaches).
And this is what you have to do for it:

How to create the outline font with Font Forge:

  1. Install Font Forge — http://fontforge.github.io/en-US/downloads/mac
  2. Load the base font into font forge — File/Open
  3. Change the em size of the base font to a factor 2 number — Element/Font Info…/General

    Font information

  4. Export font via — File/Generate font
  5. Load the modified base font — File/Open
  6. Select all characters — CMD+A
  7. Change the weight of the characters — Element/Style/Change Weight
    • Change the value for Embolden by to something significant (50 ➞ 150), according to how strong you want the outline to be
    • Change the mode to CJK

    Font characteristics

  8. Change the name of the modified font — Element/Font info/PS names
    • This step is important since you don’t want to show up duplicate fonts.
    • IMPORTANT: Make sure that the UID has changed as well!!! (If an already renamed font remains open and you change the name of the font again, Font Forge won’t ask for a UID change)

    Font name

  9. Export font via — File/Generate font
  10. Be aware that validation alerts may occur when saving or modifying the characters or font. Usually this is due to a non-perfect base font where some of the vector shapes are broken (means, they have not closed paths)

How to use both fonts in code

I created an ‘OutlinedLabel’ that inherits from UILabel. It contains some stuff for a convenient use but the essence is in the overridden drawTextInRect method.

- (void)drawTextInRect:(CGRect)rect 
{
    self.font = _outlineFont;
    self.textColor = _outlineColor;
    [super drawTextInRect:rect];

    self.font = _fillFont;
    self.textColor = _fillColor;
    [super drawTextInRect:rect];
}

Here the label text gets drawn two times. The first time is the outline with the new created outline font and an appropriate color. The second time the fill is drawn with the adjusted base font and a fill color. There is no need for managing 2 different labels.
A small test project that shows the outlined label in action, you can find on github (Outlined UILabel).

Drawbacks

Cool, the only thing to do is creating a special outline font, use it and this solves all of our problems? No! This approach works great for numbers. And it also works for characters that are included in your base font file.
BUT, if you try to use special characters, e.g. if your application/game is localised in countries with a different character set, the font substitution of iOS jumps in and replaces your font with a system default font (iOS fonts / Discussion about Chinese Characters). This means that the outline font is substituted too and therefore the outline won’t be visible. The outline will have the same size and dimensions and is drawn underneath the filling, which looks like this:

Label with Japanese text

Label with Japanese text

To avoid this you can choose a font that contains all required characters. If you need Arabic, Japanese, Chinese, Korean, Latin, … characters, your font file size will be increased a lot. And with a bigger base font and a bigger outline font (which is usually even bigger then the base font) the bundle size of the application/game gets increased tremendously.

Conclusion

In the end it is clear, that there is a performant way to get labels with outlines. But I ask myself, if and where this approach is really useful.
Outlines work great for numbers anyways. For normal text you see the outline only if there is no font substitution happening. Therefore you have to take care, that the text stays readable even without the outlines. These leads me to the question why to use outlines for normal text at all? And if you use no outlines for normal text, it may be even more consistent to avoid outlines for numbers as well.
With these questions in mind, the described approach can be only used without any drawback, if the application/game has all required characters in the custom font. This means, if no font substitution will happen.
But after all these questions and thoughts, it is a matter of the design of the application/game, if outlines are needed and in which way they get realised.

2 Comments

  1. Great tutorial — Do you know what value you used for embolden? I’m used between 150 and 300 and it seems the outline is very faint when used with small font sizes (trying with Arial). But your demo app seems to maintain a good outline when I adjust the font size so I was wondering what values you used for the embolden. Thanks!

Leave a Reply

Required fields are marked *.