Skip to content

Commit 78cc309

Browse files
authored
Merge pull request #3079 from adafruit/TheKitty-patch-8
Create Display_LVGL_Font.py
2 parents 572e952 + 6216a8a commit 78cc309

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
#
5+
# Display an LVGL (.bin) font on a CircuitPython board and
6+
# 640x480 DVI display. Unknown characters will be "."
7+
#
8+
# pylint: disable=broad-except, bare-except
9+
10+
import gc
11+
import displayio
12+
import supervisor
13+
from adafruit_bitmap_font import bitmap_font
14+
from adafruit_display_text import label
15+
from adafruit_fruitjam.peripherals import request_display_config
16+
17+
# Use the easy library call to set the resolution
18+
request_display_config(640, 480)
19+
20+
# Initialize display
21+
display = supervisor.runtime.display
22+
main_group = displayio.Group()
23+
display.root_group = main_group
24+
25+
print(f"Initial memory: {gc.mem_free()}")
26+
27+
# Font loading with error handling and diagnostics
28+
font_file = "fonts/CP437_16h.bin"
29+
try:
30+
font = bitmap_font.load_font(font_file) # pylint: disable=redefined-outer-name
31+
print(f"Font loaded: {font_file}")
32+
print(f"Memory after font load: {gc.mem_free()}")
33+
34+
# Diagnostic: Check font properties
35+
try:
36+
bbox = font.get_bounding_box()
37+
print(f"Font bounding box: {bbox}")
38+
39+
# Test a few common characters
40+
test_chars = [32, 65, 97] # space, 'A', 'a'
41+
for char_code in test_chars:
42+
glyph = font.get_glyph(char_code)
43+
if glyph:
44+
print(f"Char {char_code} ('{chr(char_code)}'): OK")
45+
else:
46+
print(f"Char {char_code} ('{chr(char_code)}'): Missing")
47+
48+
except Exception as e:
49+
print(f"Error checking font properties: {e}")
50+
51+
except Exception as e:
52+
print(f"Error loading font {font_file}: {e}")
53+
# Fallback to terminalio font
54+
import terminalio
55+
font = terminalio.FONT
56+
print("Using fallback terminalio.FONT")
57+
58+
# Get actual font dimensions
59+
try:
60+
font_bbox = font.get_bounding_box()
61+
char_width = font_bbox[0]
62+
char_height = font_bbox[1]
63+
print(f"Actual font size: {char_width}x{char_height}")
64+
except:
65+
char_width = 9 # fallback
66+
char_height = 16 # fallback
67+
print(f"Using fallback font size: {char_width}x{char_height}")
68+
69+
chars_per_line = 32 # Fixed at 32 characters per line
70+
line_number_width = 5 * char_width # Space for "000: " (5 characters)
71+
72+
displayed_count = 0
73+
skipped_count = 0
74+
current_x = line_number_width # Start after line number space
75+
current_y = char_height
76+
current_line_start = 0
77+
78+
def create_char_label(thefont, ch, x, y):
79+
"""Helper function to create character labels with error handling"""
80+
try:
81+
return label.Label(thefont, text=ch, color=0xFFFFFF, x=x, y=y)
82+
except Exception as e:
83+
print(f"Error creating label for '{ch}': {e}")
84+
return None
85+
86+
# Add first line number
87+
text = f"{current_line_start:03d}: "
88+
print(f"Creating line number: '{text}'")
89+
90+
for i, char in enumerate(text):
91+
char_label = create_char_label(font, char, i * char_width, current_y)
92+
if char_label:
93+
main_group.append(char_label)
94+
95+
print(f"Memory after first line number: {gc.mem_free()}")
96+
97+
# Try all characters from 0-255 and display ones that exist
98+
for char_code in range(256):
99+
try:
100+
# Check if we need to wrap to next line
101+
if (char_code > 0) and (char_code % chars_per_line == 0):
102+
current_x = line_number_width # Reset to after line number
103+
current_y += char_height + 4 # Add some line spacing
104+
current_line_start = char_code
105+
106+
# Stop if we run out of vertical space
107+
if current_y + char_height > display.height:
108+
print(f"Display full, stopped at character {char_code}")
109+
break
110+
111+
# Add line number for this new line
112+
text = f"{current_line_start:03d}: "
113+
for i, char in enumerate(text):
114+
char_label = create_char_label(font, char, i * char_width, current_y)
115+
if char_label:
116+
main_group.append(char_label)
117+
118+
# Check if glyph exists
119+
glyph = font.get_glyph(char_code)
120+
121+
if glyph is None:
122+
# No glyph available - display a period instead
123+
display_char = "."
124+
skipped_count += 1
125+
else:
126+
# Glyph exists - display the actual character
127+
display_char = chr(char_code)
128+
129+
# Create label for this character (or replacement)
130+
char_label = create_char_label(font, display_char, current_x, current_y)
131+
if char_label:
132+
main_group.append(char_label)
133+
134+
current_x += char_width
135+
displayed_count += 1
136+
137+
except (MemoryError, ValueError) as e:
138+
print(f"Memory/Value error at character {char_code}: {e}")
139+
break
140+
except Exception as e:
141+
print(f"Unexpected error at character {char_code}: {e}")
142+
# Continue with next character
143+
current_x += char_width
144+
displayed_count += 1
145+
146+
# More frequent garbage collection
147+
if char_code % 8 == 0:
148+
gc.collect()
149+
150+
# Progress indicator for debugging
151+
if char_code % 32 == 0:
152+
msg = f"Processed up to character {char_code}, memory: {gc.mem_free()}" # pylint: disable=f-string-without-interpolation
153+
print(msg)
154+
155+
print("\nCompleted character display:")
156+
print(f"Found {displayed_count - skipped_count} characters with glyphs")
157+
print(f"{skipped_count} missing characters displayed as periods")
158+
print(f"Total labels created: {len(main_group)}")
159+
print(f"Final free memory: {gc.mem_free()} bytes")
160+
161+
# Keep display active
162+
while True:
163+
pass

0 commit comments

Comments
 (0)