Unity font extraction

posted by harrison on September 11, 2012

I just stumbled across a paste of some useful unity code I wrote roughly a year ago: font extraction.

Unity’s fonts can be dynamically generated, or generated from a character set at build time. When you pick a character set, Unity generates a font texture, which you can access and even replace. There are a number of blog posts on the topic, and there’s an entry in the wiki. But, all of these other posts are just about extracting the texture. They don’t address the issue of font data.

The unity font is basically 3 things: a texture, a mapping from chars to rectangles in the texture, and spacing information. For most fonts, the spacing is 0, or at least constant, but it can have custom spacing for each pair of adjacent characters. But since it’s usually 0, i’m going to ignore spacing in today’s code (but you can get at it with the same technique). And the way unity stores that information is with serialized properties on the asset. That means that you can get at them in the editor, but not at runtime, so I made a script to pull it out into something i could use at runtime. It also means that it’s gross and uses strings.

Anyway, here’s some code to pull an atlas out of a unity texture:


public class SpriteFont : ScriptableObject {
    public Glyph[] glyphs;
    public Texture2D sprite_texture;

    [Serializable]
    public class Glyph {
        public Rect uv;
        public Rect vert;
        public float width;
        public int index;
    }
}

   SpriteFont BuildFont(Font font, string asset_path) {
        var sprite_font = ScriptableObject.CreateInstance<SpriteFont>();
        AssetDatabase.CreateAsset(sprite_font, asset_path);

        //pull out font atlas info
        var sFont = new SerializedObject(font);
        var size = sFont.FindProperty("m_CharacterRects.Array.size").intValue;
        sprite_font.glyphs = new SpriteFont.Glyph[size];
        for (int i = 0; i < size; ++i) {
            var prefix = "m_CharacterRects.Array.data[" + i + "]";
            var g = new SpriteFont.Glyph();
            sprite_font.glyphs[i] = g;
            g.uv = GetRect(sFont, prefix + ".uv");
            g.vert = GetRect(sFont, prefix + ".vert");
            g.index = sFont.FindProperty(prefix + ".index").intValue;
            g.width = sFont.FindProperty(prefix + ".width").floatValue;
        }

        //get the font texture
        var path = AssetDatabase.GetAssetPath(font);
        var tex = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
        sprite_font.sprite_texture = tex;

        EditorUtility.SetDirty(sprite_font);
        return sprite_font;
    }

For each character, you have the uv coordinates in the texture, the screen-space rectangle, how wide it is (how much to offset the next char by), and the character itself (index is the character, as an int). If you were making a robust tool, it should also extract the line height, and the kerning (spacing), and if you’re feeling extra robust, the per-character kerning.


Twisted Oak Studios offers consulting and development on high-tech interactive projects. Check out our portfolio, or Give us a shout if you have anything you think some really rad engineers should help you with.

Archive

More interesting posts (22 of 33 articles)

Or check out our Portfolio.