I released a new tool today! It takes pixel font "tilesets" and converts them into actual TTF fonts! It is also 100% web-based, meaning that you can try it out right now. And this post details the development process for it. Also it doesn't have a catchy name for now since I've not come up with a good pun yet.
Context and motivation
Perhaps a thing that I'm less known for, but between various technical work I also draw various pixel fonts. Although the published collection is fairly neat and organized, there is also a number of unpublished fonts featuring unusual sizes and styles that seem like a good idea up until the point where you draw Latin W or Cyrillic Й (the ultimate nemesis of a fixed-height font):
Rest assured, if you draw many of these, you need a good process for editing, previewing, and saving the fonts.
I would at first experiment with FontStruct (tracing pixel glyphs in Font Forge or other "conventional" editors didn't seem like a good time), but found that the tool wasn't strictly geared towards pixel fonts (which is fair) - you could absolutely draw a pixel font in it, but tools the tools would usually do region rather than cell operations (e.g. the eraser highlights a rectangle to erase). Still, my account still spots early versions of what would later become 6w4 and 6w3 fonts:
Later I found BitFontMaker, which was a little better, but the paginated glyph grid left some to be desired (I would much rather just draw multiple glyphs on spot), and so did the drawing tools. So, in 2014 I made BitFontReader, which would process a PNG file and pump out JSON for BitFontMaker:
BitFontReader lasted for a while, but, as my fonts started to cover more and more glyphs (for example, 7w7 has almost 500), I found that drawing all your glyphs in a row isn't such a reliable approach - for example, if you miss a glyph, everything afterwards will be offset, so you'll have to find the spot, select everything on the right, move that a few pixels right... so sometime in 2016 I made another tool, still pumping out BitFontMaker JSON, but taking a "tileset" instead:
This was an improvement - drawing a 300-glyph font was no longer so crazy, but the process remained slightly janky (import image, export JSON, import JSON, export TTF, fix-up TTF using FontForge scripts), so I never ended up publicly releasing it, only having sent it to a bunch of people that I talked to about fonts often. Still, this was how I made most of the fonts I released.
Then, in late 2018 Rob Meek (creator of FontStruct) open-sourced the font generator library that was used by the service, and it had been on my mind ever since - if I were to solve a couple other technical challenges, everything could be so nice - I wouldn't have to go through several pages just to get a new TTF file, I wouldn't have to mess with FontForge scripts just to make fonts act right, and I could even make fonts larger than 12x12 pixels!
On that subject, how many "medium-sized" (>12px height) TTF/OTF pixel fonts have you seen? I think I've only seen a few in my life - perhaps because most people have better things to do with their lives than carefully tracing their pixel drawings in a vector-based font editor.
It would take some time for me to finally get around to it.
As per above, with fonthx the actual generation, I'm left to feed it glyph data and input parameters.
Most of that was pretty straightforward, though I found that different software may interpret font parameters differently, leading me on a trail of interesting discoveries like this "you can't really use line gap" article (~17 years later, some software still uses em size for line size), or this gem of a tooltip in FontForge:
A fork of fonthx with additions that I found useful for this tool can be found on GitHub.
fonthx uses haxe.Resource to load a number of text files with charset data.
When targeting JS, files included that way are embedded into source code in base64 format.
Although the files themselves are admirably uniform, base64 versions are less so, and would add up to 3.2MB worth of JS code total. That's kind of a lot - the rest of my application compiles to less than 100KB of minified JS.
After some consideration I decided to get around this by integrating pako (pako_inflate.min.js is mere 22.6KB) and fetching a 320KB ZIP file with charset text files to populate haxe.Resource's internal list on boot.
So on the aforementioned glyph data: as you might be aware, pixel fonts are made of pixels. TTF/OTF fonts are not made of pixels - not until they are drawn onto your screen anyway. They are made out of paths (CCW paths defining shapes and CW paths defining holes in them). So you want to convert your pixels into paths.
The simplest approach would be to simply generate a square for each pixel:
This is okay, although not very efficient, and some rendering artifacts may appear on unusual font sizes.
BitFontMaker goes for a slightly better approach, merging the squares but keeping the additional vertices:
Ideally, of course, you would want an optimized path - akin to what you would trace by hand:
So I wrote a simple algorithm for that:
You can read more about it in its own post.
Overall I'm pretty happy with how this turned out:
- The tool is web-based, lightweight, and has no external dependencies.
- The tool can also be downloaded and used offline
(which does not require running native code either)
- The tool allows for arbitrary sized fonts, an improvement from BitFontMaker.
- The tool allows to edit most of the useful metadata, also an improvement.
- Combination of pixel-based input, JSON settings, and a variety of ways to re-import images (file dialog, drag and drop, even pasting them directly) allows for comfortable workflows in existing tools.
I’m just here to say: thank you for this tool. It is very easy to use and I created my very first pixel art font with it. I now plan to add this font to Game Maker Studio. If I may make a small comment, the only thing I would like to see improved is the width of the panel, which seems a bit small :)
This is so good! Making a font out of an image is very approachable. I was looking at some font making programs before and they always were very daunting. This just seems straight and to the point. Good job!