55import os
66import subprocess
77import sys
8+ from typing import Dict , Optional , Tuple , Union
89
910from reportlab .pdfbase .pdfmetrics import registerFont
1011from reportlab .pdfbase .ttfonts import TTFError , TTFont
@@ -37,7 +38,7 @@ class FontMap:
3738 them in reportlab.
3839 """
3940
40- def __init__ (self ):
41+ def __init__ (self ) -> None :
4142 """
4243 The map has the form:
4344 'internal_name': {
@@ -46,12 +47,14 @@ def __init__(self):
4647 }
4748 for faster searching we use internal keys for finding the matching font
4849 """
49- self ._map = {}
50+ self ._map : Dict [ str , Dict [ str , Union [ str , bool , int ]]] = {}
5051
5152 self .register_default_fonts ()
5253
5354 @staticmethod
54- def build_internal_name (family , weight = "normal" , style = "normal" ):
55+ def build_internal_name (
56+ family : str , weight : str = "normal" , style : str = "normal"
57+ ) -> str :
5558 """
5659 If the weight or style is given, append the capitalized weight and style
5760 to the font name. E.g. family="Arial", weight="bold" and style="italic"
@@ -71,7 +74,12 @@ def build_internal_name(family, weight="normal", style="normal"):
7174 return result_name
7275
7376 @staticmethod
74- def guess_font_filename (basename , weight = "normal" , style = "normal" , extension = "ttf" ):
77+ def guess_font_filename (
78+ basename : str ,
79+ weight : str = "normal" ,
80+ style : str = "normal" ,
81+ extension : str = "ttf" ,
82+ ) -> str :
7583 """
7684 Try to guess the actual font filename depending on family, weight and style,
7785 this works at least for windows on the "default" fonts like, Arial,
@@ -89,7 +97,9 @@ def guess_font_filename(basename, weight="normal", style="normal", extension="tt
8997 filename = f"{ basename } { prefix } .{ extension } "
9098 return filename
9199
92- def use_fontconfig (self , font_name , weight = "normal" , style = "normal" ):
100+ def use_fontconfig (
101+ self , font_name : str , weight : str = "normal" , style : str = "normal"
102+ ) -> Tuple [Optional [str ], bool ]:
93103 NOT_FOUND = (None , False )
94104 # Searching with Fontconfig
95105 try :
@@ -124,7 +134,7 @@ def use_fontconfig(self, font_name, weight="normal", style="normal"):
124134 }
125135 return font_name , exact
126136
127- def register_default_fonts (self ):
137+ def register_default_fonts (self ) -> None :
128138 self .register_font ("Times New Roman" , rlgFontName = "Times-Roman" )
129139 self .register_font ("Times New Roman" , weight = "bold" , rlgFontName = "Times-Bold" )
130140 self .register_font (
@@ -198,8 +208,13 @@ def register_default_fonts(self):
198208 )
199209
200210 def register_font_family (
201- self , family , normal , bold = None , italic = None , bolditalic = None
202- ):
211+ self ,
212+ family : str ,
213+ normal : str ,
214+ bold : Optional [str ] = None ,
215+ italic : Optional [str ] = None ,
216+ bolditalic : Optional [str ] = None ,
217+ ) -> None :
203218 self .register_font (family , normal )
204219 if bold is not None :
205220 self .register_font (family , bold , weight = "bold" )
@@ -210,12 +225,12 @@ def register_font_family(
210225
211226 def register_font (
212227 self ,
213- font_family ,
214- font_path = None ,
215- weight = "normal" ,
216- style = "normal" ,
217- rlgFontName = None ,
218- ):
228+ font_family : str ,
229+ font_path : Optional [ str ] = None ,
230+ weight : str = "normal" ,
231+ style : str = "normal" ,
232+ rlgFontName : Optional [ str ] = None ,
233+ ) -> Tuple [ Optional [ str ], bool ] :
219234 """
220235 Register a font identified by its family, weight and style linked to an
221236 actual fontfile. Or map an svg font family, weight and style combination
@@ -253,47 +268,69 @@ def register_font(
253268 except TTFError :
254269 return NOT_FOUND
255270
256- def find_font (self , font_name , weight = "normal" , style = "normal" ):
271+ # If we reach here, no registration was possible
272+ return NOT_FOUND
273+
274+ def find_font (
275+ self , font_name : str , weight : str = "normal" , style : str = "normal"
276+ ) -> Tuple [str , bool ]:
257277 """Return the font and a Boolean indicating if the match is exact."""
258278 internal_name = FontMap .build_internal_name (font_name , weight , style )
259279 # Step 1 check if the font is one of the buildin standard fonts
260280 if internal_name in STANDARD_FONT_NAMES :
261281 return internal_name , True
262282 # Step 2 Check if font is already registered
263283 if internal_name in self ._map :
284+ font_entry = self ._map [internal_name ]
264285 return (
265- self . _map [ internal_name ][ "rlgFont" ],
266- self . _map [ internal_name ][ "exact" ],
286+ str ( font_entry [ "rlgFont" ]) ,
287+ bool ( font_entry [ "exact" ]) ,
267288 )
268289 # Step 3 Try to auto register the font
269290 # Try first to register the font if it exists as ttf
270291 guessed_filename = FontMap .guess_font_filename (font_name , weight , style )
271292 reg_name , exact = self .register_font (font_name , guessed_filename )
272293 if reg_name is not None :
273294 return reg_name , exact
274- return self .use_fontconfig (font_name , weight , style )
295+ fontconfig_result = self .use_fontconfig (font_name , weight , style )
296+ if fontconfig_result [0 ] is not None :
297+ return fontconfig_result [0 ], fontconfig_result [1 ]
298+ # Fallback to default font if nothing found
299+ return DEFAULT_FONT_NAME , False
275300
276301
277302_font_map = FontMap () # the global font map
278303
279304
280305def register_font (
281- font_name , font_path = None , weight = "normal" , style = "normal" , rlgFontName = None
282- ):
306+ font_name : str ,
307+ font_path : Optional [str ] = None ,
308+ weight : str = "normal" ,
309+ style : str = "normal" ,
310+ rlgFontName : Optional [str ] = None ,
311+ ) -> Tuple [Optional [str ], bool ]:
283312 """
284313 Register a font by name or alias and path to font including file extension.
285314 """
286315 return _font_map .register_font (font_name , font_path , weight , style , rlgFontName )
287316
288317
289- def find_font (font_name , weight = "normal" , style = "normal" ):
318+ def find_font (
319+ font_name : str , weight : str = "normal" , style : str = "normal"
320+ ) -> Tuple [str , bool ]:
290321 """Return the font and a Boolean indicating if the match is exact."""
291322 return _font_map .find_font (font_name , weight , style )
292323
293324
294- def register_font_family (self , family , normal , bold = None , italic = None , bolditalic = None ):
325+ def register_font_family (
326+ family : str ,
327+ normal : str ,
328+ bold : Optional [str ] = None ,
329+ italic : Optional [str ] = None ,
330+ bolditalic : Optional [str ] = None ,
331+ ) -> None :
295332 _font_map .register_font_family (family , normal , bold , italic , bolditalic )
296333
297334
298- def get_global_font_map ():
335+ def get_global_font_map () -> FontMap :
299336 return _font_map
0 commit comments