Skip to content

Instantly share code, notes, and snippets.

@simoncozens
simoncozens / sparsify.py
Last active April 26, 2024 17:48
sparsify.py - turn masters into sparse masters
import uuid
from glyphsLib import load, GSPath, GSNode, GSLayer
from fontTools.varLib.models import VariationModel, normalizeValue
import numpy as np
from tqdm import tqdm
import argparse
def interpolate_paths_without(glyph, intermediate_layer, intermediate_location):
tags = [axis.axisTag for axis in glyph.parent.axes]
@simoncozens
simoncozens / debug-merge.py
Created January 31, 2024 09:40
Helper script to debug merge issues in fonttools -o variable
from glyphsLib import load, to_designspace
from ufo2ft.featureCompiler import FeatureCompiler, parseLayoutFeatures
from fontTools.feaLib import ast
import argparse
class Checker:
def __init__(self, sources):
self.masters = []
for source in sources:
@simoncozens
simoncozens / harmonization.md
Last active October 23, 2023 06:42
Harmonizing two Bezier curves

To harmonize (with G2 curvature) two cubic Bézier curves a0,a1,a2,a3 and b0,b1,b2,b3 where a2, a3 = b0, and b1 are colinear:

  • First find d = intersection point of line a1--a2 and line b1--b2.
  • Now find ratios p0 = |a1, a2| / |a2, d| and p1 = |d1, b1| / |b1, b2|.
  • Determine ratio p = sqrt(p0 * p1)
  • Now set position of a3 = b0 such that |a2, a3| / |a3, b1| == p.
  • To do this, set t = p / (p+1).
  • Adjust the position of a3=b0 so that it sits t of the way between a2 and b1.

Of course, you may prefer to keep the position of a3 because it's the on-curve point. Fine. Instead, compute where a3 should go according to this algorithm, work out the delta between the new position and the current position, and apply that delta to the handles a2 and b1 instead.

#!/opt/homebrew/bin/python3
import sys
sys.path.insert(0, "/Users/simon/others-repos/ufo2ft/Lib")
from glyphsLib.classes import GSFont
from glyphsLib.builder import UFOBuilder
from glyphsLib.builder.font import fill_ufo_metadata
from fontmake.font_project import FontProject
from timeit import default_timer as timer
import requests
from dateutil.relativedelta import relativedelta, FR
from datetime import datetime
import os
lastweek = datetime.utcnow().replace(hour=0,microsecond=0) + relativedelta(weekday=FR(-1))
headers = {"Authorization": "bearer "+os.environ["GITHUB_TOKEN"]}
def run_query(query):
import sys
import os
DEFAULT_NGRAM_SIZE = 5
def all_ngrams(word, size=None):
if size is None:
size = DEFAULT_NGRAM_SIZE
for i in range(max(1, len(word) - size)):
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables.otBase import OTTableWriter
import sys
from fontTools.feaLib.lookupDebugInfo import LOOKUP_DEBUG_INFO_KEY
font = TTFont(sys.argv[1])
def locate(table, ix):
if "Debg" not in font:
return str(ix)
@simoncozens
simoncozens / hands-face-space.ipynb
Last active February 15, 2023 00:39
Hands, Face, Space
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Justification with Variable Fonts

  • In JSTF header
Type Name Description
uint16 majorVersion Major version of the JSTF table, = 1
uint16 minorVersion Minor version of the JSTF table, = 0
uint16 jstfScriptCount Number of JstfScriptRecords in this table
JstfScriptRecord jstfScriptRecords[jstfScriptCount] Array of JstfScriptRecords, in alphabetical order by jstfScriptTag
@simoncozens
simoncozens / otvar-instance.py
Created September 27, 2016 10:04
OpenType Variation Instance Generator
#!/usr/bin/python
from fontTools.misc.py23 import *
from fontTools.ttLib import TTFont
import sys
import argparse
parser = argparse.ArgumentParser(description="OpenType Variation Instance Generator")
parser.add_argument('font', help="font file")
parser.add_argument('-a', '--all', action="store_true", help="Generate all instances")
parser.add_argument('-o', '--output', help="Output directory", default = ".")