Skip to content

Instantly share code, notes, and snippets.

@zec
Created November 19, 2010 01:50
Show Gist options
  • Save zec/706013 to your computer and use it in GitHub Desktop.
Save zec/706013 to your computer and use it in GitHub Desktop.
Script to create .tfm and .enc files for a PostScript-flavored OpenType font for pdfTeX
#!/usr/bin/env python
# Copyright (c) 2010 Zachary Catlin
# MIT-licensed; see full license at end-of-file.
# A Python/FontForge script that creates subfont TeX metrics and encoding files
# of a given PostScript-flavored OpenType font, much the way ttf2tfm(1) creates
# subfont files for TrueType fonts. This allows the font to be used with the
# LUC encoding provided by the LaTeX ucs package. Also, the script exports the
# original font to Type1 format for more flexible use by pdfTeX. All generated
# files are written to the current directory.
# Usage: python mktfms.py <original.otf> <base TeX font name>
import fontforge
import sys
import os
if(len(sys.argv) < 3):
print("No font file specified")
sys.exit(1)
fnt = fontforge.open(sys.argv[1])
texName = sys.argv[2]
if fnt.layers['Fore'].is_quadratic:
print("Only supports PostScript-flavored OpenType fonts")
sys.exit(1)
unicodeMap = {}
for glyph in fnt.glyphs():
if(glyph.unicode >= 0):
unicodeMap[glyph.unicode] = (glyph.glyphname, glyph.encoding)
# Create .tfm and .enc files for each range of 256 code points for which
# there is at least one glyph in the font file.
for i in set([k >> 8 for k in unicodeMap.iterkeys()]):
if(i < 0x100):
rangeName = '{0:02x}'.format(i)
else:
rangeName = '{0:04x}'.format(i)
baseName = texName + rangeName
encName = 'mktfms-' + baseName + 'Encoding'
# tfmFont will contain the subset of glyphs we are interested in.
tfmFont = fontforge.font()
tfmFont.encoding = fnt.encoding
tfmFont.fontname = fnt.fontname
tfmFont.familyname = fnt.familyname
tfmFont.fullname = fnt.fullname
tfmFont.weight = fnt.weight
tfmFont.em = fnt.em
tfmFont.layers['Fore'].is_quadratic = False
fnt.selection.none()
tfmFont.selection.none()
# Make the encoding for this subfont, selecting the appropriate glyphs
# in fnt and tfmFont along the way
encFile = open(baseName + '.enc', 'w')
encFile.write('/' + encName + ' [\n')
for j in range(256):
codePoint = (i * 256) + j
if codePoint in unicodeMap:
#print(unicodeMap[codePoint])
fnt.selection.select(('more',), unicodeMap[codePoint][1])
tfmFont.selection.select(('more',), unicodeMap[codePoint][1])
encFile.write('/' + unicodeMap[codePoint][0] + '\n')
else:
encFile.write('/.notdef\n')
encFile.write('] def\n')
encFile.close()
# Do the actual copy of glyphs
fnt.copy()
tfmFont.paste()
# Using the encoding file, re-encode tfmFont, then export
fontforge.loadEncodingFile(baseName + '.enc')
tfmFont.encoding = encName
tfmFont.generate(baseName + '.pfa', flags=('tfm'))
tfmFont.close()
# We're only interested in the font metrics, not the subsetted font, so...
os.remove(baseName + '.pfa')
# Create a Type1 version of fnt, as pdfTeX likes Type1 fonts better.
# No metrics are needed for this file.
fnt.generate(texName + '.pfb', flags=())
fnt.close()
# Copyright (c) 2010 Zachary Catlin.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment