fonttools-opentype-feature-freezer

OTFeatureFreezer GUI app and pyftfeatfreeze commandline tool in Python to permanently "apply" OpenType features to fonts, by remapping their Unicode assignments

View the Project on GitHub twardoch/fonttools-opentype-feature-freezer

OpenType Feature Freezer: Make Advanced Typography Accessible Everywhere

OpenType Feature Freezer is a powerful tool designed to make sophisticated typographic features, like small caps or old-style numerals, accessible by default in your fonts. This means you can use these features even in applications with limited or no OpenType support.

Part 1: For Everyone Using Fonts

What Does It Do?

Many professional fonts come with “OpenType features” – special typographic effects such as true small capitals, alternative character shapes, ligatures, or figures (numbers) that align differently with text. Normally, you need specific software that allows you to turn these features on.

OpenType Feature Freezer modifies a font file so that selected OpenType features are “frozen” into it. The characters that were previously only accessible via these features become the default characters in the modified font.

For example, if you freeze the “small caps” (smcp) feature, typing lowercase letters will directly produce small capitals.

Who Is It For?

This tool is for anyone who wants to use advanced typographic features in applications that don’t provide easy access to OpenType controls. This includes:

Why Is It Useful?

Installation

OpenType Feature Freezer is available in two forms:

OTFeatureFreezer GUI App (macOS)

  1. Download the DMG for macOS
  2. Open the downloaded DMG file.
  3. Drag the OTFeatureFreezer.app icon to your /Applications folder.
  4. First Run: Ctrl+click the OTFeatureFreezer.app icon in /Applications, choose “Open” from the menu, and then click “Open” in the dialog box.
  5. Subsequent Runs: Double-click the app icon.

OTFeatureFreezer GUI App (Windows 64-bit)

  1. Download the ZIP for Windows
  2. You need a 64-bit version of Windows (7 or newer).
  3. Unzip the downloaded file.
  4. Run setup_featfreeze.exe to install the application.
  5. Launch “OTFeatureFreezer” from your Start Menu.

pyftfeatfreeze CLI App (All Platforms)

This requires Python 3.6 or newer. If you don’t have Python, get it from python.org or your system’s package manager.

Recommended Method (using pipx): Pipx installs Python command-line tools in isolated environments, which is clean and convenient.

pipx install opentype-feature-freezer

To upgrade later:

pipx upgrade opentype-feature-freezer

Alternative Method (using pip): It’s generally recommended to run pip via python3 -m pip to ensure you’re using pip associated with the correct Python installation, especially if you have multiple Python versions. It’s best to do this inside a Python virtual environment:

python3 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
python3 -m pip install --upgrade opentype-feature-freezer

If the above fails, or for a user-specific installation (avoids needing admin rights):

python3 -m pip install --user --upgrade opentype-feature-freezer

Development Version (from GitHub - for testing latest changes):

python3 -m pip install --upgrade git+https://github.com/twardoch/fonttools-opentype-feature-freezer

How to Use

Using the OTFeatureFreezer GUI

The GUI provides an easy-to-use interface for all the freezing and renaming options:

  1. Input Font File: Click to browse and select your input .otf or .ttf font file.
  2. Output Font File: Specify where to save the modified font ([input_filename].featfreeze.otf by default).
  3. Options to control feature freezing:
    • Features: Enter a comma-separated list of OpenType feature tags (e.g., smcp,c2sc,onum). These are the features you want to “freeze.”
    • Script: Optionally, specify an OpenType script tag (e.g., cyrl, latn) to apply features only for that script. If blank, features are applied across all relevant scripts.
    • Lang: Optionally, specify an OpenType language tag (e.g., SRB for Serbian) to apply features for that specific language system.
    • Zap glyphnames…: (Advanced, TTF only) Removes glyph names from the font, potentially reducing file size.
  4. Options to control font renaming:
    • Add a suffix to the font family name: If checked, a suffix is added. By default, this suffix is constructed from the frozen feature tags (e.g., “MyFont SMCP C2SC”).
    • Use a custom suffix…: If the above is checked, you can specify your own suffix here (e.g., “SC”).
    • Search for strings…: Allows renaming parts of the font’s internal names. Format: search1/replace1,search2/replace2.
    • Update font version string: Adds information about the frozen features to the font’s version string.
  5. Reporting options:
    • Report languages, scripts and features…: Instead of modifying the font, this option prints out information about the features, scripts, and languages present in the input font.
    • Output names of remapped glyphs…: Prints the names of glyphs that were changed during the freezing process.
    • Print additional information…: Verbose mode, shows more details during processing.
  6. Click “Run” (or the equivalent button, often the program name itself at the bottom of the Gooey interface) to process the font.

The GUI includes a “Help” menu with links to “About” information and the project’s online documentation.

Using the pyftfeatfreeze CLI

The basic command structure is:

pyftfeatfreeze [OPTIONS] INPATH [OUTPATH]

Common CLI Options:

CLI Examples:

  1. Freeze small caps and old-style numerals, add “SC OS” suffix, rename “OpenSans” to “OpenSansSC”:
    pyftfeatfreeze -f 'c2sc,smcp,onum' -S -U "SC OS" -R 'OpenSans/OpenSansSO' OpenSans-Regular.ttf OpenSansSO-Regular.ttf
    
  2. Freeze Bulgarian localized forms (locl for Cyrillic script, Bulgarian language), add “BG” suffix:
    pyftfeatfreeze -f 'locl' -s 'cyrl' -l 'BGR ' -S -U BG MyFont.otf MyFontBG.otf
    

    Note: To remap features for multiple script/language combinations, run the tool multiple times, using the output of one run as the input for the next. Apply renaming options (-S, -U, -R) typically on the final run.

  3. Only rename parts of the font’s internal name (no feature freezing):
    pyftfeatfreeze -R 'Lato/Otal,Regular/Rg' Lato-Regular.ttf Otal-Rg.ttf
    

Part 2: For Developers & Contributors

How the Code Works (Internals)

The core logic resides in the RemapByOTL class within src/opentype_feature_freezer/__init__.py. The process flow is as follows:

  1. Font Opening: The input font file is opened using fontTools.ttLib.TTFont.
  2. Feature and Lookup Filtering:
    • The tool identifies relevant GSUB (Glyph Substitution) lookups.
    • It filters these lookups based on user-specified OpenType feature tags (--features), script tag (--script), and language tag (--lang).
    • If no script is specified, the tool attempts to apply features across all relevant scripts by processing each script tag found. For language systems within a script, if a specific language is not given or does not match an existing LangSysRecord, the DefaultLangSys for that script is used.
  3. Substitution Application:
    • It processes GSUB LookupType 1 (Single Substitution) and LookupType 3 (Alternate Substitution).
    • It also handles LookupType 7 (Extension Substitution) which can wrap Type 1 or Type 3 lookups.
    • A substitution mapping is built, tracking which original glyph names should be replaced by which new glyph names. For alternate substitutions, the first alternate glyph from the list is chosen (e.g., a.alt1 from [a.alt1, a.alt2]).
  4. cmap Remapping:
    • The font’s character map (cmap table) is modified. Existing Unicode codepoints that pointed to original glyphs are updated to point to the new glyphs resulting from the applied substitutions. This is what makes the features “default.”
  5. Font Renaming (Optional):
    • If requested via options like --suffix, --usesuffix, or --replacenames, the tool modifies various name records in the name table (e.g., Family Name (ID 1), Full Name (ID 4), PostScript Name (ID 6), Version String (ID 5), Unique ID (ID 3), WWS Family/Subfamily (ID 16, 17)).
    • For CFF-based OpenType fonts (.otf), it also updates FamilyName, FullName, and the main font name in the CFF table.
  6. Glyph Name Zapping (Optional):
    • For TrueType-flavored fonts (.ttf), the --zapnames option sets the post table format to 3.0. This removes glyph names from the font, which can sometimes reduce file size but makes debugging harder.
  7. Font Saving: The modified font object is saved to the output path using fontTools.ttLib.TTFont.save().

Key Modules:

Limitations:

Coding Rules & Conventions

Contributing

Contributions are welcome! Whether it’s reporting a bug, suggesting an improvement, or submitting code changes.

Reporting Issues:

Development Setup:

  1. Ensure you have Python 3.6+ and Poetry installed.
  2. Clone the repository:
    git clone https://github.com/twardoch/fonttools-opentype-feature-freezer.git
    
  3. Navigate into the project directory:
    cd fonttools-opentype-feature-freezer
    
  4. Install development dependencies, including pytest and mypy, in a virtual environment using Poetry:
    poetry install
    
  5. Activate the virtual environment:
    poetry shell
    

Building:

Running Tests:

Other Information

Software License and Disclaimer

This tool is licensed “as is” under the Apache License, Version 2.0. By using the tool, you accept all conditions of the license, including Disclaimer of Warranty and Limitation of Liability.

Important: When modifying fonts, please ensure you comply with the font’s End User License Agreement (EULA). If the font is licensed under the SIL Open Font License (OFL) and uses Reserved Font Name(s), you must use the -R (rename) option to change the font’s name if you plan to distribute the modified version.

Requirements

Changelog (Recent Highlights)

For older history, this tool was previously part of the fonttools-utils repository.

Credits


Star Watch Fork