Skip to main content

FoundryTools

FoundryTools is a Python library for working with font files and their data. It provides a high-level interface for inspecting, manipulating, and converting fonts, leveraging the capabilities of the fontTools library and other font-related tools, such as AFDKO, cffsubr, defcon, dehinter, skia-pathops, ttfautohint-py, ufo2ft, and ufo-extractor.

The library is designed to simplify font processing tasks, such as reading and writing font files, accessing font tables and metadata, modifying glyph data, and converting fonts between different formats. It offers a set of classes and utilities for working with fonts at various levels of abstraction, from low-level font table manipulation to high-level font inspection and conversion.

FoundryTools is intended for font developers, type designers, font engineers, and anyone working with font files who needs a programmatic way to interact with font data. It provides a Pythonic API for common font operations and can be used in scripts, tools, and workflows that involve font processing.

Below is an overview of the key components and features of FoundryTools, while the detailed documentation can be found at the following link: https://foundrytools.readthedocs.io/en/latest/

Table of Contents

Installation

FoundryTools requires Python 3.11 or later.

pip

FoundryTools releases are available on the Python Package Index (PyPI), so it can be installed with pip:

python -m pip install foundrytools

Editable mode

If you would like to contribute to the development, clone the repository from GitHub and use uv to create an environment and install the package in editable mode.

# clone the repository:
git clone https://github.com/ftCLI/FoundryTools.git
cd foundrytools

# create the environment and install the package with development dependencies:
uv sync --group dev

Font Class: High-Level Wrapper for TTFont

Overview

The Font class is a high-level wrapper around the TTFont class from the fontTools library, providing a user-friendly interface for working with font files and their data. It simplifies font manipulation and offers various utilities for accessing and modifying font-specific properties.

Features

  • Load fonts from file paths (str or Path), BytesIO objects, and TTFont instances.
  • Manipulate font tables, attributes, and metadata.
  • Provides Pythonic getter and setter properties for accessing internal font data.
  • Works as a context manager to automatically manage resources.

Initialization

The class is initialized with the following parameters:

  • `font_source`: A path to a font file (as str or Path), a BytesIO object, or an existing TTFont instance.
  • `lazy` (Optional[bool], Default: None): Controls whether font data is loaded lazily (on-demand) or eagerly (immediately). The default value None falls somewhere between.
  • `recalc_bboxes` (bool, Default: True): Recalculates glyf, CFF, head bounding box values, and hhea/vhea min/max values when saving the font.
  • `recalc_timestamp` (bool, Default: False): Updates the font’s modified timestamp in the head table when saving.

Example Usage:

from io import BytesIO

from foundrytools import Font

# Loading a font from a file
font = Font("path/to/font.ttf")
print(font.file)  # Access the file path

# Loading a font from BytesIO
with open("path/to/font.ttf", "rb") as f:
    font_data = BytesIO(f.read())
font = Font(font_data)
print(font.bytesio)  # BytesIO object access

# Using the class as a context manager
with Font("path/to/font.ttf") as font:
    print(font.ttfont)  # Access the TTFont object

Font Initialization

The _init_font method performs automatic loading of fonts based on the font_source parameter.

Supported methods for loading fonts:

  • _init_from_file: Loads from a file.
  • _init_from_bytesio: Loads from an in-memory BytesIO object.
  • _init_from_ttfont: Loads from an already initialized TTFont.

Style Flags Initialization

The flags attribute is initialized to an instance of the StyleFlags class, which provides convenience methods for managing font styles. It abstracts away low-level bitwise operations on the font tables (OS/2 and head). Instead, users can interact with properties like is_bold, is_italic, is_regular, is_oblique to check or modify the font's style easily.

from foundrytools.core.font import Font

font = Font("path/to/font.ttf")
print(font.flags.is_bold)  # Check if the font is bold
font.flags.is_bold = True  # Set the font as bold
font.flags.is_italic = False  # Set the font as non-italic
font.flags.is_oblique = True  # Set the font as oblique
# The is_regular property is read-only, as it is inferred from the other style flags. To set the
# font as regular, use the set_regular method.
font.flags.set_regular()  # Set the font as regular

Tables Initialization

The _init_tables method initializes placeholders for various font tables, ensuring that they are ready to be loaded when accessed. The method sets up the initial state for each table in the font.

def _init_tables(self) -> None:
    """
    Initialize all font table attributes to None. This method sets up the initial state
    for each table in the font, ensuring that they are ready to be loaded when accessed.
    """
    self._cff: Optional[CFFTable] = None
    self._cmap: Optional[CmapTable] = None
    self._fvar: Optional[FvarTable] = None
    self._gdef: Optional[GdefTable] = None
    self._glyf: Optional[GlyfTable] = None
    self._gsub: Optional[GsubTable] = None
    self._head: Optional[HeadTable] = None
    self._hhea: Optional[HheaTable] = None
    self._hmtx: Optional[HmtxTable] = None
    self._kern: Optional[KernTable] = None
    self._name: Optional[NameTable] = None
    self._os_2: Optional[OS2Table] = None
    self._post: Optional[PostTable] = None

Font Tables

Font Tables Access

The _get_table method is a private helper function within the Font class, designed to manage and retrieve font table objects. It utilizes lazy loading, meaning that it only initializes and loads a font table when it is explicitly requested, leading to better performance and reduced memory usage. Below is a step-by-step explanation.

TABLES_LOOKUP = {
    "CFF ": ("_cff", CFFTable),
    "cmap": ("_cmap", CmapTable),
    "fvar": ("_fvar", FvarTable),
    "GDEF": ("_gdef", GdefTable),
    "glyf": ("_glyf", GlyfTable),
    "GSUB": ("_gsub", GsubTable),
    "head": ("_head", HeadTable),
    "hhea": ("_hhea", HheaTable),
    "kern": ("_kern", KernTable),
    "hmtx": ("_hmtx", HmtxTable),
    "name": ("_name", NameTable),
    "OS/2": ("_os_2", OS2Table),
    "post": ("_post", PostTable),
}


def _get_table(self, table_tag: str):  # type: ignore
    table_attr, table_cls = TABLES_LOOKUP[table_tag]
    if getattr(self, table_attr) is None:
        if self.ttfont.get(table_tag) is None:
            raise KeyError(f"The '{table_tag}' table is not present in the font")
        setattr(self, table_attr, table_cls(self.ttfont))
    table = getattr(self, table_attr)
    if table is None:
        raise KeyError(f"An error occurred while loading the '{table_tag}' table")
    return table
  • Purpose:
    • Accepts table_tag, a string identifier corresponding to a specific table in the font file (e.g., "CFF", "cmap", etc.).
    • Looks up table_tag in the TABLES_LOOKUP dictionary or mapping, which provides:
      • table_attr: The attribute name in the Font object where the table is stored.
      • table_cls: The class used to instantiate the requested table.
    • Checks if the corresponding table attribute (table_attr) already exists (i.e., has been previously loaded).
    • If it is None, the method proceeds to load the table.
    • Verifies whether the requested table (table_tag) is present in the underlying TTFont object (self.ttfont).
    • If the table is missing from the font file, it raises a KeyError to notify the caller.
    • If the table exists, it is instantiated using the corresponding table class (table_cls) and passed the TTFont object (self.ttfont) as an argument.
    • The table instance is then stored in the Font object as an attribute using setattr.
    • Retrieves the table object stored in the Font object after ensuring its proper initialization.
    • As a safeguard, checks if the table object is still None.
    • If it has not been successfully instantiated, an error is raised to indicate a failure during the loading process.

The _get_table method is commonly used in property methods of the Font class to provide easy access to specific font tables. For example:

@property
def t_cff_(self) -> CFFTable:
    return self._get_table("CFF ")

In the above code snippet:

  • The t_cff_ property calls _get_table with the table tag "CFF".
  • _get_table ensures that the CFF table, if not already initialized, is loaded and stored in the Font object.
  • The returned table object is of type CFFTable, which is a wrapper around Font.ttfont['CFF '] table.
  • The same pattern is followed for other tables such as t_cmap, t_name, t_os_2, etc.

Accessing font tables is straightforward using the Font class. For example, to access the CFF table of a font:

from foundrytools import Font

font = Font("path/to/font.otf")
cff_table = font.t_cff_

The CFFTable object is defined in the core.tables.cff_ module and provides a wrapper around the CFF table (i.e., a fontTools.ttLib.tables.C_F_F_.table_C_F_F_ object), adding convenience methods for common operations.

For example:

from foundrytools.core.font import Font

font = Font("path/to/font.otf")
font.t_cff_.remove_hinting()
font.t_cff_.round_coordinates()
font.save("path/to/font_2.otf")

Another example accessing the name and OS/2 tables:

from foundrytools import Font

font = Font("path/to/font.otf")
font.t_name.remove_unused_names()
font.t_name.find_replace("Old Family Name", "New Family Name")
font.t_os_2.weight_class = 400
font.t_os_2.recalc_unicode_ranges(percentage=33.0)

Table wrappers provide the table property to access the wrapped ttLib.tables objects.

The following lines are equivalent:

font.t_name.table.getBestFamilyName()  # Access the wrapped ttLib.tables._n_a_m_e.table__n_a_m_e object

font.ttfont["name"].getBestFamilyName()  # This is equivalent to the above line

Tables can also be accessed directly, without using the Font class:

from fontTools.ttLib import TTFont
from foundrytools.core.tables.post import PostTable

ttfont = TTFont("path/to/font.ttf")

post = PostTable(ttfont)
post.italic_angle = 0.0
post.underline_position = -100

ttfont.save("path/to/font_2.ttf")

Supported Tables

The following tables are currently supported, other tables will be added as needed:

  • CFF: t_cff_ (CFFTable)
  • cmap: t_cmap (CmapTable)
  • fvar: t_fvar (FvarTable)
  • GDEF: t_gdef (GdefTable)
  • GSUB: t_gsub (GsubTable)
  • glyf: t_glyf (GlyfTable)
  • head: t_head (HeadTable)
  • hhea: t_hhea (HheaTable)
  • hmtx: t_hmtx (HmtxTable)
  • kern: t_kern (KernTable)
  • name: t_name (NameTable)
  • OS/2: t_os_2 (OS2Table)
  • post: t_post (PostTable)

Style Flags

The Font class provides a set of style flags to simplify font style management. These flags are used to determine the font style based on the font’s attributes, such as weight, italic, and obliqueness.

The following style flags are available:

  • `is_bold` (bool):
    • Returns True if the font is bold based on the OS/2 table’s and head table’s values.
    • Provides a setter to update the bold flag.
  • `is_italic` (bool):
    • Returns True if the font is italic based on the OS/2 table’s and head table’s values.
    • Provides a setter to update the italic flag.
  • `is_regular` (bool):
    • Returns True if the font is regular based on the OS/2 table’s and head table’s values.
    • This property is read-only and inferred from the other style flags. To set the font as regular, use the set_regular method.
  • `is_oblique` (bool):
    • Returns True if the font is oblique based on the OS/2 table’s and head table’s values.
    • Provides a setter to update the oblique flag.

Properties

The following properties provide accessible abstractions of internal font data:

  • `file`:
    • Returns the font’s file path (or None if not loaded from file).
    • Provides a setter to update the file path.
  • `bytesio`:
    • Returns the in-memory BytesIO object containing the font data.
    • Provides a setter to update the BytesIO object.
  • `ttfont`:
    • Returns the wrapped TTFont object.
    • Provides a setter for replacing the TTFont object.
  • `temp_file`: A placeholder for temporary file path of the font, in case it is needed for some operations.
  • `is_ps` (bool): Indicates if the font contains PostScript outlines based on TTFont.sfntVersion.
  • `is_tt` (bool): Indicates if the font contains TrueType outlines based on TTFont.sfntVersion.
  • `is_woff` (bool): Indicates if the font is in the WOFF format by checking the flavor attribute.
  • `is_woff2` (bool): Indicates if the font is in the WOFF2 format by checking the flavor attribute.
  • `is_static` (bool): Indicates if the font is a static font by checking for the absence of a fvar table.
  • `is_variable` (bool): Indicates if the font is a variable font by checking for the presence of a fvar table.

Advanced Features

  • Context Management: The Font class supports the with statement. On entering the context, it returns the Font instance, and upon exiting, it releases allocated resources (e.g., closing files, clearing temporary data).
  • Rebuilding and Reloading:
    • reload: Reload the font by saving it to a temporary stream and reloading from it.
    • rebuild: Save the font as XML to a temporary stream and then re-import it.
  • Conversion Utilities:
    • to_woff: Converts the font into WOFF format.
    • to_woff2: Converts the font into WOFF2 format.
    • to_ttf: Converts a PostScript font into TrueType.
    • to_otf: Converts a TrueType font into PostScript.
    • to_sfnt: Converts WOFF/WOFF2 fonts to SFNT format.
  • Subsetting Operations:
    • remove_glyphs: Removes specified glyphs from the font.
    • remove_unused_glyphs: Removes glyphs that are unreachable by Unicode values or lookup rules.
  • Contours:
    • correct_contours: Adjusts glyph contours for overlaps, contour direction errors, and small paths.
    • scale_upm: Scales the font’s units per em (UPM).
  • Sorting and Managing Glyph Order:
    • rename_glyph: Rename specific glyphs in the font.
    • rename_glyphs: Renames all glyphs in the font based on a custom mapping.
    • sort_glyphs: Sorts glyphs based on Unicode values, alphabetical order, or design order.

FontFinder Class: Font Search and Filtering

Overview

The FontFinder class is a robust Python tool designed to search for font files in a directory, with options for filtering, customization, and recursion. It simplifies the process of finding fonts based on specific criteria and supports the handling of single files and directories. It is particularly useful in scenarios involving large font repositories or automated font processing pipelines. With its built-in filtering and customization options, it provides a robust way to manage fonts programmatically.

Features:

  • Recursive Search: Searches directories and subdirectories for font files.
  • Filtering: Supports filtering by font type (TrueType/PostScript), web font flavor (woff, woff2), and font variations (static/variable).
  • Customizable Options: Options for lazy processing, recalculation of timestamps, and bounding boxes.
  • Error Handling: Handles invalid input paths and conflicting filter conditions.

Constructor

__init__(input_path: Path, options: Optional[FinderOptions] = None, filter_: Optional[FinderFilter] = None)

Initializes the FontFinder instance.

  • Parameters:

    • input_path (Path): The file or directory path to search for fonts.
    • options (FinderOptions): Optional class containing customizable search options. If not provided, defaults to sensible defaults.
    • filter_ (FinderFilter): Optional class used to filter results based on font properties.
  • Key Actions:

    • Resolves the input_path to an absolute path. If invalid, a FinderError is raised.
    • Generates filter conditions from the provided filter_.
    • Validates that no conflicting filters are in use.

Main Methods

find_fonts()

Returns a list of Fonts that meet the specified conditions.

  • Description: This method evaluates font files in the given path and applies the specified filter conditions.

  • Example:

from foundrytools.lib.font_finder import FontFinder

finder = FontFinder(input_path="path/to/fonts")
fonts = finder.find_fonts()
for font in fonts:
    print(font.file)

generate_fonts()

A generator function that yields Font objects one by one.

  • Purpose: Useful when memory efficiency is critical and a large number of files are processed.

  • Yield:

    • An object of type Font for each font matching the criteria.
  • Exceptions:

    • Skips files that raise TTLibError or PermissionError.

Private Methods

_generate_files()

Generates file paths from the given input_path.

  • Description:

    • If input_path is a file, it yields that file.
    • If input_path is a directory:
      • Searches recursively (Path.rglob("*")) if the recursive option is True.
      • Searches non-recursively (Path.glob("*")) otherwise.
  • Yield:

    • Paths to files that match the criteria.

_validate_filter_conditions()

Ensures that no conflicting filter conditions are present.

  • Raises:
    • FinderError if:
      • Both TrueType (filter_out_tt) and PostScript (filter_out_ps) are excluded.
      • All web fonts (woff, woff2) and standard fonts (sfnt) are excluded.
      • Both static and variable fonts are excluded.

_generate_filter_conditions(filter_: FinderFilter)

Converts the provided FinderFilter into executable filter conditions.

  • Parameters:

    • filter_: Instance of FinderFilter.
  • Returns:

    • A list of tuples, where each tuple consists of:
      1. A boolean indicating whether the filter is enabled.
      2. A callable function that checks a font property.

Usage

Basic Example:

from foundrytools.lib.font_finder import FontFinder

# Path to process
path = "path/to/fonts/"

# Initialize FontFinder with default options
finder = FontFinder(input_path=path)

# Find fonts
fonts = finder.find_fonts()

# Process fonts
for font in fonts:
    print(font)

Example with Recursion and Filtering:

from foundrytools.lib.font_finder import FontFinder, FinderOptions, FinderFilter

options = FinderOptions(recursive=True, lazy=True)
filter_ = FinderFilter(filter_out_tt=True, filter_out_woff=True)

finder = FontFinder(input_path="path/to/fonts", options=options, filter_=filter_)

for font in finder.generate_fonts():
    print(font.file)

The apps package

The apps package contains pre-built applications that leverage the Font class and other utilities provided by FoundryTools. These applications are designed to perform specific font processing tasks, such as fixing errors, autohinting, and more.

Please refer to the individual modules within the apps package for detailed information on each application.

An example of using the fix_italic_angle application:

from foundrytools.lib.font_finder import FontFinder
from foundrytools.app.fix_italic_angle import run as fix_italic_angle

finder = FontFinder(input_path="path/to/fonts")
fonts = finder.find_fonts()

for font in fonts:
    fix_italic_angle(font)
    font.save(font.file.with_name(f"{font.file.stem}_fixed.ttf"))

Metadata

Release files for foundrytools 0.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for foundrytools 0.1.7
File Size Uploaded
foundrytools-0.1.7.tar.gz 1.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for foundrytools 0.1.7
File Interpreter ABI Platform
foundrytools-0.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 2.8 MB

Release files / foundrytools-0.1.7.tar.gz

Download URL foundrytools-0.1.7.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
7b8623bf1618931dabdbd4d75aba4b200582555c86f9f7d5d7c1819d5d04fef8
BLAKE2b-256 checksum
How to use checksums
067b47f9c2c629bebd124fbe97379dd61bc871e9c183f15fa79d3bae2efeb713
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / foundrytools-0.1.7-py3-none-any.whl

Download URL foundrytools-0.1.7-py3-none-any.whl
Size 1.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
49a77f471143dcc885270313b1966c6a3834d81bc9d1f71c7f8b3c40a6afe9be
BLAKE2b-256 checksum
How to use checksums
7d6e876011cf26a539ea1a67154c47ef2b242da5d6af24d7eaaafbb2bdd98c2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.7 This release

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page