CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pysdl2

Pure Python wrapper around SDL2 libraries for cross-platform multimedia development

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

fonts-text.mddocs/

Font and Text Rendering

TrueType font loading and text rendering through SDL2_ttf integration and bitmap font support. PySDL2 provides both low-level TTF functions and high-level font management classes.

Capabilities

TTF Initialization and Management

Core functions for initializing and managing the TTF system.

def TTF_Init() -> int:
    """
    Initialize TTF system.
    
    Returns:
    0 on success, -1 on failure
    """

def TTF_Quit() -> None:
    """Shut down TTF system and free resources."""

def TTF_WasInit() -> int:
    """Check if TTF system is initialized."""

def TTF_GetError() -> bytes:
    """Get last TTF error message."""

def TTF_SetError(fmt: bytes) -> None:
    """Set TTF error message."""

Font Loading and Management

Functions for loading and managing TrueType fonts.

def TTF_OpenFont(file: bytes, ptsize: int) -> TTF_Font:
    """
    Load font from file at specified point size.
    
    Parameters:
    - file: path to font file as bytes
    - ptsize: font size in points
    
    Returns:
    TTF_Font object or None on failure
    """

def TTF_OpenFontIndex(file: bytes, ptsize: int, index: int) -> TTF_Font:
    """
    Load font from file at specified point size and face index.
    
    Parameters:
    - file: path to font file as bytes
    - ptsize: font size in points
    - index: face index in font file
    
    Returns:
    TTF_Font object or None on failure
    """

def TTF_OpenFontRW(src: SDL_RWops, freesrc: int, ptsize: int) -> TTF_Font:
    """Load font from SDL_RWops source."""

def TTF_OpenFontIndexRW(src: SDL_RWops, freesrc: int, ptsize: int, index: int) -> TTF_Font:
    """Load font from SDL_RWops source with face index."""

def TTF_CloseFont(font: TTF_Font) -> None:
    """Close font and free resources."""

Font Metrics and Properties

Functions for querying font properties and metrics.

def TTF_FontHeight(font: TTF_Font) -> int:
    """Get font height (baseline to baseline distance)."""

def TTF_FontAscent(font: TTF_Font) -> int:
    """Get font ascent (baseline to top)."""

def TTF_FontDescent(font: TTF_Font) -> int:
    """Get font descent (baseline to bottom)."""

def TTF_FontLineSkip(font: TTF_Font) -> int:
    """Get recommended line spacing."""

def TTF_FontFaces(font: TTF_Font) -> int:
    """Get number of faces in font."""

def TTF_FontFaceIsFixedWidth(font: TTF_Font) -> int:
    """Check if font is monospace."""

def TTF_FontFaceFamilyName(font: TTF_Font) -> bytes:
    """Get font family name."""

def TTF_FontFaceStyleName(font: TTF_Font) -> bytes:
    """Get font style name."""

def TTF_GetFontStyle(font: TTF_Font) -> int:
    """Get font style flags."""

def TTF_SetFontStyle(font: TTF_Font, style: int) -> None:
    """Set font style flags."""

def TTF_GetFontOutline(font: TTF_Font) -> int:
    """Get font outline thickness."""

def TTF_SetFontOutline(font: TTF_Font, outline: int) -> None:
    """Set font outline thickness."""

def TTF_GetFontHinting(font: TTF_Font) -> int:
    """Get font hinting mode."""

def TTF_SetFontHinting(font: TTF_Font, hinting: int) -> None:
    """Set font hinting mode."""

def TTF_GetFontKerning(font: TTF_Font) -> int:
    """Get font kerning enabled state."""

def TTF_SetFontKerning(font: TTF_Font, allowed: int) -> None:
    """Enable/disable font kerning."""

Font Style Constants

TTF_STYLE_NORMAL: int = 0x00        # Normal text
TTF_STYLE_BOLD: int = 0x01          # Bold text
TTF_STYLE_ITALIC: int = 0x02        # Italic text
TTF_STYLE_UNDERLINE: int = 0x04     # Underlined text
TTF_STYLE_STRIKETHROUGH: int = 0x08 # Strikethrough text

# Hinting modes
TTF_HINTING_NORMAL: int = 0         # Normal hinting
TTF_HINTING_LIGHT: int = 1          # Light hinting
TTF_HINTING_MONO: int = 2           # Monochrome hinting
TTF_HINTING_NONE: int = 3           # No hinting

Text Measurement

Functions for measuring text dimensions before rendering.

def TTF_SizeText(font: TTF_Font, text: bytes, w: ctypes.POINTER(ctypes.c_int), 
                h: ctypes.POINTER(ctypes.c_int)) -> int:
    """
    Calculate size of text when rendered.
    
    Parameters:
    - font: font to use
    - text: text to measure as bytes
    - w, h: pointers to store width and height
    
    Returns:
    0 on success, -1 on failure
    """

def TTF_SizeUTF8(font: TTF_Font, text: bytes, w: ctypes.POINTER(ctypes.c_int), 
                 h: ctypes.POINTER(ctypes.c_int)) -> int:
    """Calculate size of UTF-8 text when rendered."""

def TTF_SizeUNICODE(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), 
                   w: ctypes.POINTER(ctypes.c_int), h: ctypes.POINTER(ctypes.c_int)) -> int:
    """Calculate size of Unicode text when rendered."""

def TTF_MeasureText(font: TTF_Font, text: bytes, measure_width: int, 
                   extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
    """Measure text for word wrapping."""

def TTF_MeasureUTF8(font: TTF_Font, text: bytes, measure_width: int, 
                   extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
    """Measure UTF-8 text for word wrapping."""

def TTF_MeasureUNICODE(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), measure_width: int, 
                      extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
    """Measure Unicode text for word wrapping."""

Text Rendering

Functions for rendering text to surfaces.

def TTF_RenderText_Solid(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
    """
    Render text in solid color.
    
    Parameters:
    - font: font to use
    - text: text to render as bytes
    - fg: foreground color
    
    Returns:
    SDL_Surface containing rendered text or None on failure
    """

def TTF_RenderUTF8_Solid(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
    """Render UTF-8 text in solid color."""

def TTF_RenderUNICODE_Solid(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), fg: SDL_Color) -> SDL_Surface:
    """Render Unicode text in solid color."""

def TTF_RenderText_Shaded(font: TTF_Font, text: bytes, fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
    """
    Render text with background color (shaded).
    
    Parameters:
    - font: font to use
    - text: text to render as bytes
    - fg: foreground color
    - bg: background color
    
    Returns:
    SDL_Surface containing rendered text or None on failure
    """

def TTF_RenderUTF8_Shaded(font: TTF_Font, text: bytes, fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
    """Render UTF-8 text with background color."""

def TTF_RenderUNICODE_Shaded(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), 
                            fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
    """Render Unicode text with background color."""

def TTF_RenderText_Blended(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
    """
    Render anti-aliased text (blended).
    
    Parameters:
    - font: font to use
    - text: text to render as bytes
    - fg: foreground color
    
    Returns:
    SDL_Surface containing rendered text or None on failure
    """

def TTF_RenderUTF8_Blended(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
    """Render anti-aliased UTF-8 text."""

def TTF_RenderUNICODE_Blended(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), fg: SDL_Color) -> SDL_Surface:
    """Render anti-aliased Unicode text."""

def TTF_RenderText_Blended_Wrapped(font: TTF_Font, text: bytes, fg: SDL_Color, wrapLength: int) -> SDL_Surface:
    """
    Render anti-aliased text with word wrapping.
    
    Parameters:
    - font: font to use
    - text: text to render as bytes
    - fg: foreground color  
    - wrapLength: maximum line width in pixels
    
    Returns:
    SDL_Surface containing rendered text or None on failure
    """

def TTF_RenderUTF8_Blended_Wrapped(font: TTF_Font, text: bytes, fg: SDL_Color, wrapLength: int) -> SDL_Surface:
    """Render anti-aliased UTF-8 text with word wrapping."""

def TTF_RenderUNICODE_Blended_Wrapped(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), 
                                     fg: SDL_Color, wrapLength: int) -> SDL_Surface:
    """Render anti-aliased Unicode text with word wrapping."""

High-Level Font Classes

Extension module classes for simplified font management.

class FontTTF:
    """High-level TrueType font class."""
    
    def __init__(self, font_path: str, size: int, index: int = 0):
        """
        Load TrueType font.
        
        Parameters:
        - font_path: path to font file
        - size: font size in points
        - index: face index for multi-face fonts
        """
    
    def render(self, text: str, color: tuple[int, int, int] = (255, 255, 255), 
               bg: tuple[int, int, int] = None) -> SDL_Surface:
        """
        Render text to surface.
        
        Parameters:
        - text: text string to render
        - color: RGB foreground color (0-255 each)
        - bg: RGB background color (None for transparent)
        
        Returns:
        SDL_Surface containing rendered text
        """
    
    def render_blended(self, text: str, color: tuple[int, int, int] = (255, 255, 255)) -> SDL_Surface:
        """
        Render anti-aliased text.
        
        Parameters:
        - text: text string to render
        - color: RGB foreground color
        
        Returns:
        SDL_Surface containing rendered text
        """
    
    def size(self, text: str) -> tuple[int, int]:
        """
        Get text size when rendered.
        
        Parameters:
        - text: text to measure
        
        Returns:
        (width, height) tuple in pixels
        """
    
    @property
    def height(self) -> int:
        """Get font height."""
    
    @property
    def ascent(self) -> int:
        """Get font ascent."""
    
    @property
    def descent(self) -> int:
        """Get font descent."""
    
    @property
    def line_skip(self) -> int:
        """Get recommended line spacing."""

class FontManager:
    """Manager for multiple fonts with caching."""
    
    def __init__(self, font_path: str, alias: str = None, size: int = 16):
        """
        Create font manager.
        
        Parameters:
        - font_path: default font file path
        - alias: alias for default font
        - size: default font size
        """
    
    def add(self, font_path: str, alias: str = None, size: int = 16) -> None:
        """
        Add font to manager.
        
        Parameters:
        - font_path: path to font file
        - alias: font alias (uses filename if None)
        - size: font size in points
        """
    
    def get(self, alias: str, size: int = 16) -> FontTTF:
        """
        Get font by alias and size.
        
        Parameters:
        - alias: font alias
        - size: font size in points
        
        Returns:
        FontTTF object
        """
    
    def close(self) -> None:
        """Close all fonts and free resources."""

Bitmap Font Support

Simple bitmap font class for pixel-perfect text rendering.

class BitmapFont:
    """Bitmap font class for pixel-perfect text rendering."""
    
    def __init__(self, surface: SDL_Surface, size: tuple[int, int], mapping: list[str] = None):
        """
        Create bitmap font from surface.
        
        Parameters:
        - surface: surface containing font characters
        - size: (width, height) of each character
        - mapping: list of characters in font surface order
        """
    
    def render(self, text: str, bpp: int = None) -> SDL_Surface:
        """
        Render text using bitmap font.
        
        Parameters:
        - text: text to render
        - bpp: bits per pixel for rendered surface
        
        Returns:
        SDL_Surface containing rendered text
        """
    
    def can_render(self, text: str) -> bool:
        """
        Check if font can render all characters in text.
        
        Parameters:
        - text: text to check
        
        Returns:
        True if all characters can be rendered
        """
    
    @property
    def size(self) -> tuple[int, int]:
        """Get character size as (width, height) tuple."""

Text Direction Support

Constants and functions for text direction and rendering.

# Text direction constants (for advanced text layout)
HB_DIRECTION_LTR: int = 0  # Left-to-right
HB_DIRECTION_RTL: int = 1  # Right-to-left  
HB_DIRECTION_TTB: int = 2  # Top-to-bottom
HB_DIRECTION_BTT: int = 3  # Bottom-to-top

def TTF_SetDirection(direction: int) -> int:
    """Set text direction for complex text layout."""

def TTF_SetScript(script: int) -> int:
    """Set script for complex text layout."""

Types

class TTF_Font:
    """Opaque structure representing a loaded font."""

class SDL_Color:
    """Color structure for text rendering."""
    r: int  # Red component (0-255)
    g: int  # Green component (0-255)
    b: int  # Blue component (0-255)
    a: int  # Alpha component (0-255)

Usage Examples

Basic Text Rendering

import sdl2
import sdl2.sdlttf
import sdl2.ext

# Initialize SDL2 and TTF
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
sdl2.sdlttf.TTF_Init()

# Create window and renderer
window = sdl2.SDL_CreateWindow(b"Text Rendering", 
                              sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED,
                              800, 600, sdl2.SDL_WINDOW_SHOWN)
renderer = sdl2.SDL_CreateRenderer(window, -1, sdl2.SDL_RENDERER_ACCELERATED)

# Load font
font = sdl2.sdlttf.TTF_OpenFont(b"arial.ttf", 24)
if not font:
    print("Failed to load font")
    exit(1)

# Render text
color = sdl2.SDL_Color(255, 255, 255, 255)  # White text
text_surface = sdl2.sdlttf.TTF_RenderText_Blended(font, b"Hello, PySDL2!", color)
text_texture = sdl2.SDL_CreateTextureFromSurface(renderer, text_surface)
sdl2.SDL_FreeSurface(text_surface)

# Get text dimensions
text_w = ctypes.c_int()
text_h = ctypes.c_int()
sdl2.SDL_QueryTexture(text_texture, None, None, text_w, text_h)

# Main loop
running = True
event = sdl2.SDL_Event()

while running:
    while sdl2.SDL_PollEvent(event):
        if event.type == sdl2.SDL_QUIT:
            running = False
    
    # Clear screen
    sdl2.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
    sdl2.SDL_RenderClear(renderer)
    
    # Render text centered
    dest_rect = sdl2.SDL_Rect(
        (800 - text_w.value) // 2,
        (600 - text_h.value) // 2,
        text_w.value,
        text_h.value
    )
    sdl2.SDL_RenderCopy(renderer, text_texture, None, dest_rect)
    
    # Present frame
    sdl2.SDL_RenderPresent(renderer)

# Cleanup
sdl2.SDL_DestroyTexture(text_texture)
sdl2.sdlttf.TTF_CloseFont(font)
sdl2.SDL_DestroyRenderer(renderer)
sdl2.SDL_DestroyWindow(window)
sdl2.sdlttf.TTF_Quit()
sdl2.SDL_Quit()

High-Level Font Usage

import sdl2.ext

# Initialize SDL2 extensions
sdl2.ext.init()

# Create window and renderer
window = sdl2.ext.Window("High-Level Text", size=(800, 600))
window.show()
renderer = sdl2.ext.Renderer(window)

# Create font manager
font_manager = sdl2.ext.FontManager("arial.ttf", "default", 24)
font_manager.add("times.ttf", "serif", 18)
font_manager.add("courier.ttf", "mono", 16)

# Get fonts
default_font = font_manager.get("default")
title_font = font_manager.get("default", 36)  # Larger size
mono_font = font_manager.get("mono")

# Render different text styles
title_surface = title_font.render("PySDL2 Text Demo", (255, 255, 0))
body_surface = default_font.render("This is regular text.", (255, 255, 255))
code_surface = mono_font.render("print('Hello, World!')", (0, 255, 0))

# Convert surfaces to textures
title_texture = sdl2.ext.Texture(renderer, title_surface)
body_texture = sdl2.ext.Texture(renderer, body_surface)
code_texture = sdl2.ext.Texture(renderer, code_surface)

# Free surfaces (textures have copies)
sdl2.SDL_FreeSurface(title_surface)
sdl2.SDL_FreeSurface(body_surface) 
sdl2.SDL_FreeSurface(code_surface)

# Main loop
running = True
while running:
    events = sdl2.ext.get_events()
    for event in events:
        if event.type == sdl2.SDL_QUIT:
            running = False
    
    # Clear screen
    renderer.clear((50, 50, 50))
    
    # Render text at different positions
    renderer.copy(title_texture, dstrect=sdl2.SDL_Rect(50, 50, 0, 0))
    renderer.copy(body_texture, dstrect=sdl2.SDL_Rect(50, 150, 0, 0))
    renderer.copy(code_texture, dstrect=sdl2.SDL_Rect(50, 200, 0, 0))
    
    renderer.present()

# Cleanup
font_manager.close()
sdl2.ext.quit()

Word Wrapping and Multi-line Text

import sdl2
import sdl2.sdlttf

# Initialize
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
sdl2.sdlttf.TTF_Init()

# Create window
window = sdl2.SDL_CreateWindow(b"Word Wrapping",
                              sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED,
                              600, 400, sdl2.SDL_WINDOW_SHOWN)
renderer = sdl2.SDL_CreateRenderer(window, -1, sdl2.SDL_RENDERER_ACCELERATED)

# Load font
font = sdl2.sdlttf.TTF_OpenFont(b"arial.ttf", 18)

# Long text for word wrapping
long_text = b"This is a very long text that will be wrapped across multiple lines to demonstrate the word wrapping functionality of SDL2_ttf."

# Render wrapped text
color = sdl2.SDL_Color(255, 255, 255, 255)
wrapped_surface = sdl2.sdlttf.TTF_RenderUTF8_Blended_Wrapped(font, long_text, color, 500)
wrapped_texture = sdl2.SDL_CreateTextureFromSurface(renderer, wrapped_surface)
sdl2.SDL_FreeSurface(wrapped_surface)

# Main loop
running = True
event = sdl2.SDL_Event()

while running:
    while sdl2.SDL_PollEvent(event):
        if event.type == sdl2.SDL_QUIT:
            running = False
    
    # Clear and render
    sdl2.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
    sdl2.SDL_RenderClear(renderer)
    
    # Render wrapped text
    dest_rect = sdl2.SDL_Rect(50, 50, 500, 300)
    sdl2.SDL_RenderCopy(renderer, wrapped_texture, None, dest_rect)
    
    sdl2.SDL_RenderPresent(renderer)

# Cleanup
sdl2.SDL_DestroyTexture(wrapped_texture)
sdl2.sdlttf.TTF_CloseFont(font)
sdl2.SDL_DestroyRenderer(renderer)
sdl2.SDL_DestroyWindow(window)
sdl2.sdlttf.TTF_Quit()
sdl2.SDL_Quit()

Bitmap Font Usage

import sdl2.ext

# Initialize
sdl2.ext.init()
window = sdl2.ext.Window("Bitmap Font", size=(640, 480))
window.show()

# Load bitmap font surface (assumes 16x16 character grid)
font_surface = sdl2.SDL_LoadBMP(b"bitmap_font.bmp")

# Character mapping for ASCII printable characters
ascii_chars = [chr(i) for i in range(32, 127)]

# Create bitmap font
bitmap_font = sdl2.ext.BitmapFont(font_surface, (8, 16), ascii_chars)

# Render text with bitmap font
text = "Bitmap Font Text!"
rendered_surface = bitmap_font.render(text)

# Main loop
running = True
while running:
    events = sdl2.ext.get_events()
    for event in events:
        if event.type == sdl2.SDL_QUIT:
            running = False
    
    # Clear screen and blit bitmap text
    window_surface = sdl2.SDL_GetWindowSurface(window.window)
    sdl2.SDL_FillRect(window_surface, None, 0)  # Black background
    
    dest_rect = sdl2.SDL_Rect(10, 10, 0, 0)
    sdl2.SDL_BlitSurface(rendered_surface, None, window_surface, dest_rect)
    
    sdl2.SDL_UpdateWindowSurface(window.window)

# Cleanup
sdl2.SDL_FreeSurface(rendered_surface)
sdl2.SDL_FreeSurface(font_surface)
sdl2.ext.quit()

Install with Tessl CLI

npx tessl i tessl/pypi-pysdl2

docs

audio.md

events-input.md

file-io.md

fonts-text.md

graphics-rendering.md

image-processing.md

index.md

joystick-input.md

sprites-animation.md

system-utils.md

timer.md

window-display.md

tile.json