natechoe.dev The blog Contact info Other links The github repo

Generating PSF files

The setfont utility, which (obviously) sets the Linux console font, requires a psf file to work. After several hours fo trying to use existing utilities, then giving up and spending more hours writing my own utility, I have a utility to generate PSF files now. The rest of this blog post will be some technical information on why this is hard, and some design lessons we can learn by avoiding this situation.

Part 1: Why existing toolchains suck

If you search how to convert ttf files to psf files and somehow don't get any scammy online pdf converters in your search results, you'll find this Reddit post, which recommends using the otf2bdf and bdf2psf utilities. When I used these tools, however, bdf2psf gave me this message:

Use of uninitialized value $font_size in numeric le (<=) at bdf2psf line 99.

This leads to our first two design lessons: Make it work, and make it responsive. The first point is obvious, but if your program doesn't work tell the user why it doesn't. In this case I think bdf2psf received an invalid file as input, but I have no way of knowing because bdf2psf doesn't tell me what happened. Whenever you have or expect an error, give the user a hint to get back on track. I had no such hints, and decided after several hours that it would be easier to write my own utility instead.

Part 2: Why psf sucks

To roll my own converter, I'd have to learn about psf files in the first place, so I went where I always go when I don't know something, Wikipedia. Here is the entire article at the time I checked:

PC Screen Font (PSF) is a bitmap font format currently employed by the Linux kernel for console fonts. Documentation of the PSF file format can be found within the source code of the Linux kernel.[1] The format can be found here with University Eindhoven.[2]

That's not very helpful, and that university is quite vague with its description as well. As it turns out, the only complete, authoritative description of the psf format is the setfont source code itself. Font files consist of a header with little endian values, some bitmaps, and a glyph table. The setfont utility doesn't actually parse the bitmaps though, it just reads them and sends them to the kernel. The system call in the kernel doesn't read the bitmaps either, though, it just stores the bitmaps in a place that the screen renderer can understand. This leads to our second design lesson: Make things obvious. To get a full description of the psf format, rather than reading a human-written document I had to read source code. Not only that, I had to read source code from two separate repositories and manage details from both, because "the source code is the documentation" only works with well-written source code that doesn't span two codebases and doesn't make the parsing process obvious.

Part 3: Conclusion

ttf2psf exists now, it generates psf files from ttf files using FreeType, and actually works.