Use a custom icon font in QML

When it comes to images, mobile development is facing exactly the same problem than mobile web development. Images need to scale well, have a decent file size etc.. Responsive web design often use icon fonts to solve this problem for icons. In this case, an icon font also have the advantage of limiting HTTP requests.

In QML, we do have the possibilities to use BorderImage, or to use SVG files. Both approaches have their merits but they also have some drawbacks. For example, currently, SVG files are not rendered correctly on retina display (QTBUG-35271). BorderImage are less interesting for icons since the icon itself would not scale.

Other developers used icon fonts in QML, in particular using the Font Awesome web font.

Previous works with Font Awesome

Font Awesome is a popular icon font in web development. So popular than for oncen it's also used in QML. 2 years ago, markg85 described how to Use font awesome in QML. Recently, Ricardo do Valle created a GitHub project to demonstrate the same approach with QML in Qt 5.3.

Here I want to quickly show how one can create his own web font and use it in QML, based on the same method.

Create a font on Icomoon

Create a couple of icons in your favorite vector graphics editor, save as SVG and go to Icomoon.io. The website is one of the numerous options available to create a web font. It's easy to add your icons and then create a font. You can customize codepoints, font name and so on.

Add the font to a QML app

The QML app will use the TTF format of the font. You can grab it from the zip generated by Icomoon. We would also want to have an easy way to refer to each icon in the font to avoid the following:

Label {  
   text: "\ue601"
   font.family: "MyFont"
}

Icomoon also provide an HTML demo file. I wrote a small python script to parse it and extract a javascript file to map the codepoints with human friendly names. The script takes the path to demo.html as a command line parameter.

import requests  
import re  
import sys

from bs4 import BeautifulSoup

f = open(sys.argv[1],"r")  
data = f.read()  
soup = BeautifulSoup(data)

glyphs = soup.find_all('div', class_="glyph")

print ".pragma library"  
print "var Icon = {"  
for g in glyphs:  
    ##t = g.text.strip()
    pbs = g.find_all('div', class_="pbs")

    for pb in pbs:
        variable = pb.text.strip()
        variable =  re.sub(r'(?!^)-([a-zA-Z])', lambda m: m.group(1).upper(), variable[10:])
        #print variable

    input = g.find_all('input', class_="unit size1of2")

    for i in input:
        charcode = "\\u" + i['value']

    print "      " + variable + " " * (20 - len(variable))  + ": \"" + charcode + "\","

print "}"  

The output of this script is a javascript file, MyFont.js to include in a QML app. And we can then write:

import "MyFont.js" as MyFont  
Label {  
   text: MyFont.Icon.logo // name of the icon
   font.family: "MyFont"
}

Conclusion

This is it. Comments or questions? @lasconic