0
# Font and Text Rendering
1
2
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.
3
4
## Capabilities
5
6
### TTF Initialization and Management
7
8
Core functions for initializing and managing the TTF system.
9
10
```python { .api }
11
def TTF_Init() -> int:
12
"""
13
Initialize TTF system.
14
15
Returns:
16
0 on success, -1 on failure
17
"""
18
19
def TTF_Quit() -> None:
20
"""Shut down TTF system and free resources."""
21
22
def TTF_WasInit() -> int:
23
"""Check if TTF system is initialized."""
24
25
def TTF_GetError() -> bytes:
26
"""Get last TTF error message."""
27
28
def TTF_SetError(fmt: bytes) -> None:
29
"""Set TTF error message."""
30
```
31
32
### Font Loading and Management
33
34
Functions for loading and managing TrueType fonts.
35
36
```python { .api }
37
def TTF_OpenFont(file: bytes, ptsize: int) -> TTF_Font:
38
"""
39
Load font from file at specified point size.
40
41
Parameters:
42
- file: path to font file as bytes
43
- ptsize: font size in points
44
45
Returns:
46
TTF_Font object or None on failure
47
"""
48
49
def TTF_OpenFontIndex(file: bytes, ptsize: int, index: int) -> TTF_Font:
50
"""
51
Load font from file at specified point size and face index.
52
53
Parameters:
54
- file: path to font file as bytes
55
- ptsize: font size in points
56
- index: face index in font file
57
58
Returns:
59
TTF_Font object or None on failure
60
"""
61
62
def TTF_OpenFontRW(src: SDL_RWops, freesrc: int, ptsize: int) -> TTF_Font:
63
"""Load font from SDL_RWops source."""
64
65
def TTF_OpenFontIndexRW(src: SDL_RWops, freesrc: int, ptsize: int, index: int) -> TTF_Font:
66
"""Load font from SDL_RWops source with face index."""
67
68
def TTF_CloseFont(font: TTF_Font) -> None:
69
"""Close font and free resources."""
70
```
71
72
### Font Metrics and Properties
73
74
Functions for querying font properties and metrics.
75
76
```python { .api }
77
def TTF_FontHeight(font: TTF_Font) -> int:
78
"""Get font height (baseline to baseline distance)."""
79
80
def TTF_FontAscent(font: TTF_Font) -> int:
81
"""Get font ascent (baseline to top)."""
82
83
def TTF_FontDescent(font: TTF_Font) -> int:
84
"""Get font descent (baseline to bottom)."""
85
86
def TTF_FontLineSkip(font: TTF_Font) -> int:
87
"""Get recommended line spacing."""
88
89
def TTF_FontFaces(font: TTF_Font) -> int:
90
"""Get number of faces in font."""
91
92
def TTF_FontFaceIsFixedWidth(font: TTF_Font) -> int:
93
"""Check if font is monospace."""
94
95
def TTF_FontFaceFamilyName(font: TTF_Font) -> bytes:
96
"""Get font family name."""
97
98
def TTF_FontFaceStyleName(font: TTF_Font) -> bytes:
99
"""Get font style name."""
100
101
def TTF_GetFontStyle(font: TTF_Font) -> int:
102
"""Get font style flags."""
103
104
def TTF_SetFontStyle(font: TTF_Font, style: int) -> None:
105
"""Set font style flags."""
106
107
def TTF_GetFontOutline(font: TTF_Font) -> int:
108
"""Get font outline thickness."""
109
110
def TTF_SetFontOutline(font: TTF_Font, outline: int) -> None:
111
"""Set font outline thickness."""
112
113
def TTF_GetFontHinting(font: TTF_Font) -> int:
114
"""Get font hinting mode."""
115
116
def TTF_SetFontHinting(font: TTF_Font, hinting: int) -> None:
117
"""Set font hinting mode."""
118
119
def TTF_GetFontKerning(font: TTF_Font) -> int:
120
"""Get font kerning enabled state."""
121
122
def TTF_SetFontKerning(font: TTF_Font, allowed: int) -> None:
123
"""Enable/disable font kerning."""
124
```
125
126
### Font Style Constants
127
128
```python { .api }
129
TTF_STYLE_NORMAL: int = 0x00 # Normal text
130
TTF_STYLE_BOLD: int = 0x01 # Bold text
131
TTF_STYLE_ITALIC: int = 0x02 # Italic text
132
TTF_STYLE_UNDERLINE: int = 0x04 # Underlined text
133
TTF_STYLE_STRIKETHROUGH: int = 0x08 # Strikethrough text
134
135
# Hinting modes
136
TTF_HINTING_NORMAL: int = 0 # Normal hinting
137
TTF_HINTING_LIGHT: int = 1 # Light hinting
138
TTF_HINTING_MONO: int = 2 # Monochrome hinting
139
TTF_HINTING_NONE: int = 3 # No hinting
140
```
141
142
### Text Measurement
143
144
Functions for measuring text dimensions before rendering.
145
146
```python { .api }
147
def TTF_SizeText(font: TTF_Font, text: bytes, w: ctypes.POINTER(ctypes.c_int),
148
h: ctypes.POINTER(ctypes.c_int)) -> int:
149
"""
150
Calculate size of text when rendered.
151
152
Parameters:
153
- font: font to use
154
- text: text to measure as bytes
155
- w, h: pointers to store width and height
156
157
Returns:
158
0 on success, -1 on failure
159
"""
160
161
def TTF_SizeUTF8(font: TTF_Font, text: bytes, w: ctypes.POINTER(ctypes.c_int),
162
h: ctypes.POINTER(ctypes.c_int)) -> int:
163
"""Calculate size of UTF-8 text when rendered."""
164
165
def TTF_SizeUNICODE(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16),
166
w: ctypes.POINTER(ctypes.c_int), h: ctypes.POINTER(ctypes.c_int)) -> int:
167
"""Calculate size of Unicode text when rendered."""
168
169
def TTF_MeasureText(font: TTF_Font, text: bytes, measure_width: int,
170
extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
171
"""Measure text for word wrapping."""
172
173
def TTF_MeasureUTF8(font: TTF_Font, text: bytes, measure_width: int,
174
extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
175
"""Measure UTF-8 text for word wrapping."""
176
177
def TTF_MeasureUNICODE(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), measure_width: int,
178
extent: ctypes.POINTER(ctypes.c_int), count: ctypes.POINTER(ctypes.c_int)) -> int:
179
"""Measure Unicode text for word wrapping."""
180
```
181
182
### Text Rendering
183
184
Functions for rendering text to surfaces.
185
186
```python { .api }
187
def TTF_RenderText_Solid(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
188
"""
189
Render text in solid color.
190
191
Parameters:
192
- font: font to use
193
- text: text to render as bytes
194
- fg: foreground color
195
196
Returns:
197
SDL_Surface containing rendered text or None on failure
198
"""
199
200
def TTF_RenderUTF8_Solid(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
201
"""Render UTF-8 text in solid color."""
202
203
def TTF_RenderUNICODE_Solid(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), fg: SDL_Color) -> SDL_Surface:
204
"""Render Unicode text in solid color."""
205
206
def TTF_RenderText_Shaded(font: TTF_Font, text: bytes, fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
207
"""
208
Render text with background color (shaded).
209
210
Parameters:
211
- font: font to use
212
- text: text to render as bytes
213
- fg: foreground color
214
- bg: background color
215
216
Returns:
217
SDL_Surface containing rendered text or None on failure
218
"""
219
220
def TTF_RenderUTF8_Shaded(font: TTF_Font, text: bytes, fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
221
"""Render UTF-8 text with background color."""
222
223
def TTF_RenderUNICODE_Shaded(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16),
224
fg: SDL_Color, bg: SDL_Color) -> SDL_Surface:
225
"""Render Unicode text with background color."""
226
227
def TTF_RenderText_Blended(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
228
"""
229
Render anti-aliased text (blended).
230
231
Parameters:
232
- font: font to use
233
- text: text to render as bytes
234
- fg: foreground color
235
236
Returns:
237
SDL_Surface containing rendered text or None on failure
238
"""
239
240
def TTF_RenderUTF8_Blended(font: TTF_Font, text: bytes, fg: SDL_Color) -> SDL_Surface:
241
"""Render anti-aliased UTF-8 text."""
242
243
def TTF_RenderUNICODE_Blended(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16), fg: SDL_Color) -> SDL_Surface:
244
"""Render anti-aliased Unicode text."""
245
246
def TTF_RenderText_Blended_Wrapped(font: TTF_Font, text: bytes, fg: SDL_Color, wrapLength: int) -> SDL_Surface:
247
"""
248
Render anti-aliased text with word wrapping.
249
250
Parameters:
251
- font: font to use
252
- text: text to render as bytes
253
- fg: foreground color
254
- wrapLength: maximum line width in pixels
255
256
Returns:
257
SDL_Surface containing rendered text or None on failure
258
"""
259
260
def TTF_RenderUTF8_Blended_Wrapped(font: TTF_Font, text: bytes, fg: SDL_Color, wrapLength: int) -> SDL_Surface:
261
"""Render anti-aliased UTF-8 text with word wrapping."""
262
263
def TTF_RenderUNICODE_Blended_Wrapped(font: TTF_Font, text: ctypes.POINTER(ctypes.c_uint16),
264
fg: SDL_Color, wrapLength: int) -> SDL_Surface:
265
"""Render anti-aliased Unicode text with word wrapping."""
266
```
267
268
### High-Level Font Classes
269
270
Extension module classes for simplified font management.
271
272
```python { .api }
273
class FontTTF:
274
"""High-level TrueType font class."""
275
276
def __init__(self, font_path: str, size: int, index: int = 0):
277
"""
278
Load TrueType font.
279
280
Parameters:
281
- font_path: path to font file
282
- size: font size in points
283
- index: face index for multi-face fonts
284
"""
285
286
def render(self, text: str, color: tuple[int, int, int] = (255, 255, 255),
287
bg: tuple[int, int, int] = None) -> SDL_Surface:
288
"""
289
Render text to surface.
290
291
Parameters:
292
- text: text string to render
293
- color: RGB foreground color (0-255 each)
294
- bg: RGB background color (None for transparent)
295
296
Returns:
297
SDL_Surface containing rendered text
298
"""
299
300
def render_blended(self, text: str, color: tuple[int, int, int] = (255, 255, 255)) -> SDL_Surface:
301
"""
302
Render anti-aliased text.
303
304
Parameters:
305
- text: text string to render
306
- color: RGB foreground color
307
308
Returns:
309
SDL_Surface containing rendered text
310
"""
311
312
def size(self, text: str) -> tuple[int, int]:
313
"""
314
Get text size when rendered.
315
316
Parameters:
317
- text: text to measure
318
319
Returns:
320
(width, height) tuple in pixels
321
"""
322
323
@property
324
def height(self) -> int:
325
"""Get font height."""
326
327
@property
328
def ascent(self) -> int:
329
"""Get font ascent."""
330
331
@property
332
def descent(self) -> int:
333
"""Get font descent."""
334
335
@property
336
def line_skip(self) -> int:
337
"""Get recommended line spacing."""
338
339
class FontManager:
340
"""Manager for multiple fonts with caching."""
341
342
def __init__(self, font_path: str, alias: str = None, size: int = 16):
343
"""
344
Create font manager.
345
346
Parameters:
347
- font_path: default font file path
348
- alias: alias for default font
349
- size: default font size
350
"""
351
352
def add(self, font_path: str, alias: str = None, size: int = 16) -> None:
353
"""
354
Add font to manager.
355
356
Parameters:
357
- font_path: path to font file
358
- alias: font alias (uses filename if None)
359
- size: font size in points
360
"""
361
362
def get(self, alias: str, size: int = 16) -> FontTTF:
363
"""
364
Get font by alias and size.
365
366
Parameters:
367
- alias: font alias
368
- size: font size in points
369
370
Returns:
371
FontTTF object
372
"""
373
374
def close(self) -> None:
375
"""Close all fonts and free resources."""
376
```
377
378
### Bitmap Font Support
379
380
Simple bitmap font class for pixel-perfect text rendering.
381
382
```python { .api }
383
class BitmapFont:
384
"""Bitmap font class for pixel-perfect text rendering."""
385
386
def __init__(self, surface: SDL_Surface, size: tuple[int, int], mapping: list[str] = None):
387
"""
388
Create bitmap font from surface.
389
390
Parameters:
391
- surface: surface containing font characters
392
- size: (width, height) of each character
393
- mapping: list of characters in font surface order
394
"""
395
396
def render(self, text: str, bpp: int = None) -> SDL_Surface:
397
"""
398
Render text using bitmap font.
399
400
Parameters:
401
- text: text to render
402
- bpp: bits per pixel for rendered surface
403
404
Returns:
405
SDL_Surface containing rendered text
406
"""
407
408
def can_render(self, text: str) -> bool:
409
"""
410
Check if font can render all characters in text.
411
412
Parameters:
413
- text: text to check
414
415
Returns:
416
True if all characters can be rendered
417
"""
418
419
@property
420
def size(self) -> tuple[int, int]:
421
"""Get character size as (width, height) tuple."""
422
```
423
424
### Text Direction Support
425
426
Constants and functions for text direction and rendering.
427
428
```python { .api }
429
# Text direction constants (for advanced text layout)
430
HB_DIRECTION_LTR: int = 0 # Left-to-right
431
HB_DIRECTION_RTL: int = 1 # Right-to-left
432
HB_DIRECTION_TTB: int = 2 # Top-to-bottom
433
HB_DIRECTION_BTT: int = 3 # Bottom-to-top
434
435
def TTF_SetDirection(direction: int) -> int:
436
"""Set text direction for complex text layout."""
437
438
def TTF_SetScript(script: int) -> int:
439
"""Set script for complex text layout."""
440
```
441
442
## Types
443
444
```python { .api }
445
class TTF_Font:
446
"""Opaque structure representing a loaded font."""
447
448
class SDL_Color:
449
"""Color structure for text rendering."""
450
r: int # Red component (0-255)
451
g: int # Green component (0-255)
452
b: int # Blue component (0-255)
453
a: int # Alpha component (0-255)
454
```
455
456
## Usage Examples
457
458
### Basic Text Rendering
459
460
```python
461
import sdl2
462
import sdl2.sdlttf
463
import sdl2.ext
464
465
# Initialize SDL2 and TTF
466
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
467
sdl2.sdlttf.TTF_Init()
468
469
# Create window and renderer
470
window = sdl2.SDL_CreateWindow(b"Text Rendering",
471
sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED,
472
800, 600, sdl2.SDL_WINDOW_SHOWN)
473
renderer = sdl2.SDL_CreateRenderer(window, -1, sdl2.SDL_RENDERER_ACCELERATED)
474
475
# Load font
476
font = sdl2.sdlttf.TTF_OpenFont(b"arial.ttf", 24)
477
if not font:
478
print("Failed to load font")
479
exit(1)
480
481
# Render text
482
color = sdl2.SDL_Color(255, 255, 255, 255) # White text
483
text_surface = sdl2.sdlttf.TTF_RenderText_Blended(font, b"Hello, PySDL2!", color)
484
text_texture = sdl2.SDL_CreateTextureFromSurface(renderer, text_surface)
485
sdl2.SDL_FreeSurface(text_surface)
486
487
# Get text dimensions
488
text_w = ctypes.c_int()
489
text_h = ctypes.c_int()
490
sdl2.SDL_QueryTexture(text_texture, None, None, text_w, text_h)
491
492
# Main loop
493
running = True
494
event = sdl2.SDL_Event()
495
496
while running:
497
while sdl2.SDL_PollEvent(event):
498
if event.type == sdl2.SDL_QUIT:
499
running = False
500
501
# Clear screen
502
sdl2.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
503
sdl2.SDL_RenderClear(renderer)
504
505
# Render text centered
506
dest_rect = sdl2.SDL_Rect(
507
(800 - text_w.value) // 2,
508
(600 - text_h.value) // 2,
509
text_w.value,
510
text_h.value
511
)
512
sdl2.SDL_RenderCopy(renderer, text_texture, None, dest_rect)
513
514
# Present frame
515
sdl2.SDL_RenderPresent(renderer)
516
517
# Cleanup
518
sdl2.SDL_DestroyTexture(text_texture)
519
sdl2.sdlttf.TTF_CloseFont(font)
520
sdl2.SDL_DestroyRenderer(renderer)
521
sdl2.SDL_DestroyWindow(window)
522
sdl2.sdlttf.TTF_Quit()
523
sdl2.SDL_Quit()
524
```
525
526
### High-Level Font Usage
527
528
```python
529
import sdl2.ext
530
531
# Initialize SDL2 extensions
532
sdl2.ext.init()
533
534
# Create window and renderer
535
window = sdl2.ext.Window("High-Level Text", size=(800, 600))
536
window.show()
537
renderer = sdl2.ext.Renderer(window)
538
539
# Create font manager
540
font_manager = sdl2.ext.FontManager("arial.ttf", "default", 24)
541
font_manager.add("times.ttf", "serif", 18)
542
font_manager.add("courier.ttf", "mono", 16)
543
544
# Get fonts
545
default_font = font_manager.get("default")
546
title_font = font_manager.get("default", 36) # Larger size
547
mono_font = font_manager.get("mono")
548
549
# Render different text styles
550
title_surface = title_font.render("PySDL2 Text Demo", (255, 255, 0))
551
body_surface = default_font.render("This is regular text.", (255, 255, 255))
552
code_surface = mono_font.render("print('Hello, World!')", (0, 255, 0))
553
554
# Convert surfaces to textures
555
title_texture = sdl2.ext.Texture(renderer, title_surface)
556
body_texture = sdl2.ext.Texture(renderer, body_surface)
557
code_texture = sdl2.ext.Texture(renderer, code_surface)
558
559
# Free surfaces (textures have copies)
560
sdl2.SDL_FreeSurface(title_surface)
561
sdl2.SDL_FreeSurface(body_surface)
562
sdl2.SDL_FreeSurface(code_surface)
563
564
# Main loop
565
running = True
566
while running:
567
events = sdl2.ext.get_events()
568
for event in events:
569
if event.type == sdl2.SDL_QUIT:
570
running = False
571
572
# Clear screen
573
renderer.clear((50, 50, 50))
574
575
# Render text at different positions
576
renderer.copy(title_texture, dstrect=sdl2.SDL_Rect(50, 50, 0, 0))
577
renderer.copy(body_texture, dstrect=sdl2.SDL_Rect(50, 150, 0, 0))
578
renderer.copy(code_texture, dstrect=sdl2.SDL_Rect(50, 200, 0, 0))
579
580
renderer.present()
581
582
# Cleanup
583
font_manager.close()
584
sdl2.ext.quit()
585
```
586
587
### Word Wrapping and Multi-line Text
588
589
```python
590
import sdl2
591
import sdl2.sdlttf
592
593
# Initialize
594
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
595
sdl2.sdlttf.TTF_Init()
596
597
# Create window
598
window = sdl2.SDL_CreateWindow(b"Word Wrapping",
599
sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED,
600
600, 400, sdl2.SDL_WINDOW_SHOWN)
601
renderer = sdl2.SDL_CreateRenderer(window, -1, sdl2.SDL_RENDERER_ACCELERATED)
602
603
# Load font
604
font = sdl2.sdlttf.TTF_OpenFont(b"arial.ttf", 18)
605
606
# Long text for word wrapping
607
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."
608
609
# Render wrapped text
610
color = sdl2.SDL_Color(255, 255, 255, 255)
611
wrapped_surface = sdl2.sdlttf.TTF_RenderUTF8_Blended_Wrapped(font, long_text, color, 500)
612
wrapped_texture = sdl2.SDL_CreateTextureFromSurface(renderer, wrapped_surface)
613
sdl2.SDL_FreeSurface(wrapped_surface)
614
615
# Main loop
616
running = True
617
event = sdl2.SDL_Event()
618
619
while running:
620
while sdl2.SDL_PollEvent(event):
621
if event.type == sdl2.SDL_QUIT:
622
running = False
623
624
# Clear and render
625
sdl2.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
626
sdl2.SDL_RenderClear(renderer)
627
628
# Render wrapped text
629
dest_rect = sdl2.SDL_Rect(50, 50, 500, 300)
630
sdl2.SDL_RenderCopy(renderer, wrapped_texture, None, dest_rect)
631
632
sdl2.SDL_RenderPresent(renderer)
633
634
# Cleanup
635
sdl2.SDL_DestroyTexture(wrapped_texture)
636
sdl2.sdlttf.TTF_CloseFont(font)
637
sdl2.SDL_DestroyRenderer(renderer)
638
sdl2.SDL_DestroyWindow(window)
639
sdl2.sdlttf.TTF_Quit()
640
sdl2.SDL_Quit()
641
```
642
643
### Bitmap Font Usage
644
645
```python
646
import sdl2.ext
647
648
# Initialize
649
sdl2.ext.init()
650
window = sdl2.ext.Window("Bitmap Font", size=(640, 480))
651
window.show()
652
653
# Load bitmap font surface (assumes 16x16 character grid)
654
font_surface = sdl2.SDL_LoadBMP(b"bitmap_font.bmp")
655
656
# Character mapping for ASCII printable characters
657
ascii_chars = [chr(i) for i in range(32, 127)]
658
659
# Create bitmap font
660
bitmap_font = sdl2.ext.BitmapFont(font_surface, (8, 16), ascii_chars)
661
662
# Render text with bitmap font
663
text = "Bitmap Font Text!"
664
rendered_surface = bitmap_font.render(text)
665
666
# Main loop
667
running = True
668
while running:
669
events = sdl2.ext.get_events()
670
for event in events:
671
if event.type == sdl2.SDL_QUIT:
672
running = False
673
674
# Clear screen and blit bitmap text
675
window_surface = sdl2.SDL_GetWindowSurface(window.window)
676
sdl2.SDL_FillRect(window_surface, None, 0) # Black background
677
678
dest_rect = sdl2.SDL_Rect(10, 10, 0, 0)
679
sdl2.SDL_BlitSurface(rendered_surface, None, window_surface, dest_rect)
680
681
sdl2.SDL_UpdateWindowSurface(window.window)
682
683
# Cleanup
684
sdl2.SDL_FreeSurface(rendered_surface)
685
sdl2.SDL_FreeSurface(font_surface)
686
sdl2.ext.quit()
687
```