@@ -45,6 +45,12 @@ class LVGLFont(GlyphCache):
45
45
"""
46
46
47
47
def __init__ (self , f : FileIO , bitmap_class = None ):
48
+ """Initialize LVGL font.
49
+
50
+ Args:
51
+ f: File object containing the LVGL font data
52
+ bitmap_class: Optional bitmap class to use for glyphs. Defaults to displayio.Bitmap.
53
+ """
48
54
super ().__init__ ()
49
55
f .seek (0 )
50
56
self .file = f
@@ -77,7 +83,7 @@ def __init__(self, f: FileIO, bitmap_class=None):
77
83
self ._x_offset = 0
78
84
self ._y_offset = self ._descent
79
85
elif table_marker == b"cmap" :
80
- self ._load_cmap (remaining_section )
86
+ self ._load_cmap (remaining_section , section_start )
81
87
elif table_marker == b"loca" :
82
88
self ._max_cid = struct .unpack ("<I" , remaining_section [0 :4 ])[0 ]
83
89
self ._loca_start = section_start + 4
@@ -112,21 +118,40 @@ def _load_head(self, data):
112
118
self ._compression_alg = data [33 ]
113
119
self ._subpixel_rendering = data [34 ]
114
120
115
- def _load_cmap (self , data ):
121
+ def _load_cmap (self , data , section_start ):
116
122
data = memoryview (data )
117
123
subtable_count = struct .unpack ("<I" , data [0 :4 ])[0 ]
118
- self ._cmap_tiny = []
124
+ self ._cmap_subtables = []
125
+ data_offset = 4
126
+
119
127
for i in range (subtable_count ):
120
- subtable_header = data [4 + 16 * i : 4 + 16 * (i + 1 )]
121
- (_ , range_start , range_length , glyph_offset , _ ) = struct .unpack (
122
- "<IIHHH" , subtable_header [:14 ]
128
+ subtable_header = data [data_offset + 16 * i : data_offset + 16 * (i + 1 )]
129
+ # Subtable header format:
130
+ # 4 bytes - data offset
131
+ # 4 bytes - range start
132
+ # 2 bytes - range length
133
+ # 2 bytes - glyph ID offset
134
+ # 2 bytes - data entries count
135
+ # 1 byte - format type
136
+ # 1 byte - padding
137
+ if len (subtable_header ) < 16 :
138
+ raise RuntimeError ("Invalid cmap subtable header size" )
139
+
140
+ (data_offset_val , range_start , range_length , glyph_offset , entries_count ) = (
141
+ struct .unpack ("<IIHHH" , subtable_header [:14 ])
123
142
)
124
143
format_type = subtable_header [14 ]
125
144
126
- if format_type != 2 :
127
- raise RuntimeError (f"Unsupported cmap format { format_type } " )
128
-
129
- self ._cmap_tiny .append ((range_start , range_start + range_length , glyph_offset ))
145
+ # Store subtable header info
146
+ subtable_info = {
147
+ "format" : format_type ,
148
+ "data_offset" : data_offset_val + section_start - 8 ,
149
+ "range_start" : range_start ,
150
+ "range_length" : range_length ,
151
+ "glyph_offset" : glyph_offset ,
152
+ "entries_count" : entries_count ,
153
+ }
154
+ self ._cmap_subtables .append (subtable_info )
130
155
131
156
@property
132
157
def ascent (self ) -> int :
@@ -177,10 +202,38 @@ def load_glyphs(self, code_points: Union[int, str, Iterable[int]]) -> None:
177
202
for code_point in code_points :
178
203
# Find character ID in the cmap table
179
204
cid = None
180
- for start , end , offset in self ._cmap_tiny :
181
- if start <= code_point < end :
182
- cid = offset + (code_point - start )
183
- break
205
+
206
+ # Search through all subtables
207
+ for subtable in self ._cmap_subtables :
208
+ format_type = subtable ["format" ]
209
+ range_start = subtable ["range_start" ]
210
+ range_length = subtable ["range_length" ]
211
+ glyph_offset = subtable ["glyph_offset" ]
212
+ entries_count = subtable ["entries_count" ]
213
+ data_offset = subtable ["data_offset" ]
214
+
215
+ if range_start <= code_point < range_start + range_length :
216
+ if format_type == 0 : # Continuous
217
+ # Read the glyph IDs from the data section (single bytes)
218
+ self .file .seek (data_offset )
219
+ subtable_data = self .file .read (entries_count )
220
+ glyph_id = subtable_data [code_point - range_start ]
221
+ cid = glyph_id + glyph_offset
222
+ break
223
+ elif format_type == 2 : # Format 0 tiny
224
+ cid = glyph_offset + (code_point - range_start )
225
+ break
226
+ elif format_type == 3 : # Sparse tiny
227
+ # Read the codepoint offsets from the data section
228
+ self .file .seek (data_offset )
229
+ subtable_data = self .file .read (entries_count * 2 )
230
+ for i in range (entries_count ):
231
+ cp_offset = struct .unpack ("<H" , subtable_data [i * 2 : (i + 1 ) * 2 ])[0 ]
232
+ if cp_offset + range_start == code_point :
233
+ cid = glyph_offset + i
234
+ break
235
+ if cid is not None :
236
+ break
184
237
185
238
if cid is None or cid >= self ._max_cid :
186
239
self ._glyphs [code_point ] = None
0 commit comments