Pure Python wrapper around SDL2 libraries for cross-platform multimedia development
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
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."""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."""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."""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 hintingFunctions 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."""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."""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."""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."""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."""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)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()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()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()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