Last year, the AppStream specification gained proper support for adding metadata for fonts, after Richard Hughes did some work on it years ago. We weren’t happy with how fonts were handled at that time, so we searched for better solutions, which is why this took a bit longer to be done. Last year, I was implementing the final support for fonts in both appstream-generator (the metadata extractor used by Debian and a few others) as well as the AppStream specification. This blogpost was sitting on my todo list as a draft for a long time now, and I only just now managed to finish it, so sorry for announcing this so late. Fonts are already available via AppStream for a year, and this post just sums up the status quo and some neat tricks if you want to write metainfo files for fonts. If you are following AppStream (or the Debian fonts list), you know everything already 🙂 .
Both Richard and I first tried to extract all the metadata to display fonts in a proper way to the users from the font files directly. This turned out to be very difficult, since font metadata is often wrong or incomplete, and certain desirable bits of metadata (like a longer description) are missing entirely. After messing around with different ways to solve this for days (afterall, by extracting the data from font files directly we would have hundreds of fonts directly available in software centers), I also came to the same conclusion as Richard: The best and easiest solution here is to mandate the availability of metainfo files per font.
Which brings me to the second issue: What is a font? For any person knowing about fonts, they will understand one font as one font face, e.g. “Lato Regular Italic” or “Lato Bold”. A user however will see the font family as a font, e.g. just “Lato” instead of all the font faces separated out. Since AppStream data is used primarily by software centers, we want something that is easy for users to understand. Hence, an AppStream “font” components really describes a font family or collection of fonts, instead of individual font faces. We do also want AppStream data to be useful for system components looking for a specific font, which is why font components will advertise the individual font face names they contain via a <provides/> -tag. Naming fonts and making them identifiable is a whole other issue, I used a document from Adobe on font naming issues as a rough guideline while working on this.
How to write a good metainfo file for a font is best shown with an example. Lato is a well-looking font family that we want displayed in a software center. So, we write a metainfo file for it an place it in /usr/share/metainfo/com.latofonts.Lato.metainfo.xml for the AppStream metadata generator to pick up:
<?xml version="1.0" encoding="UTF-8"?>
<summary>A sanserif typeface family</summary>
Lato is a sanserif typeface family designed in the Summer 2010 by Warsaw-based designer
Łukasz Dziedzic (“Lato” means “Summer” in Polish). In December 2010 the Lato family
was published under the open-source Open Font License by his foundry tyPoland, with
support from Google.
<font>Lato Black Italic</font>
<font>Lato Bold Italic</font>
<font>Lato Hairline Italic</font>
When the file is processed, we know that we need to look for fonts in the package it is contained in. So, the appstream-generator will load all the fonts in the package and render example texts for them as an image, so we can show users a preview of the font. It will also use heuristics to render an “icon” for the respective font component using its regular typeface. Of course that is not ideal – what if there are multiple font faces in a package? What if the heuristics fail to detect the right font face to display?
This behavior can be influenced by adding <font/> tags to a <provides/> tag in the metainfo file. The font-provides tags should contain the fullnames of the font faces you want to associate with this font component. If the font file does not define a fullname, the family and style are used instead. That way, someone writing the metainfo file can control which fonts belong to the described component. The metadata generator will also pick the first mentioned font name in the <provides/> list as the one to render the example icon for. It will also sort the example text images in the same order as the fonts are listed in the provides-tag.
The example lines of text are written in a language matching the font using Pango.
But what about symbolic fonts? Or fonts where any heuristic fails? At the moment, we see ugly tofu characters or boxes instead of an actual, useful representation of the font. This brings me to an inofficial extension to font metainfo files, that, as far as I know, only appstream-generator supports at the moment. I am not happy enough with this solution to add it to the real specification, but it serves as a good method to fix up the edge cases where we can not render good example images for fonts. AppStream-Generator supports the FontIconText and FontSampleText custom AppStream properties to allow metainfo file authors to override the default texts and autodetected values. FontIconText will override the characters used to render the icon, while FontSampleText can be a line of text used to render the example images. This is especially useful for symbolic fonts, where the heuristics usually fail and we do not know which glyphs would be representative for a font.
For example, a font with mathematical symbols might want to add the following to its metainfo file:
<value key="FontSampleText">∑ ∮ √ ‖...‖ ⊕ ? ℕ ⋉</value>
Any unicode glyphs are allowed, but asgen will but some length restrictions on the texts.
So, In summary:
- Fonts are hard
- I need to blog faster
- Please add metainfo files to your fonts and submit them upstream if you can!
- Fonts must have a metainfo file in order to show up in GNOME Software, KDE Discover, AppCenter, etc.
- The “new” font specification is backwards compatible to Richard’s pioneer work in 2014
- The appstream-generator supports a few non-standard values to influence how font images are rendered that you might be interested in (maybe we can do something like that for appstream-builder as well)
- The appstream-generator does not (yet?) support the <extends/> logic Richard outlined in his blog post, mainly because it wasn’t necessary in Debian/Ubuntu/Arch yet (which is asgen’s primary audience), and upstream projects would rarely want to write multiple metainfo files.
- The metaInfo files are not supposed to replace the existing fontconfig files, and we can not generate them from existing metadata, sadly
- If you want a more detailed look at writing font metainfo files, take a look at the AppStream specification.
- Please write more font metadata 😉