CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-fonttools

Tools to manipulate font files

Pending
Overview
Eval results
Files

utilities-tools.mddocs/

Utilities and Tools

Miscellaneous utilities for text processing, geometric transformations, XML handling, and various font-related calculations. These utilities provide foundational support for font manipulation and processing workflows.

Capabilities

Geometric Transformations

2D affine transformation matrix operations for scaling, rotation, translation, and skewing.

class Transform:
    def __init__(self, a=1, b=0, c=0, d=1, e=0, f=0):
        """
        Create 2D affine transformation matrix.

        Parameters:
        - a, b, c, d, e, f: float, transformation matrix components
          [a c e]   [x]   [a*x + c*y + e]
          [b d f] × [y] = [b*x + d*y + f]
          [0 0 1]   [1]   [1]
        """

    def transformPoint(self, point):
        """
        Apply transformation to point.

        Parameters:
        - point: Tuple[float, float], input coordinates

        Returns:
        Tuple[float, float]: Transformed coordinates
        """

    def transformPoints(self, points):
        """
        Apply transformation to list of points.

        Parameters:
        - points: List[Tuple[float, float]], input points

        Returns:
        List[Tuple[float, float]]: Transformed points
        """

    def scale(self, x, y=None):
        """
        Create scaling transformation.

        Parameters:
        - x: float, horizontal scale factor
        - y: float, vertical scale factor (default: same as x)

        Returns:
        Transform: New scaling transformation
        """

    def rotate(self, angle):
        """
        Create rotation transformation.

        Parameters:
        - angle: float, rotation angle in radians

        Returns:
        Transform: New rotation transformation
        """

    def translate(self, x, y):
        """
        Create translation transformation.

        Parameters:
        - x, y: float, translation offsets

        Returns:
        Transform: New translation transformation
        """

    def skew(self, x, y):
        """
        Create skew transformation.

        Parameters:
        - x, y: float, skew angles in radians

        Returns:
        Transform: New skew transformation
        """

    def inverse(self):
        """
        Get inverse transformation.

        Returns:
        Transform: Inverse transformation matrix
        """

    def __mul__(self, other):
        """
        Multiply transformations.

        Parameters:
        - other: Transform, transformation to multiply with

        Returns:
        Transform: Combined transformation
        """

Identity = Transform()  # Identity transformation constant

Transformation Examples

from fontTools.misc.transform import Transform, Identity
import math

# Create basic transformations
scale_transform = Transform().scale(2.0, 1.5)  # Scale 2x horizontally, 1.5x vertically
rotate_transform = Transform().rotate(math.radians(45))  # Rotate 45 degrees
translate_transform = Transform().translate(100, 50)  # Move 100 right, 50 up

# Combine transformations
combined = scale_transform * rotate_transform * translate_transform

# Apply to points
original_points = [(0, 0), (100, 0), (100, 100), (0, 100)]
transformed_points = combined.transformPoints(original_points)

print("Original:", original_points)
print("Transformed:", transformed_points)

# Create complex transformation
complex_transform = (Transform()
                    .translate(-50, -50)  # Center at origin
                    .rotate(math.radians(30))  # Rotate 30 degrees
                    .scale(1.2)  # Scale up 20%
                    .translate(200, 300))  # Move to final position

# Apply to single point
x, y = complex_transform.transformPoint((100, 100))
print(f"Point (100, 100) transformed to ({x}, {y})")

Array and Bounds Utilities

Functions for working with coordinate arrays and bounding box calculations.

def calcBounds(array):
    """
    Calculate bounding box of coordinate array.

    Parameters:
    - array: List[Tuple[float, float]], coordinate points

    Returns:
    Tuple[float, float, float, float]: (xMin, yMin, xMax, yMax) or None if empty
    """

def updateBounds(bounds, p):
    """
    Update bounding box to include point.

    Parameters:
    - bounds: Tuple[float, float, float, float], current bounds (xMin, yMin, xMax, yMax)
    - p: Tuple[float, float], point to include

    Returns:
    Tuple[float, float, float, float]: Updated bounds
    """

def pointInRect(p, rect):
    """
    Test if point is inside rectangle.

    Parameters:
    - p: Tuple[float, float], point coordinates
    - rect: Tuple[float, float, float, float], rectangle (xMin, yMin, xMax, yMax)

    Returns:
    bool: True if point is inside rectangle
    """

def rectCenter(rect):
    """
    Get center point of rectangle.

    Parameters:
    - rect: Tuple[float, float, float, float], rectangle (xMin, yMin, xMax, yMax)

    Returns:
    Tuple[float, float]: Center coordinates
    """

def intRect(rect):
    """
    Convert rectangle to integer coordinates.

    Parameters:
    - rect: Tuple[float, float, float, float], rectangle with float coordinates

    Returns:
    Tuple[int, int, int, int]: Rectangle with integer coordinates
    """

Array and Bounds Examples

from fontTools.misc.arrayTools import calcBounds, updateBounds, rectCenter

# Calculate bounds of point array
points = [(10, 20), (50, 10), (30, 60), (80, 40)]
bounds = calcBounds(points)
print(f"Bounds: {bounds}")  # (10, 10, 80, 60)

# Update bounds incrementally
current_bounds = None
for point in points:
    if current_bounds is None:
        current_bounds = (point[0], point[1], point[0], point[1])
    else:
        current_bounds = updateBounds(current_bounds, point)

print(f"Incremental bounds: {current_bounds}")

# Get rectangle center
center = rectCenter(bounds)
print(f"Center: {center}")  # (45.0, 35.0)

Text Processing Utilities

Functions for handling hexadecimal data, safe evaluation, and text conversion.

def safeEval(data):
    """
    Safely evaluate simple Python expressions.

    Parameters:
    - data: str, Python expression to evaluate

    Returns:
    Any: Evaluation result
    """

def readHex(content):
    """
    Read hexadecimal string and return bytes.

    Parameters:
    - content: str, hexadecimal string

    Returns:
    bytes: Decoded binary data
    """

def writeHex(data):
    """
    Convert bytes to hexadecimal string.

    Parameters:
    - data: bytes, binary data

    Returns:
    str: Hexadecimal representation
    """

def hexStr(value):
    """
    Convert integer to hexadecimal string.

    Parameters:
    - value: int, integer value

    Returns:
    str: Hexadecimal string (e.g., "0x1a2b")
    """

Text Processing Examples

from fontTools.misc.textTools import safeEval, readHex, writeHex, hexStr

# Safe evaluation
result = safeEval("2 + 3 * 4")
print(f"Safe eval result: {result}")  # 14

# Hex conversion
hex_string = "48656c6c6f20576f726c64"  # "Hello World" in hex
binary_data = readHex(hex_string)
print(f"Decoded: {binary_data}")  # b'Hello World'

# Convert back to hex
hex_result = writeHex(binary_data)
print(f"Re-encoded: {hex_result}")

# Integer to hex
print(f"0x{255:02x}")  # 0xff
print(hexStr(255))  # 0xff

Rounding Utilities

Functions for various rounding operations commonly used in font processing.

def roundFunc(value, func=round):
    """
    Apply rounding function safely.

    Parameters:
    - value: float, value to round
    - func: callable, rounding function (default: round)

    Returns:
    int: Rounded value
    """

def noRound(value):
    """
    No-op rounding function (returns input unchanged).

    Parameters:  
    - value: float, input value

    Returns:
    float: Unchanged input value
    """

def otRound(value):
    """
    OpenType-style rounding (rounds 0.5 up).

    Parameters:
    - value: float, value to round

    Returns:
    int: Rounded value using OpenType rules
    """

Rounding Examples

from fontTools.misc.roundTools import roundFunc, noRound, otRound

values = [1.2, 1.5, 1.7, 2.5, -1.5]

print("Standard rounding:")
for val in values:
    print(f"  {val} -> {roundFunc(val)}")

print("OpenType rounding:")
for val in values:
    print(f"  {val} -> {otRound(val)}")

print("No rounding:")
for val in values:
    print(f"  {val} -> {noRound(val)}")

Fixed-Point Arithmetic

Utilities for working with fixed-point numbers used in font tables.

def fixedToFloat(value, precisionBits=16):
    """
    Convert fixed-point integer to floating-point.

    Parameters:
    - value: int, fixed-point value
    - precisionBits: int, number of fractional bits (default: 16)

    Returns:
    float: Floating-point representation
    """

def floatToFixed(value, precisionBits=16):
    """
    Convert floating-point to fixed-point integer.

    Parameters:  
    - value: float, floating-point value
    - precisionBits: int, number of fractional bits (default: 16)

    Returns:
    int: Fixed-point representation
    """

def ensureVersionIsLong(value):
    """
    Ensure version number is in correct format.

    Parameters:
    - value: int or float, version number

    Returns:
    int: Properly formatted version number
    """

Fixed-Point Examples

from fontTools.misc.fixedTools import fixedToFloat, floatToFixed

# Convert between fixed-point and float
float_val = 1.5
fixed_val = floatToFixed(float_val)
print(f"Float {float_val} -> Fixed {fixed_val}")  # 98304 (1.5 * 65536)

back_to_float = fixedToFloat(fixed_val)
print(f"Fixed {fixed_val} -> Float {back_to_float}")  # 1.5

# Different precision
fixed_8bit = floatToFixed(1.5, precisionBits=8)
print(f"8-bit fixed: {fixed_8bit}")  # 384 (1.5 * 256)

Bezier Curve Mathematics

Mathematical functions for working with Bezier curves and path calculations.

def calcQuadraticBounds(pt1, pt2, pt3):
    """
    Calculate bounding box of quadratic Bezier curve.

    Parameters:
    - pt1, pt2, pt3: Tuple[float, float], curve control points

    Returns:
    Tuple[float, float, float, float]: Bounding box (xMin, yMin, xMax, yMax)
    """

def calcCubicBounds(pt1, pt2, pt3, pt4):
    """
    Calculate bounding box of cubic Bezier curve.

    Parameters:
    - pt1, pt2, pt3, pt4: Tuple[float, float], curve control points

    Returns:
    Tuple[float, float, float, float]: Bounding box (xMin, yMin, xMax, yMax)
    """

def splitLine(pt1, pt2, where):
    """
    Split line segment at parameter t.

    Parameters:
    - pt1, pt2: Tuple[float, float], line endpoints
    - where: float, parameter t (0.0 to 1.0)

    Returns:
    Tuple[Tuple, Tuple]: Two line segments
    """

def splitQuadratic(pt1, pt2, pt3, where):
    """
    Split quadratic Bezier curve at parameter t.

    Parameters:
    - pt1, pt2, pt3: Tuple[float, float], curve control points
    - where: float, parameter t (0.0 to 1.0)

    Returns:
    Tuple[Tuple, Tuple]: Two quadratic curve segments
    """

def splitCubic(pt1, pt2, pt3, pt4, where):
    """
    Split cubic Bezier curve at parameter t.

    Parameters:
    - pt1, pt2, pt3, pt4: Tuple[float, float], curve control points  
    - where: float, parameter t (0.0 to 1.0)

    Returns:
    Tuple[Tuple, Tuple]: Two cubic curve segments
    """

Bezier Mathematics Examples

from fontTools.misc.bezierTools import calcCubicBounds, splitCubic

# Calculate bounds of cubic curve
pt1 = (0, 0)
pt2 = (50, 100)  
pt3 = (150, 100)
pt4 = (200, 0)

bounds = calcCubicBounds(pt1, pt2, pt3, pt4)
print(f"Curve bounds: {bounds}")

# Split curve at midpoint
left_curve, right_curve = splitCubic(pt1, pt2, pt3, pt4, 0.5)
print(f"Left curve: {left_curve}")
print(f"Right curve: {right_curve}")

XML Processing

Utilities for reading and writing XML data in font processing contexts.

class XMLWriter:
    def __init__(self, outFile, encoding="utf-8"):
        """
        XML output writer.

        Parameters:
        - outFile: file-like, output file object
        - encoding: str, character encoding
        """

    def begintag(self, tag, **kwargs):
        """
        Write opening XML tag.

        Parameters:
        - tag: str, tag name
        - kwargs: tag attributes
        """

    def endtag(self, tag):
        """
        Write closing XML tag.

        Parameters:
        - tag: str, tag name
        """

    def simpletag(self, tag, **kwargs):
        """
        Write self-closing XML tag.

        Parameters:
        - tag: str, tag name
        - kwargs: tag attributes
        """

    def data(self, data):
        """
        Write XML character data.

        Parameters:
        - data: str, character data
        """

class XMLReader:
    def __init__(self, inFile):
        """
        XML input reader.

        Parameters:
        - inFile: file-like, input file object
        """

    def read(self, handler):
        """
        Parse XML with content handler.

        Parameters:
        - handler: object, content handler with start/end/data methods
        """

Logging Configuration

Utilities for configuring FontTools logging output.

def configLogger(level="INFO", format=None, logger=None):
    """
    Configure FontTools logging.

    Parameters:
    - level: str, logging level ("DEBUG", "INFO", "WARNING", "ERROR")
    - format: str, log message format string
    - logger: Logger, specific logger to configure (default: fontTools logger)
    """

Logging Examples

from fontTools.misc.loggingTools import configLogger
import logging

# Configure FontTools logging
configLogger(level="DEBUG")

# Use FontTools logger
from fontTools import log
log.info("Processing font file")
log.warning("Unusual glyph structure detected")
log.error("Font validation failed")

# Configure with custom format
configLogger(
    level="INFO",
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)

File System Utilities

Cross-platform file system operations for font processing.

from fontTools.misc.filesystem import open_file, ensure_path

# Platform-aware file opening
with open_file("font.ttf", "rb") as f:
    font_data = f.read()

# Ensure directory exists
ensure_path("output/fonts/")

Integration Examples

def optimize_glyph_coordinates(glyph_coords, transform=None):
    """Example combining multiple utilities."""
    from fontTools.misc.arrayTools import calcBounds
    from fontTools.misc.roundTools import otRound
    from fontTools.misc.transform import Transform
    
    # Apply transformation if provided
    if transform:
        coords = transform.transformPoints(glyph_coords)
    else:
        coords = glyph_coords
    
    # Round coordinates using OpenType rules
    rounded_coords = [(otRound(x), otRound(y)) for x, y in coords]
    
    # Calculate optimized bounds
    bounds = calcBounds(rounded_coords)
    
    return rounded_coords, bounds

def create_web_font_transform(target_upm=1000):
    """Create transformation for web font optimization."""
    from fontTools.misc.transform import Transform
    
    # Common web font optimizations
    transform = Transform()
    
    # Scale to target units per em
    current_upm = 2048  # Assume source UPM
    scale_factor = target_upm / current_upm
    transform = transform.scale(scale_factor)
    
    # Optional: slight compression for better rendering
    transform = transform.scale(1.0, 0.95)
    
    return transform

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