diff --git a/adafruit_bitmap_font/lvfontbin.py b/adafruit_bitmap_font/lvfontbin.py index 13075da..5438f04 100644 --- a/adafruit_bitmap_font/lvfontbin.py +++ b/adafruit_bitmap_font/lvfontbin.py @@ -45,6 +45,12 @@ class LVGLFont(GlyphCache): """ def __init__(self, f: FileIO, bitmap_class=None): + """Initialize LVGL font. + + Args: + f: File object containing the LVGL font data + bitmap_class: Optional bitmap class to use for glyphs. Defaults to displayio.Bitmap. + """ super().__init__() f.seek(0) self.file = f @@ -77,7 +83,7 @@ def __init__(self, f: FileIO, bitmap_class=None): self._x_offset = 0 self._y_offset = self._descent elif table_marker == b"cmap": - self._load_cmap(remaining_section) + self._load_cmap(remaining_section, section_start) elif table_marker == b"loca": self._max_cid = struct.unpack(" int: @@ -177,10 +202,38 @@ def load_glyphs(self, code_points: Union[int, str, Iterable[int]]) -> None: for code_point in code_points: # Find character ID in the cmap table cid = None - for start, end, offset in self._cmap_tiny: - if start <= code_point < end: - cid = offset + (code_point - start) - break + + # Search through all subtables + for subtable in self._cmap_subtables: + format_type = subtable["format"] + range_start = subtable["range_start"] + range_length = subtable["range_length"] + glyph_offset = subtable["glyph_offset"] + entries_count = subtable["entries_count"] + data_offset = subtable["data_offset"] + + if range_start <= code_point < range_start + range_length: + if format_type == 0: # Continuous + # Read the glyph IDs from the data section (single bytes) + self.file.seek(data_offset) + subtable_data = self.file.read(entries_count) + glyph_id = subtable_data[code_point - range_start] + cid = glyph_id + glyph_offset + break + elif format_type == 2: # Format 0 tiny + cid = glyph_offset + (code_point - range_start) + break + elif format_type == 3: # Sparse tiny + # Read the codepoint offsets from the data section + self.file.seek(data_offset) + subtable_data = self.file.read(entries_count * 2) + for i in range(entries_count): + cp_offset = struct.unpack("= self._max_cid: self._glyphs[code_point] = None diff --git a/examples/bitmap_font_lvgl_simpletest.py b/examples/bitmap_font_lvgl_simpletest.py new file mode 100644 index 0000000..72f9872 --- /dev/null +++ b/examples/bitmap_font_lvgl_simpletest.py @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +This example demonstrates loading and using an LVGL format font. +You can convert fonts to LVGL format using the online converter: +https://lvgl.io/tools/fontconverter +""" + +from adafruit_bitmap_font import bitmap_font + +# Use the Japanese font file +font_file = "fonts/unifont-16.0.02-ja.bin" + +font = bitmap_font.load_font(font_file) +print("Successfully loaded LVGL font") +print("Font metrics:") +print(f" Ascent: {font.ascent}") +print(f" Descent: {font.descent}") +bbox = font.get_bounding_box() +print(f" Bounding box: width={bbox[0]}, height={bbox[1]}, x_offset={bbox[2]}, y_offset={bbox[3]}") + +# Test characters +test_japanese = "a こんにちは世界🎉" # Hello World in Japanese (according to Claude) +print(f"\nTesting characters: {test_japanese}") +font.load_glyphs(test_japanese) +for c in test_japanese: + glyph = font.get_glyph(ord(c)) + if glyph: + print(f" Character '{c}' (U+{ord(c):04X}):") # Print ASCII art representation of the glyph + for y in range(glyph.height): + pixels = [] + for x in range(glyph.width): + value = glyph.bitmap[x, y] + pixel = "#" if value > 0 else " " + pixels.append(pixel) + print(" " + "".join(pixels)) + else: + print(f" Character '{c}' (U+{ord(c):04X}) not found in font") diff --git a/examples/fonts/unifont-16.0.02-ascii-emoji.bin b/examples/fonts/unifont-16.0.02-ascii-emoji.bin index 71ba9b4..418f709 100644 Binary files a/examples/fonts/unifont-16.0.02-ascii-emoji.bin and b/examples/fonts/unifont-16.0.02-ascii-emoji.bin differ diff --git a/examples/fonts/unifont-16.0.02-ja.bin b/examples/fonts/unifont-16.0.02-ja.bin new file mode 100644 index 0000000..e550156 Binary files /dev/null and b/examples/fonts/unifont-16.0.02-ja.bin differ diff --git a/examples/fonts/unifont-16.0.02-ja.bin.license b/examples/fonts/unifont-16.0.02-ja.bin.license new file mode 100644 index 0000000..18b43d8 --- /dev/null +++ b/examples/fonts/unifont-16.0.02-ja.bin.license @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2024 GNU Unifont Contributors +# +# SPDX-License-Identifier: OFL-1.1 + +# Unifont version 16.0.02 is licensed under the SIL Open Font License 1.1 (OFL-1.1). + +# Original Unifont converted to LVGL binary format for use with CircuitPython.