@@ -45,6 +45,12 @@ class LVGLFont(GlyphCache):
4545 """
4646
4747 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+ """
4854 super ().__init__ ()
4955 f .seek (0 )
5056 self .file = f
@@ -77,7 +83,7 @@ def __init__(self, f: FileIO, bitmap_class=None):
7783 self ._x_offset = 0
7884 self ._y_offset = self ._descent
7985 elif table_marker == b"cmap" :
80- self ._load_cmap (remaining_section )
86+ self ._load_cmap (remaining_section , section_start )
8187 elif table_marker == b"loca" :
8288 self ._max_cid = struct .unpack ("<I" , remaining_section [0 :4 ])[0 ]
8389 self ._loca_start = section_start + 4
@@ -112,21 +118,40 @@ def _load_head(self, data):
112118 self ._compression_alg = data [33 ]
113119 self ._subpixel_rendering = data [34 ]
114120
115- def _load_cmap (self , data ):
121+ def _load_cmap (self , data , section_start ):
116122 data = memoryview (data )
117123 subtable_count = struct .unpack ("<I" , data [0 :4 ])[0 ]
118- self ._cmap_tiny = []
124+ self ._cmap_subtables = []
125+ data_offset = 4
126+
119127 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 ])
123142 )
124143 format_type = subtable_header [14 ]
125144
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 )
130155
131156 @property
132157 def ascent (self ) -> int :
@@ -177,10 +202,38 @@ def load_glyphs(self, code_points: Union[int, str, Iterable[int]]) -> None:
177202 for code_point in code_points :
178203 # Find character ID in the cmap table
179204 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
184237
185238 if cid is None or cid >= self ._max_cid :
186239 self ._glyphs [code_point ] = None
0 commit comments