Close01 / 07

01 / 07

fontscrape

Self-initiated · 2020–26 · Concept and development

Contact sheet of scraped glyphs: a five-by-ten grid of black tiles, each holding one white lower-case a from a different installed font — sans, serif, blackletter, italic, a stencil, a Devanagari face and one that renders as a lone ellipse

Every font on a Mac, rendered as one letter, as a folder of images.

It was built to feed GlyphGAN and turned into the more interesting half. A model trained on typography is a model of whatever dataset it was given, and there was no way to make that dataset without deciding several things that change what the model learns.

There is nothing to install. Core Text and Core Graphics ship with macOS, so there is no dependency to fetch, no Xcode project and no runtime. Around 3,600 fonts at 256 pixels takes about three seconds.

What a rendering mode decides

The same glyph can be rasterised three ways, and each one throws away something different.

Fit scales the ink to fill the canvas. Point size and x-height differences are normalised away, and what survives is letterform shape alone.

X-height scales so every face shares an x-height and centres the ink. Width and stroke weight survive as signal, which is the difference between a compressed light and an extended black staying recognisably different and becoming the same rectangle.

Metric renders at a fixed point size on a shared baseline, keeping each font’s absolute metrics.

None of these is correct. They encode different questions, and picking one is picking what the model is allowed to notice.

A font library is less varied than it looks

On the machine this was built for, 3,639 faces came from 654 families. GT America alone accounted for seventy of them, Minion Pro sixty-four, Surt fifty-four. Anything trained on that is skewed toward whichever families you happen to own the most weights of.

Capping at three faces per family cuts it to 1,405, and the cap chooses faces spread across the family’s weight range rather than in file order — so a family contributes something like an ultralight, a regular and a black rather than three near-identical mediums.

Variable fonts go the other way. They carry continuous weight and width axes, so the tool can instantiate several points along one and render each. Those are real typefaces the designer specified rather than affine copies of a bitmap, which makes them honest additional samples.

The two compose in one order and not the other: variations are generated first, then the per-family cap is applied to whatever came out, counting samples rather than source files. Otherwise a variable family smuggles extra weight through a cap that thinks it is holding.

What the manifest knows

The optional CSV carries each sample’s normalised weight, width and slant, and Core Text’s own stylistic classification — sans-serif, slab-serif, script, ornamental — rather than a guess from the font’s name. Enough to condition a model on style, not only on which letter it is.

The last columns come from the font’s OpenType name table: declared licence, licence URL, copyright, vendor. The vendor’s own text rather than anything inferred.

Scraping is not the problem

The tool reads installed fonts through the same Core Text APIs any application uses to draw text. It never copies, embeds or redistributes a font file.

What you do with the images afterwards is a different question, and the answer depends on where you are. In the United States typeface designs have never been copyrightable while the font software is — which puts a raster of a letterform on very different ground from the file it came from. The UK, Germany and much of the EU do extend protection to the designs. On top of that sits each foundry’s own agreement, and some now address machine learning explicitly.

Least to most exposed: rendering glyphs locally and training something for yourself is nothing. Publishing the image set is redistributing derivative representations of fonts you licensed and do not own. Publishing a model trained on them is unsettled law.

Filtering to fonts that declare permissive terms in their own name table gives a defensible subset — on this machine, 3,639 faces down to 222, from Velvetyne, Colophon, Bold Monday and similar. Far smaller, and with a clear basis for publishing it and for someone else to reproduce the result.

Fonts that declare nothing are not thereby permissive. Commercial foundries usually leave the field empty and put their terms in a separate agreement. The manifest records what each font claims so the question can be checked rather than assumed.

Details that only matter once

Output is 8-bit greyscale PNG. Glyphs are black-and-white shapes, so colour channels carry no information and lossy compression would put ringing artefacts on every stem.

Glyphs are drawn by glyph ID rather than by character, which stops Core Text quietly substituting a different family and mislabelling the sample. A font with no glyph for the requested character is skipped rather than rendered.

Apple’s private interface faces are excluded by default. They are near-duplicate optical grades rather than distinct typefaces, and including them would be the family-skew problem again in miniature.

Files are named after the font’s PostScript name, so a sample stays traceable to the face it came from — which is the whole point when something in the output looks wrong.

The release is fetched with curl on purpose. macOS attaches its quarantine flag in the downloading application; browsers do that and curl does not, so the binary just runs.