CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-fonttools

Tools to manipulate font files

Pending
Overview
Eval results
Files

font-processing.mddocs/

Font Processing

Font optimization, subsetting, and merging tools for reducing file sizes, removing unused features, and combining multiple fonts into collections. These tools are essential for web font optimization and font distribution workflows.

Capabilities

Font Subsetting

Remove unused glyphs, features, and tables to create optimized fonts with smaller file sizes.

class Subsetter:
    def __init__(self, options=None):
        """
        Initialize font subsetter.

        Parameters:
        - options: Options, subsetting configuration (default: default options)
        """

    def subset(self, font):
        """
        Apply subsetting to TTFont instance.

        Parameters:
        - font: TTFont, font to subset (modified in-place)
        """

class Options:
    def __init__(self, **kwargs):
        """
        Subsetting configuration options.

        Parameters:
        - text: str, characters to keep (default: None)
        - unicodes: List[int], Unicode codepoints to keep
        - glyphs: List[str], glyph names to keep
        - layout_features: List[str], OpenType features to keep
        - name_IDs: List[int], name table entries to keep
        - name_languages: List[int], name table languages to keep
        - drop_tables: List[str], tables to remove
        - passthrough_tables: bool, keep unhandled tables
        - hinting: bool, keep hinting information
        - legacy_kern: bool, keep legacy kern table
        - symbol_cmap: bool, keep symbol character maps
        - ignore_missing_glyphs: bool, continue if glyphs missing
        - ignore_missing_unicodes: bool, continue if Unicode missing
        """

Basic Subsetting Example

from fontTools.subset import Subsetter, Options
from fontTools.ttLib import TTFont

# Load font
font = TTFont("input.ttf")

# Create subsetter with options
options = Options(
    text="Hello World!",  # Keep only these characters
    layout_features=['kern', 'liga'],  # Keep kerning and ligatures
    hinting=True,  # Preserve hinting
    ignore_missing_glyphs=True  # Don't fail on missing glyphs
)

subsetter = Subsetter(options)
subsetter.subset(font)

# Save subsetted font
font.save("output_subset.ttf")
font.close()

Advanced Subsetting

# Subset by Unicode ranges
options = Options(
    unicodes=list(range(0x20, 0x7F)) + list(range(0xA0, 0xFF)),  # Basic Latin + Latin-1
    layout_features=['kern', 'liga', 'clig', 'frac'],
    drop_tables=['DSIG', 'GSUB', 'GPOS'],  # Remove specific tables
    name_IDs=[1, 2, 3, 4, 5, 6],  # Keep essential name entries
    hinting=False  # Remove hinting for smaller size
)

subsetter = Subsetter(options)
subsetter.subset(font)

Web Font Optimization

def optimize_for_web(input_path, output_path, text_content):
    """Optimize font for web usage."""
    font = TTFont(input_path)
    
    # Web-optimized subsetting
    options = Options(
        text=text_content,
        layout_features=['kern', 'liga'],  # Common web features
        drop_tables=['DSIG', 'prep', 'fpgm', 'cvt '],  # Remove hinting tables
        hinting=False,  # Remove hinting
        desubroutinize=True,  # Flatten CFF subroutines
        passthrough_tables=False  # Drop unknown tables
    )
    
    subsetter = Subsetter(options)
    subsetter.subset(font)
    
    font.save(output_path)
    font.close()
    
    print(f"Optimized font saved to {output_path}")

Font Merging

Combine multiple fonts into a single font or font collection.

class Merger:
    def __init__(self, options=None):
        """
        Initialize font merger.

        Parameters:
        - options: Options, merging configuration
        """

    def merge(self, fontfiles):
        """
        Merge multiple fonts into single font.

        Parameters:
        - fontfiles: List[str], paths to font files to merge

        Returns:
        TTFont: Merged font
        """

class Options:
    def __init__(self, **kwargs):
        """
        Font merging options.

        Parameters:
        - verbose: bool, enable verbose output
        - timing: bool, report timing information
        - ignore_missing_glyphs: bool, continue on missing glyphs
        - drop_tables: List[str], tables to exclude from merge
        """

Basic Font Merging

from fontTools.merge import Merger, Options
from fontTools.ttLib import TTFont

# Merge multiple fonts
merger = Merger()
merged_font = merger.merge(["font1.ttf", "font2.ttf", "font3.ttf"])

# Save merged result
merged_font.save("merged_font.ttf")
merged_font.close()

Advanced Merging with Options

# Configure merging options
options = Options(
    verbose=True,
    ignore_missing_glyphs=True,
    drop_tables=['DSIG']  # Drop digital signatures
)

merger = Merger(options)

# Merge fonts with specific character ranges
latin_font = TTFont("latin.ttf")
cyrillic_font = TTFont("cyrillic.ttf") 
arabic_font = TTFont("arabic.ttf")

merged_font = merger.merge([latin_font, cyrillic_font, arabic_font])
merged_font.save("multilingual.ttf")

TTX XML Conversion

Convert fonts to/from TTX XML format for human-readable font analysis and modification.

def main(args=None):
    """
    Convert OpenType fonts to XML and back.

    Parameters:
    - args: List[str], command line arguments
      Common options:
      - -d: dump font to XML
      - -m: merge XML back to font
      - -t: specify tables to dump/compile
      - -x: exclude specific tables
      - -s: split tables into separate files
      - -i: don't disassemble TT instructions
      - -z: use WOFF2 compression
    """

TTX Usage Examples

import subprocess

# Convert font to XML
subprocess.run(["fonttools", "ttx", "font.ttf"])  # Creates font.ttx

# Convert specific tables only
subprocess.run(["fonttools", "ttx", "-t", "cmap", "-t", "name", "font.ttf"])

# Convert XML back to font
subprocess.run(["fonttools", "ttx", "font.ttx"])  # Creates font.ttf

# Split each table into separate XML file
subprocess.run(["fonttools", "ttx", "-s", "font.ttf"])

Command-Line Interface

FontTools provides command-line tools for batch processing:

def main(args=None):
    """
    Font subsetting command-line interface.

    Parameters:
    - args: List[str], command line arguments
    """

Command-Line Usage

# Subset font to specific text
fonttools subset font.ttf --text="Hello World"

# Subset with Unicode ranges
fonttools subset font.ttf --unicodes="U+0020-007F,U+00A0-00FF"

# Web font optimization
fonttools subset font.ttf --text-file=content.txt --layout-features="kern,liga" --no-hinting

# Merge fonts
fonttools merge font1.ttf font2.ttf font3.ttf

# TTX conversion
fonttools ttx font.ttf            # to XML
fonttools ttx font.ttx            # to binary

Error Handling

class SubsettingError(Exception):
    """Base subsetting exception."""

class MissingGlyphsSubsettingError(SubsettingError):
    """Required glyphs are missing from font."""

class MissingUnicodesSubsettingError(SubsettingError):  
    """Required Unicode codepoints are missing from font."""

Batch Processing Utilities

def process_font_directory(input_dir, output_dir, text_content):
    """Process all fonts in a directory."""
    import os
    from pathlib import Path
    
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)
    
    for font_file in input_path.glob("*.ttf"):
        try:
            font = TTFont(font_file)
            
            # Apply subsetting
            options = Options(text=text_content, hinting=False)
            subsetter = Subsetter(options)
            subsetter.subset(font)
            
            # Save with suffix
            output_file = output_path / f"{font_file.stem}_subset.ttf"
            font.save(output_file)
            font.close()
            
            print(f"Processed: {font_file.name} -> {output_file.name}")
            
        except Exception as e:
            print(f"Error processing {font_file.name}: {e}")

# Usage
process_font_directory("input_fonts/", "output_fonts/", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

Performance Optimization

def optimize_subsetting_performance(font_paths, common_options):
    """Optimize subsetting for multiple fonts with shared options."""
    # Reuse subsetter instance for better performance
    subsetter = Subsetter(common_options)
    
    for font_path in font_paths:
        font = TTFont(font_path)
        
        # Create a copy for subsetting (preserves original)
        font_copy = TTFont()
        font_copy.importXML(font.saveXML())
        
        subsetter.subset(font_copy)
        
        output_path = font_path.replace('.ttf', '_subset.ttf')
        font_copy.save(output_path)
        
        font.close()
        font_copy.close()

Integration Patterns

def create_web_font_variants(font_path, text_samples):
    """Create multiple optimized variants for different use cases."""
    base_font = TTFont(font_path)
    variants = {}
    
    # Full feature set (headlines)
    headline_options = Options(
        text=text_samples['headlines'],
        layout_features=['kern', 'liga', 'clig', 'dlig'],
        hinting=True
    )
    variants['headline'] = create_subset(base_font, headline_options)
    
    # Basic features (body text)
    body_options = Options(
        text=text_samples['body'],
        layout_features=['kern'],
        hinting=False  # Smaller size for body text
    )
    variants['body'] = create_subset(base_font, body_options)
    
    # Minimal (fallback)
    fallback_options = Options(
        text=text_samples['essential'],
        layout_features=[],
        hinting=False
    )
    variants['fallback'] = create_subset(base_font, fallback_options)
    
    return variants

def create_subset(base_font, options):
    """Helper to create font subset."""
    # Create deep copy to avoid modifying original
    font = TTFont()
    font.importXML(base_font.saveXML())
    
    subsetter = Subsetter(options)
    subsetter.subset(font)
    
    return font

Install with Tessl CLI

npx tessl i tessl/pypi-fonttools

docs

core-font-operations.md

drawing-pens.md

font-building.md

font-processing.md

index.md

utilities-tools.md

variable-fonts.md

tile.json