Skip to content

Instantly share code, notes, and snippets.

@damieng
Created July 19, 2025 20:30
Show Gist options
  • Save damieng/2238a3eddc1cafab780937e969c56a94 to your computer and use it in GitHub Desktop.
Save damieng/2238a3eddc1cafab780937e969c56a94 to your computer and use it in GitHub Desktop.
Spectrum font conversion in FontLab 5
#FLM: ZX Conversion
# Create TTF from 8x8 ZX BDF
## Set metadata
import os
font = fl.font
# Base name on filename
fontName = os.path.basename(os.path.splitext(font.file_name)[0]).strip()
nameParts = fontName.split()
isBold = True if "Bold" in nameParts else False
isItalic = True if "Italic" in nameParts else False
styleNames = []
font.font_style = 0
font.weight = "Regular"
font.weight_code = 400
# Typical font characteristics
pixels_descender = 1 # Pixels for the descender
pixels_lower = 5 # Lower-case x-height (acxo)
pixels_upper = 7 # Upper-case height (ABCD)
pixels_ascender = pixels_upper
# Pixel metrics
pixel_size_x = 100
pixel_size_y = 100
pixels_wide = 8
pixels_high = 8
# Calculations
height = pixel_size_y * 8
width = pixel_size_x * 8
# Set the font metrics
font.upm = height
font.ascender[0] = pixels_ascender * pixel_size_y
font.descender[0] = 0 - (pixels_descender * pixel_size_y)
font.cap_height[0] = pixels_upper * pixel_size_y
font.x_height[0] = pixels_lower * pixel_size_y
font.default_width[0] = width
font.underline_position = font.descender[0]
font.underline_thickness = pixel_size_y
font.is_fixed_pitch = 1
font.panose[3] = 0
if isBold:
styleNames.append("Bold")
nameParts.remove("Bold")
font.font_style += 32
font.weight = "Bold"
font.weight_code = 700
if isItalic:
styleNames.append("Italic")
nameParts.remove("Italic")
font.font_style += 1
if styleNames:
styleName = " ".join(styleNames)
else:
styleName = "Regular"
familyName = " ".join(nameParts)
fullName = familyName + " " + styleName
# Set all standard names
font.family_name = familyName
font.style_name = styleName
font.font_name = familyName.replace(' ', '') + "-" + styleName.replace(' ', '')
font.full_name = fullName
font.menu_name = familyName
font.apple_name = fullName if isBold or isItalic else familyName
# Personalized creator info
font.designer = "Damien Guard"
font.designer_url = "https://damieng.com"
font.year = 2019
font.copyright = "Copyright 2019 Damien Guard."
font.vendor = "ENVY"
font.vendor_url = "https://envytech.com"
# Set OpenType & TrueType data
font.pref_family_name = familyName
font.pref_style_name = styleName
font.mac_compatible = fullName
font.tt_u_id = font.designer.replace(' ','') + ": " + fullName + ": " + str(font.year)
fl.UpdateFont()
## Clear font
glyphs = font.glyphs
for glyph in reversed(glyphs):
del glyphs[glyph.index]
## Index mode
fl.CallCommand(33209)
## Import BDF to background
fl.CallCommand(33911)
## Trace BDF background
fl.CallCommand(32873)
fl.CallCommand(33925)
## Remap indexes to correct location
for i in range(32, len(glyphs)):
glyphs[i].unicode = i
font.GenerateNames()
glyphs[i].width = width
## Remap indexes to correct location
for i in range(32, len(glyphs)):
glyphs[i].unicode = i
font.GenerateNames()
glyphs[i].width = width
fl.UpdateFont()
## Back to names mode
fl.CallCommand(33208)
## Remove empty glyphs
namesToKeep = [ '.notdef', 'NULL', 'CR', 'space' ]
for glyph in reversed(glyphs):
if not glyph.nodes and not glyph.components:
if not glyph.name in namesToKeep:
del glyphs[font.FindGlyph(glyph.name)]
fl.UpdateFont()
## Save & generate
ttfname = os.path.splitext(font.file_name)[0] + ".ttf"
fl.GenerateFont(ftTRUETYPE, ttfname)
fl.Save(font.file_name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment