Skip to content

Instantly share code, notes, and snippets.

@kousu
Last active March 3, 2017 21:03
Show Gist options
  • Save kousu/16f6358a159010d83bc157d5de9ccfee to your computer and use it in GitHub Desktop.
Save kousu/16f6358a159010d83bc157d5de9ccfee to your computer and use it in GitHub Desktop.
Pare down font files for web use

Sometimes** (**I'm thinking of the web, here, really) you only need a subset of glyphs in a font. A full font file can be pretty bandwidth-heavy.

cut_font will snip a font down to only the characters given on the command line. It will use the same output format as input format. It doesn't handle glyph variations (like italics or bold versions of a font) nor let you choose the output file; sorry about that; patches welcome.

Example

$ ./cut_font Symbola.ttf ≄ a b C D \`
The glyph named dz is mapped to U+02A3.
But its name indicates it should be mapped to U+01F3.
The glyph named macron is mapped to U+02C9.
But its name indicates it should be mapped to U+00AF.
The glyph named Delta is mapped to U+0394.
But its name indicates it should be mapped to U+2206.
The glyph named Omega is mapped to U+03A9.
But its name indicates it should be mapped to U+2126.
The glyph named mu is mapped to U+03BC.
But its name indicates it should be mapped to U+00B5.
The glyph named hyphenminus is mapped to U+2010.
But its name indicates it should be mapped to U+002D.
The glyph named gscript is mapped to U+210A.
But its name indicates it should be mapped to U+0261.
The glyph named arrowupleft is mapped to U+21B0.
But its name indicates it should be mapped to U+2196.
The glyph named arrowupright is mapped to U+21B1.
But its name indicates it should be mapped to U+2197.
The glyph named arrowdownleft is mapped to U+21B2.
But its name indicates it should be mapped to U+2199.
The glyph named arrowdownright is mapped to U+21B3.
But its name indicates it should be mapped to U+2198.
The glyph named dblarrowleft is mapped to U+21C7.
But its name indicates it should be mapped to U+21D4.
The glyph named dblarrowright is mapped to U+21C9.
But its name indicates it should be mapped to U+21D2.
The glyph named arrowdblboth is mapped to U+21ED.
But its name indicates it should be mapped to U+21D4.
The glyph named periodcentered is mapped to U+2219.
But its name indicates it should be mapped to U+00B7.
The glyph named difference is mapped to U+224F.
But its name indicates it should be mapped to U+223C.
The glyph named intersectiondbl is mapped to U+22D2.
But its name indicates it should be mapped to U+22D3.
The glyph named uniondbl is mapped to U+22D3.
But its name indicates it should be mapped to U+22D2.
The glyph named anglebracketleft is mapped to U+2329.
But its name indicates it should be mapped to U+3008.
The glyph named anglebracketright is mapped to U+232A.
But its name indicates it should be mapped to U+3009.
The glyph named carriagereturn is mapped to U+240D.
But its name indicates it should be mapped to U+21B5.
The glyph named subsetdblequal is mapped to U+2AC5.
But its name indicates it should be mapped to U+2286.
The glyph named supersetdblequal is mapped to U+2AC6.
But its name indicates it should be mapped to U+2287.
The glyph named ascript is mapped to U+1D4B6.
But its name indicates it should be mapped to U+0251.
The glyph named fscript is mapped to U+1D4BB.
But its name indicates it should be mapped to U+0192.
The glyph named lscript is mapped to U+1D4C1.
But its name indicates it should be mapped to U+2113.
The glyph named vscript is mapped to U+1D4CB.
But its name indicates it should be mapped to U+028B.
keeping C
keeping D
keeping grave
keeping a
keeping b
keeping notasymptequal
Wrote result of 6 glyphs to Symbola_cut.ttf
gauchier:net nguenthe$ 

This cut the 2MB Symbola font down to more like 2K:

$ ls -lh Symbola*.ttf
-rw-r--r--@ 1 nguenthe  staff   2.0M  2 Mar 18:42 Symbola.ttf
-rw-r--r--  1 nguenthe  staff   3.2K  3 Mar 11:34 Symbola_cut.ttf
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Usage:
cut_font [font_file] [character_to_keep, ...]
e.g.
./cut_font Symbola.ttf ≄ a b c d e f g h A B C D E F G H
Requires: fontforge <http://fontforge.github.io>,
Arch: pacman -S fontforge
OS X: brew install fontforge
Debian*: apt install fontforge
etc. (Windows probably works too. I dunno)
"""
from __future__ import print_function
import sys, os
import locale
import fontforge
KEEP = sys.argv[2:]
if sys.version_info.major == 2:
# on py2 we need to manually decode characters, because sys.argv gives py2 'str's which are really raw bytes!
# figure out the encoding (if this doesn't match what the user passed in ...that's gonna have to be their problem)
locale.setlocale(locale.LC_ALL,"")
_, defaultencoding = locale.getlocale()
# get unicode
KEEP = [e.decode(defaultencoding) for e in KEEP]
# pretend we're py3
chr = unichr
F = fontforge.open(sys.argv[1])
# The fontforge objects are not as pythonic as they could be
# they don't have a .keys(), though they behave like a dict;
# their len() always gives the initial length, regardless of
# the actual number of elements.
#
# The elements are fontforge.glyph objects, keyed by string,
# either a name ("grave" = "`") or a unicode codepoint ("uFF14")
for e in list(F):
if chr(F[e].unicode) in KEEP:
#print("dropping", e)
F.removeGlyph(e)
else:
print("keeping", e)
# save the cut up font as a new font
output = "_cut".join(os.path.splitext(sys.argv[1]))
F.generate(output).save()
print("Wrote result of %d glyphs to %s" % (len(list(F)), output))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment