Skip to content

Commit 856e95f

Browse files
committed
Implement loading of any font in a collection
For backwards-compatibility, the path+index is passed around in a lightweight subclass of `str`.
1 parent 11a56ec commit 856e95f

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

lib/matplotlib/font_manager.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,19 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
310310
return [fname for fname in fontfiles if os.path.exists(fname)]
311311

312312

313+
class FontPath(str):
314+
__match_args__ = ('path', 'face_index')
315+
316+
def __new__(cls, path, face_index):
317+
ret = super().__new__(cls, path)
318+
ret.face_index = face_index
319+
return ret
320+
321+
@property
322+
def path(self):
323+
return str(self)
324+
325+
313326
@dataclasses.dataclass(frozen=True)
314327
class FontEntry:
315328
"""
@@ -1542,7 +1555,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
15421555
# actually raised.
15431556
return cbook._ExceptionInfo(ValueError, "No valid font could be found")
15441557

1545-
return _cached_realpath(result)
1558+
return FontPath(_cached_realpath(result), best_font.index)
15461559

15471560

15481561
@_api.deprecated("3.11")
@@ -1618,8 +1631,9 @@ def get_font(font_filepaths, hinting_factor=None):
16181631
16191632
Parameters
16201633
----------
1621-
font_filepaths : Iterable[str, Path, bytes, tuple[str | Path | bytes, int]], \
1622-
str, Path, bytes, tuple[str | Path | bytes, int]
1634+
font_filepaths : Iterable[str, Path, bytes, FontPath, \
1635+
tuple[str | Path | bytes, int, FontPath]], \
1636+
str, Path, bytes, FontPath, tuple[str | Path | bytes, int]
16231637
Relative or absolute paths to the font files to be used.
16241638
16251639
If a single string, bytes, or `pathlib.Path`, then it will be treated
@@ -1635,14 +1649,17 @@ def get_font(font_filepaths, hinting_factor=None):
16351649
16361650
"""
16371651
match font_filepaths:
1652+
case FontPath(path, index):
1653+
paths = ((_cached_realpath(path), index), )
16381654
case str() | Path() | bytes() as path:
16391655
paths = ((_cached_realpath(path), 0), )
16401656
case (str() | Path() | bytes() as path, int() as index):
16411657
paths = ((_cached_realpath(path), index), )
16421658
case _:
16431659
paths = tuple(
16441660
(_cached_realpath(fname[0]), fname[1]) if isinstance(fname, tuple)
1645-
else (_cached_realpath(fname), 0)
1661+
else (_cached_realpath(fname.path), fname.face_index)
1662+
if isinstance(fname, FontPath) else (_cached_realpath(fname), 0)
16461663
for fname in font_filepaths)
16471664

16481665
hinting_factor = mpl._val_or_rc(hinting_factor, 'text.hinting_factor')

lib/matplotlib/font_manager.pyi

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ def _get_fontconfig_fonts() -> list[Path]: ...
2828
def findSystemFonts(
2929
fontpaths: Iterable[str | os.PathLike | Path] | None = ..., fontext: str = ...
3030
) -> list[str]: ...
31+
32+
class FontPath(str):
33+
face_index: int
34+
def __new__(cls: type[str], path: str, face_index: int) -> FontPath: ...
35+
@property
36+
def path(self) -> str: ...
37+
3138
@dataclass
3239
class FontEntry:
3340
fname: str = ...
@@ -118,12 +125,12 @@ class FontManager:
118125
directory: str | None = ...,
119126
fallback_to_default: bool = ...,
120127
rebuild_if_missing: bool = ...,
121-
) -> str: ...
128+
) -> FontPath: ...
122129
def get_font_names(self) -> list[str]: ...
123130

124131
def is_opentype_cff_font(filename: str) -> bool: ...
125132
def get_font(
126-
font_filepaths: Iterable[str | Path | bytes | FontFace] | str | Path | bytes | FontFace,
133+
font_filepaths: Iterable[str | Path | bytes | FontFace | FontPath] | str | Path | bytes | FontFace | FontPath,
127134
hinting_factor: int | None = ...,
128135
) -> ft2font.FT2Font: ...
129136

lib/matplotlib/tests/test_font_manager.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,12 @@ def test_find_ttc():
122122
pytest.skip("Font wqy-zenhei.ttc may be missing")
123123
# All fonts from this collection should have loaded as well.
124124
for name in ["WenQuanYi Zen Hei Mono", "WenQuanYi Zen Hei Sharp"]:
125-
assert findfont(FontProperties(family=[name]),
126-
fallback_to_default=False) == fontpath
125+
subfontpath = findfont(FontProperties(family=[name]), fallback_to_default=False)
126+
assert subfontpath.path == fontpath.path
127+
assert subfontpath.face_index != fontpath.face_index
128+
subfont = get_font(subfontpath)
129+
assert subfont.fname == subfontpath.path
130+
assert subfont.face_index == subfontpath.face_index
127131
fig, ax = plt.subplots()
128132
ax.text(.5, .5, "\N{KANGXI RADICAL DRAGON}", fontproperties=fp)
129133
for fmt in ["raw", "svg", "pdf", "ps"]:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy