Skip to content

Getting Font Glyphs apparently limited to 167 or less #10449

Open
@TheKitty

Description

@TheKitty

CircuitPython version and board name

Adafruit CircuitPython 10.0.0-alpha.7 on 2025-06-17; Adafruit Metro RP2350 with rp2350b
Board ID:adafruit_metro_rp2350
UID:030FA9DAE6154C9A

Code/REPL

# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import supervisor
from displayio import Group, TileGrid, Palette, Bitmap
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
from adafruit_fruitjam.peripherals import request_display_config
import gc

colors = 2

request_display_config(640, 480)

main_group = Group()
display = supervisor.runtime.display
display.root_group = main_group

font_file = "fonts/cp437-8x12.bdf"
font = bitmap_font.load_font(font_file)
gc.collect()

char_size = font.get_bounding_box()
screen_size = (display.width // char_size[0], display.height // char_size[1])

terminal_palette = Palette(colors)
terminal_palette[0] = 0x000000
terminal_palette[1] = 0xffffff

# Display info labels
text = f"Screen size (pixels): {display.width}x{display.height}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 55
main_group.append(text_area)

text = f"Screen size (characters): {screen_size[0]}x{screen_size[1]}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 65
main_group.append(text_area)

text_area = label.Label(font, text=font_file, color=terminal_palette[1])
text_area.x = 0
text_area.y = 80
main_group.append(text_area)

text = f"Font size (pixels): {char_size[0]}x{char_size[1]}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 90
main_group.append(text_area)

gc.collect()

# Work around glyph cache limitation by processing in batches
def display_all_chars_with_cache_management():
    """Display characters starting from 81 through 256"""
    
    # Clear previous attempts
    while len(main_group) > 4:  # Keep the 4 info labels
        main_group.pop()
    gc.collect()
    
    char_width = 8
    char_height = char_size[1]
    chars_per_line = display.width // char_width
    
    # Start from character 81, display through 256
    start_char = 89
    end_char = 240
    total_chars = end_char - start_char
    total_lines = (total_chars + chars_per_line - 1) // chars_per_line
    
    # Create bitmap for the character range
    bitmap_height = min(total_lines * char_height, display.height - 110)
    charset_bitmap = Bitmap(display.width, bitmap_height, 2)
    
    # Create palette
    charset_palette = Palette(2)
    charset_palette[0] = 0x000000  # Black background
    charset_palette[1] = 0xFFFFFF  # White text
    
    print(f"Created bitmap: {display.width}x{bitmap_height} pixels")
    print(f"Displaying characters {start_char}-{end_char-1}")
    
    # Process characters in batches to work around glyph cache limits
    batch_size = 80  # Process 80 characters at a time
    total_displayed = 0
    
    for batch_start in range(start_char, end_char, batch_size):
        batch_end = min(batch_start + batch_size, end_char)
        print(f"Processing batch {batch_start}-{batch_end-1}")
        
        # Force garbage collection before each batch
        gc.collect()
        
        batch_displayed = 0
        for code in range(batch_start, batch_end):
            try:
                # Calculate position (adjust for starting at character 81)
                adjusted_index = code - start_char
                char_x = (adjusted_index % chars_per_line) * char_width
                char_y = (adjusted_index // chars_per_line) * char_height
                
                # Skip if position is outside bitmap
                if char_y + char_height > bitmap_height:
                    print(f"Reached bitmap height limit at character {code}")
                    break
                
                # Get glyph and draw it
                glyph = font.get_glyph(code)
                
                # Draw with bounds checking
                glyph_height = min(glyph.bitmap.height, char_height)
                glyph_width = min(glyph.bitmap.width, char_width)
                
                for py in range(glyph_height):
                    for px in range(glyph_width):
                        if (py + char_y < bitmap_height and 
                            px + char_x < display.width):
                            try:
                                pixel_val = glyph.bitmap[px, py]
                                if pixel_val:
                                    charset_bitmap[px + char_x, py + char_y] = 1
                            except (IndexError, MemoryError):
                                continue
                
                batch_displayed += 1
                total_displayed += 1
                
            except (MemoryError, AttributeError, ValueError) as e:
                print(f"Skipped character {code} in batch: {type(e).__name__}")
                continue
        
        print(f"Batch complete: {batch_displayed} characters drawn")
        
        # Try to clear glyph cache between batches
        try:
            # Force garbage collection to potentially free glyph cache
            gc.collect()
            # Small delay to let things settle
            import time
            time.sleep(0.1)
        except:
            pass
    
    # Create TileGrid to display the final bitmap
    charset_tilegrid = TileGrid(
        charset_bitmap,
        pixel_shader=charset_palette,
        x=0,
        y=110
    )
    
    main_group.append(charset_tilegrid)
    
    print(f"Final result: {total_displayed} characters from {start_char}-{end_char-1}")
    return total_displayed

# Try the cache-aware approach
chars_displayed = display_all_chars_with_cache_management()
gc.collect()

print(f"Successfully displayed {chars_displayed} characters")
print(f"Final free memory: {gc.mem_free()} bytes")

while(True):
    pass

Behavior

This code goes to great lengths to keep the number of glyphs displayed to below 167. If more are displayed, the program halts with memory errors, even if there is enough memory available.

Description

Trying to display all 255 glyphs in a .bdf font seems impossible as if one tries to display more than 167, there is a memory error.

Additional information

Displaying <167 glyphs works just fine and results in 40k memory free, so it is not hitting a memory barrier.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions