23
23
# - setWeights function needs improvement
24
24
# - 'light' is an invalid weight value, remove it.
25
25
26
+ from collections import OrderedDict
26
27
import dataclasses
27
28
from functools import lru_cache
28
29
import json
@@ -947,6 +948,24 @@ def copy(self):
947
948
return new
948
949
949
950
951
+ class FontsInterface :
952
+ def __init__ (self , ordered_family ):
953
+ self .set_orderedfamily (ordered_family )
954
+
955
+ def set_orderedfamily (self , ordered_family ):
956
+ self .families = []
957
+ self .filepaths = []
958
+ for key , value in ordered_family .items ():
959
+ self .families .append (key )
960
+ self .filepaths .append (value )
961
+
962
+ def get_families (self ):
963
+ return self .families
964
+
965
+ def get_filepaths (self ):
966
+ return self .filepaths
967
+
968
+
950
969
class _JSONEncoder (json .JSONEncoder ):
951
970
def default (self , o ):
952
971
if isinstance (o , FontManager ):
@@ -1304,16 +1323,51 @@ def findfont(self, prop, fontext='ttf', directory=None,
1304
1323
rc_params = tuple (tuple (rcParams [key ]) for key in [
1305
1324
"font.serif" , "font.sans-serif" , "font.cursive" , "font.fantasy" ,
1306
1325
"font.monospace" ])
1326
+
1327
+ if not isinstance (prop , FontProperties ):
1328
+ prop = FontProperties ._from_any (prop )
1329
+
1307
1330
return self ._findfont_cached (
1308
1331
prop , fontext , directory , fallback_to_default , rebuild_if_missing ,
1309
1332
rc_params )
1310
1333
1334
+ def find_fontsprop (self , prop , fontext = 'ttf' , directory = None ,
1335
+ fallback_to_default = True , rebuild_if_missing = True ):
1336
+
1337
+ prop = FontProperties ._from_any (prop )
1338
+ ffamily = prop .get_family ()
1339
+
1340
+ # maintain two dicts, one for available paths,
1341
+ # the other for fallback paths
1342
+ fpaths , fbpaths = OrderedDict (), OrderedDict ()
1343
+ for fidx in range (len (ffamily )):
1344
+ cprop = prop .copy ()
1345
+
1346
+ # set current prop's family
1347
+ cprop .set_family (ffamily [fidx ])
1348
+
1349
+ try :
1350
+ fpath = self .findfont (cprop , fontext , directory ,
1351
+ False , rebuild_if_missing )
1352
+ fpaths [ffamily [fidx ]] = fpath
1353
+
1354
+ except ValueError as e :
1355
+ if fallback_to_default :
1356
+ fpath = self .findfont (cprop , fontext , directory ,
1357
+ True , rebuild_if_missing )
1358
+ fbpaths .update ({self .defaultFamily [fontext ]: fpath })
1359
+ else :
1360
+ raise e
1361
+
1362
+ # append fallback font(s) to the very end
1363
+ fpaths .update (fbpaths )
1364
+
1365
+ return FontsInterface (fpaths )
1366
+
1311
1367
@lru_cache ()
1312
1368
def _findfont_cached (self , prop , fontext , directory , fallback_to_default ,
1313
1369
rebuild_if_missing , rc_params ):
1314
1370
1315
- prop = FontProperties ._from_any (prop )
1316
-
1317
1371
fname = prop .get_file ()
1318
1372
if fname is not None :
1319
1373
return fname
@@ -1401,9 +1455,11 @@ def is_opentype_cff_font(filename):
1401
1455
1402
1456
1403
1457
@lru_cache (64 )
1404
- def _get_font (filename , hinting_factor , * , _kerning_factor , thread_id ):
1458
+ def _get_font (fpaths , hinting_factor , * , _kerning_factor , thread_id ):
1459
+ # multiple paths, take first one
1460
+ # for now, which is always guaranteed
1405
1461
return ft2font .FT2Font (
1406
- filename , hinting_factor , _kerning_factor = _kerning_factor )
1462
+ fpaths [ 0 ] , hinting_factor , _kerning_factor = _kerning_factor )
1407
1463
1408
1464
1409
1465
# FT2Font objects cannot be used across fork()s because they reference the same
@@ -1417,11 +1473,14 @@ def _get_font(filename, hinting_factor, *, _kerning_factor, thread_id):
1417
1473
def get_font (filename , hinting_factor = None ):
1418
1474
# Resolving the path avoids embedding the font twice in pdf/ps output if a
1419
1475
# single font is selected using two different relative paths.
1420
- filename = _cached_realpath (filename )
1476
+ if isinstance (filename , FontsInterface ):
1477
+ paths = tuple ([_cached_realpath (fname ) for fname in filename .get_filepaths ()])
1478
+ else :
1479
+ paths = tuple ([_cached_realpath (filename )])
1421
1480
if hinting_factor is None :
1422
1481
hinting_factor = rcParams ['text.hinting_factor' ]
1423
1482
# also key on the thread ID to prevent segfaults with multi-threading
1424
- return _get_font (filename , hinting_factor ,
1483
+ return _get_font (paths , hinting_factor ,
1425
1484
_kerning_factor = rcParams ['text.kerning_factor' ],
1426
1485
thread_id = threading .get_ident ())
1427
1486
@@ -1446,3 +1505,4 @@ def _load_fontmanager(*, try_read_cache=True):
1446
1505
1447
1506
fontManager = _load_fontmanager ()
1448
1507
findfont = fontManager .findfont
1508
+ find_fontsprop = fontManager .find_fontsprop
0 commit comments