27
27
try :
28
28
from io import FileIO
29
29
from typing import Iterable , Union
30
+
30
31
from displayio import Bitmap
31
32
except ImportError :
32
33
pass
@@ -47,7 +48,7 @@ class LVGLFont(GlyphCache):
47
48
48
49
def __init__ (self , f : FileIO , bitmap_class = None ):
49
50
"""Initialize LVGL font.
50
-
51
+
51
52
Args:
52
53
f: File object containing the LVGL font data
53
54
bitmap_class: Optional bitmap class to use for glyphs. Defaults to displayio.Bitmap.
@@ -76,6 +77,7 @@ def __init__(self, f: FileIO, bitmap_class=None):
76
77
table_marker = f .read (4 )
77
78
section_start = f .tell ()
78
79
remaining_section = f .read (section_size - 8 )
80
+ print (f"Table marker @ { section_start } : { table_marker } ({ section_size } bytes)" )
79
81
if table_marker == b"head" :
80
82
self ._load_head (remaining_section )
81
83
# Set bounding box based on font metrics from head section
@@ -84,7 +86,7 @@ def __init__(self, f: FileIO, bitmap_class=None):
84
86
self ._x_offset = 0
85
87
self ._y_offset = self ._descent
86
88
elif table_marker == b"cmap" :
87
- self ._load_cmap (remaining_section )
89
+ self ._load_cmap (remaining_section , section_start )
88
90
elif table_marker == b"loca" :
89
91
self ._max_cid = struct .unpack ("<I" , remaining_section [0 :4 ])[0 ]
90
92
self ._loca_start = section_start + 4
@@ -119,12 +121,10 @@ def _load_head(self, data):
119
121
self ._compression_alg = data [33 ]
120
122
self ._subpixel_rendering = data [34 ]
121
123
122
- def _load_cmap (self , data ):
124
+ def _load_cmap (self , data , section_start ):
123
125
data = memoryview (data )
124
126
subtable_count = struct .unpack ("<I" , data [0 :4 ])[0 ]
125
- self ._cmap_tiny = []
126
- self ._cmap_sparse = []
127
- self ._cmap_continuous = []
127
+ self ._cmap_subtables = []
128
128
data_offset = 4
129
129
130
130
for i in range (subtable_count ):
@@ -139,35 +139,22 @@ def _load_cmap(self, data):
139
139
# 1 byte - padding
140
140
if len (subtable_header ) < 16 :
141
141
raise RuntimeError ("Invalid cmap subtable header size" )
142
-
143
- (data_offset_val , range_start , range_length , glyph_offset , entries_count ) = struct . unpack (
144
- "<IIHHH" , subtable_header [:14 ]
142
+
143
+ (data_offset_val , range_start , range_length , glyph_offset , entries_count ) = (
144
+ struct . unpack ( "<IIHHH" , subtable_header [:14 ])
145
145
)
146
146
format_type = subtable_header [14 ]
147
147
148
- if format_type == 0 : # Format 0 - continuous
149
- if data_offset_val == 0 :
150
- raise RuntimeError ("Format 0 requires data section" )
151
- subtable_data = data [data_offset_val :data_offset_val + range_length ]
152
- if len (subtable_data ) < range_length :
153
- raise RuntimeError ("Invalid cmap data length" )
154
- glyph_ids = [gid + glyph_offset for gid in subtable_data ]
155
- self ._cmap_continuous .append ((range_start , range_start + range_length , glyph_ids ))
156
- elif format_type == 2 : # Format 0 tiny
157
- self ._cmap_tiny .append ((range_start , range_start + range_length , glyph_offset ))
158
- elif format_type == 3 : # Format sparse tiny
159
- if data_offset_val == 0 :
160
- raise RuntimeError ("Format 3 requires data section" )
161
- subtable_data = data [data_offset_val :data_offset_val + entries_count * 2 ]
162
- if len (subtable_data ) < entries_count * 2 :
163
- raise RuntimeError ("Invalid cmap data length" )
164
- codepoints = []
165
- for j in range (entries_count ):
166
- cp_offset = struct .unpack ("<H" , subtable_data [j * 2 :(j + 1 ) * 2 ])[0 ]
167
- codepoints .append (range_start + cp_offset )
168
- self ._cmap_sparse .append ((codepoints , glyph_offset ))
169
- else :
170
- raise RuntimeError (f"Unsupported cmap format { format_type } " )
148
+ # Store subtable header info
149
+ subtable_info = {
150
+ "format" : format_type ,
151
+ "data_offset" : data_offset_val + section_start - 8 ,
152
+ "range_start" : range_start ,
153
+ "range_length" : range_length ,
154
+ "glyph_offset" : glyph_offset ,
155
+ "entries_count" : entries_count ,
156
+ }
157
+ self ._cmap_subtables .append (subtable_info )
171
158
172
159
@property
173
160
def ascent (self ) -> int :
@@ -218,25 +205,41 @@ def load_glyphs(self, code_points: Union[int, str, Iterable[int]]) -> None:
218
205
for code_point in code_points :
219
206
# Find character ID in the cmap table
220
207
cid = None
221
- # Check format 0 (continuous)
222
- for start , end , glyph_ids in self ._cmap_continuous :
223
- if start <= code_point < end :
224
- cid = glyph_ids [code_point - start ]
225
- break
226
-
227
- # Check format 2 (format 0 tiny)
228
- if cid is None :
229
- for start , end , offset in self ._cmap_tiny :
230
- if start <= code_point < end :
231
- cid = offset + (code_point - start )
208
+
209
+ # Search through all subtables
210
+ for subtable in self ._cmap_subtables :
211
+ format_type = subtable ["format" ]
212
+ range_start = subtable ["range_start" ]
213
+ range_length = subtable ["range_length" ]
214
+ glyph_offset = subtable ["glyph_offset" ]
215
+ entries_count = subtable ["entries_count" ]
216
+ data_offset = subtable ["data_offset" ]
217
+
218
+ if range_start <= code_point < range_start + range_length :
219
+ if format_type == 0 : # Continuous
220
+ # Read the glyph IDs from the data section (single bytes)
221
+ self .file .seek (data_offset )
222
+ subtable_data = self .file .read (entries_count )
223
+ glyph_id = subtable_data [code_point - range_start ]
224
+ if glyph_id == 0 :
225
+ print (" Glyph ID 0: not found" )
226
+ continue
227
+ cid = glyph_id + glyph_offset
232
228
break
233
-
234
- # Check format 3 (sparse tiny)
235
- if cid is None :
236
- for codepoints , offset in self ._cmap_sparse :
237
- if code_point in codepoints :
238
- cid = offset + codepoints .index (code_point )
229
+ elif format_type == 2 : # Format 0 tiny
230
+ cid = glyph_offset + (code_point - range_start )
239
231
break
232
+ elif format_type == 3 : # Sparse tiny
233
+ # Read the codepoint offsets from the data section
234
+ self .file .seek (data_offset )
235
+ subtable_data = self .file .read (entries_count * 2 )
236
+ for i in range (entries_count ):
237
+ cp_offset = struct .unpack ("<H" , subtable_data [i * 2 : (i + 1 ) * 2 ])[0 ]
238
+ if cp_offset + range_start == code_point :
239
+ cid = glyph_offset + i
240
+ break
241
+ if cid is not None :
242
+ break
240
243
241
244
if cid is None or cid >= self ._max_cid :
242
245
self ._glyphs [code_point ] = None
0 commit comments