Use Custom Application fonts with Pango/GTK
This article is originally posted on my other blog, but I am porting it here for archival purpose. I’ve also edited it as well as added some more information. You can see the original blog post on archive.org here.
I was recently working with Pango, to make it use with a Python binding called ManimPango, and found that Pango still does not make it easy to use custom (aka. application) fonts. So I decided to research on how to do it and found that there is no comprehensive guide on how to do it. So I decided to write one.
Whatever I say for Pango will apply for GTK also because GTK uses Pango internally for rendering fonts. So, if you are creating a GTK app say something like Inkscape, it also works for you 😊.
By application fonts, I mean when an application wants to use a font file that it ships, but is not installed in the system or user font directories. For example you are rendering a SVG file with a font which isn’t installed in the Users computer.
There isn’t a direct way to do that in Pango, so you should use the backend API for adding the fonts to the search path, before calling Pango.
Here is a list of Backend available per Operating System
- Windows - pangowin32(default), fontconfig(optional)
- macOS - coretext(default), fontconfig(optional)
- Linux - fontconfig (default)
For Windows
Win32 API
Since Pango 1.50.11, this method doesn’t work, see https://gitlab.gnome.org/GNOME/pango/-/issues/720
For Windows, you have to GDI API,
AddFontResourceExA
.
This will work if you are going to use the native pangowin32
backend.
Before calling into Pango, do this:
- Find the font file you want the add. See the file formats which are recognized here.
- Then call
AddFontResourceExA
orAddFontResourceExW
with the path to the font file. Though note that pango doesn’t support symbol fonts. - Make sure you pass
FR_PRIVATE
asfl
parameter so that you can use your font with Pango. - Use Pango as you otherwise would.
A sample code on how you would use that.
AddFontResourceExA("myapp/cutom.ttf", FR_PRIVATE, 0);
You can see a full example in this repository: https://gitlab.com/naveen521kk/blog-posts/-/tree/master/pango-app-fonts
Fontconfig
Here is one way to do it, using fontconfig API:
Before calling into Pango, do this:
- Add fonts to it using
FcConfigAppFontAddFile()
orFcConfigAppFontAddDir()
, set current config asFcConfigGetCurrent()
- Use Pango as you otherwise would.
This would work when you have and environment variable called
PANGOCAIRO_BACKEND
to fc
or
fontconfig
on your User’s computer and Pango is compiled with
fontconfig enabled. You can also set it before calling Pango but it may crash
your application if Pango wasn’t compiled with fontconfig and that variable is
set. See
documentation about this function.
A sample code would be
FcConfigAppFontAddFile(FcConfigGetCurrent(), "myapp/cutom.ttf");
For macOS
Coretext
You should use CTFontManagerRegisterFontsForURL()
for registering
the font. See the corresponding documentation
https://developer.apple.com/documentation/coretext/1499468-ctfontmanagerregisterfontsforurl
Since the API is for objc you can use a binding like Carbon to call the
function. The fontURL
parameter can be created by using
CFURLCreateWithBytes()
and pass it the
previous function.
A sample code would be
CFURLRef cf_url = CFURLCreateWithBytes(NULL, "myapp/font.ttf", b, 0x08000100, NULL)
CTFontManagerRegisterFontsForURL(cf_url, kCTFontManagerScopeProcess, NULL)
Fontconfig (macOS)
This is same as Windows section.
For Linux
This is same as Windows section but here the default backend is Fontconfig and the environment variable needn’t be set. There is also a article Behdad, http://mces.blogspot.com/2015/05/how-to-use-custom-application-fonts.html which may explain in detail about using Pango with fonconfig.
Python Apps
For python, it would be simple to depend on a library I created ManimPango for Manim, which can be used across platforms and has a simple API for registering font. See the docs.