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.
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.
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:
- Users of office suites like LibreOffice or OpenOffice.
- Graphic designers working with software that might not support specific OpenType features (e.g., some versions of Microsoft Office have limited small caps support).
- Anyone who wants a font variant where certain features are always active without manual intervention.
- Accessibility: Unlocks advanced typography in a wider range of applications.
- Consistency: Ensures that specific typographic styles (like old-style figures) are used consistently without needing to remember to enable features.
- Convenience: Creates ready-to-use font versions with desired features baked in.
OpenType Feature Freezer is available in two forms:
- OTFeatureFreezer (GUI): A graphical application for macOS and Windows.
- pyftfeatfreeze (CLI): A command-line tool for users comfortable with terminal commands.
- Download the DMG for macOS
- Open the downloaded DMG file.
- Drag the
OTFeatureFreezer.app
icon to your/Applications
folder. - First Run: Ctrl+click the
OTFeatureFreezer.app
icon in/Applications
, choose "Open" from the menu, and then click "Open" in the dialog box. - Subsequent Runs: Double-click the app icon.
- Download the ZIP for Windows
- You need a 64-bit version of Windows (7 or newer).
- Unzip the downloaded file.
- Run
setup_featfreeze.exe
to install the application. - Launch "OTFeatureFreezer" from your Start Menu.
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
The GUI provides an easy-to-use interface for all the freezing and renaming options:
- Input Font File: Click to browse and select your input
.otf
or.ttf
font file. - Output Font File: Specify where to save the modified font (
[input_filename].featfreeze.otf
by default). - 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.
- Features: Enter a comma-separated list of OpenType feature tags (e.g.,
- 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.
- 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.
- 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.
The basic command structure is:
pyftfeatfreeze [OPTIONS] INPATH [OUTPATH]
INPATH
: Path to the input.otf
or.ttf
font file.OUTPATH
: Optional path for the output font file. If omitted, it defaults toINPATH.featfreeze.otf
.
Common CLI Options:
-f TAGS, --features TAGS
: Comma-separated OpenType feature tags (e.g.,'smcp,c2sc'
).-s SCRIPT, --script SCRIPT
: OpenType script tag (e.g.,cyrl
). If omitted, processing applies to all relevant scripts.-l LANG, --lang LANG
: OpenType language tag (e.g.,SRB
).-S, --suffix
: Add a suffix to font family name (derived from feature tags).-U SUFFIX, --usesuffix SUFFIX
: Use a custom suffix (e.g.,SC
) when-S
is active.-R 'S/R,...', --replacenames 'S/R,...'
: Search and replace strings in font names (e.g.,'MyFont/MyFontNew,Regular/Reg'
).-z, --zapnames
: Zap glyph names from TTF fonts.-i, --info
: Update font version string.-r, --report
: Report font's features, scripts, languages instead of processing.-n, --names
: Output names of remapped glyphs.-v, --verbose
: Print detailed processing information.-V, --version
: Show program version.-h, --help
: Show help message with all options.
CLI Examples:
-
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
-
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. -
Only rename parts of the font's internal name (no feature freezing):
pyftfeatfreeze -R 'Lato/Otal,Regular/Rg' Lato-Regular.ttf Otal-Rg.ttf
The core logic resides in the RemapByOTL
class within src/opentype_feature_freezer/__init__.py
. The process flow is as follows:
- Font Opening: The input font file is opened using
fontTools.ttLib.TTFont
. - 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
, theDefaultLangSys
for that script is used.
- 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]
).
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."
- The font's character map (
- Font Renaming (Optional):
- If requested via options like
--suffix
,--usesuffix
, or--replacenames
, the tool modifies various name records in thename
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 updatesFamilyName
,FullName
, and the main font name in theCFF
table.
- If requested via options like
- Glyph Name Zapping (Optional):
- For TrueType-flavored fonts (
.ttf
), the--zapnames
option sets thepost
table format to 3.0. This removes glyph names from the font, which can sometimes reduce file size but makes debugging harder.
- For TrueType-flavored fonts (
- Font Saving: The modified font object is saved to the output path using
fontTools.ttLib.TTFont.save()
.
Key Modules:
src/opentype_feature_freezer/__init__.py
: Contains theRemapByOTL
class with the primary font processing logic.src/opentype_feature_freezer/cli.py
: Implements thepyftfeatfreeze
command-line interface using Python'sargparse
module. It parses arguments and passes them toRemapByOTL
.app/OTFeatureFreezer.py
: Usesezgooey
to wrap theargparse
definitions fromcli.py
, creating theOTFeatureFreezer
GUI application for macOS and Windows.
Limitations:
- Supported Substitutions: Primarily handles GSUB Single (Type 1) and Alternate (Type 3) substitutions, including those within Extension (Type 7) lookups. It does not process other GSUB lookup types like Ligature, Multiple, or Chaining Contextual substitutions.
cmap
Dependency: The tool works by remapping existingcmap
entries. If a glyph involved in a substitution (either the original or the replacement) does not have a Unicode value assigned in anycmap
table, that specific remapping might not have a visible effect through standard character input. A warning is issued in such cases.- Global Feature Application: Features are applied based on the chosen script and language for the entire font. The tool does not interpret complex conditional logic within OpenType feature definitions themselves.
- Python Version: The codebase targets Python 3.6 and newer.
- Type Hinting: Modern Python type hints are used throughout the code for improved clarity, maintainability, and to facilitate static analysis. See
typing
module usage. - Logging: The standard
logging
module is used for outputting informational messages, warnings, and errors. Verbosity is controlled by the-v
flag. - Project & Dependency Management: Poetry is used for managing dependencies, building the package, and publishing. Configuration is in
pyproject.toml
. - Static Analysis: MyPy is used for static type checking, with configuration in
mypy.ini
. - Testing: pytest is used for unit and integration testing. Tests are located in the
tests/
directory. - Code Style: While no specific linter (like Flake8 or Black) is explicitly configured in
pyproject.toml
apart from MyPy, contributions should generally follow PEP 8 guidelines and maintain consistency with the existing codebase.
Contributions are welcome! Whether it's reporting a bug, suggesting an improvement, or submitting code changes.
Reporting Issues:
- Please use the GitHub Issues page to report bugs or request features.
- Provide clear steps to reproduce bugs, including the font file (if possible and license permits), the command used, and observed vs. expected behavior.
Development Setup:
- Ensure you have Python 3.6+ and Poetry installed.
- Clone the repository:
git clone https://github.com/twardoch/fonttools-opentype-feature-freezer.git
- Navigate into the project directory:
cd fonttools-opentype-feature-freezer
- Install development dependencies, including
pytest
andmypy
, in a virtual environment using Poetry:poetry install
- Activate the virtual environment:
poetry shell
Building:
-
Python Package (Wheel/sdist):
poetry build
The distributable files will be in the
dist/
directory. -
GUI Applications (DMG for macOS, EXE for Windows):
- Building these requires a macOS environment.
- Navigate to the
app/
subdirectory. - Run the deployment script:
cd app ./macdeploy all
- This script uses PyInstaller and other tools to package the GUI application.
Running Tests:
- Ensure you have installed development dependencies (
poetry install
). - Run
pytest
from the project root directory:Or, if your environment is not yet active:pytest
poetry run pytest
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.
- Python 3.6 or newer.
- fontTools (automatically installed as a dependency).
- For the GUI (OTFeatureFreezer): ezgooey (automatically installed).
- 1.32.2 (and recent versions): Ongoing type hinting improvements, CI updates, and minor bug fixes.
- 1.32: Changed the
-s
(script) option: if not provided, remapping attempts to apply to all relevant scripts. - 1.31: Changed the
-S
(suffix) option: if not provided, no suffix is added. Introduced GUI apps.
For older history, this tool was previously part of the fonttools-utils
repository.
- Original code and ongoing development by Adam Twardoch.
- Contributions from various developers (see
AUTHORS
andCONTRIBUTORS
files, and GitHub commit history). - Built upon the powerful
fontTools
library.
<script async defer src="https://buttons.github.io/buttons.js"></script>