From 9a7c2d8052f792056e412c05ee7eeba9708dd861 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 25 Jul 2025 01:20:05 -0400 Subject: [PATCH 1/6] Add os.PathLike support to FT2Font constructor, and FontManager Since we pass the filename to `io.open`, we can accept everything it can. Also, fix the return value of `FT2Font.fname`, which could be `bytes` if that was initially provided. --- lib/matplotlib/font_manager.py | 6 ++--- lib/matplotlib/font_manager.pyi | 14 +++++----- lib/matplotlib/ft2font.pyi | 5 ++-- lib/matplotlib/tests/test_font_manager.py | 33 ++++++++++++++++++----- lib/matplotlib/tests/test_ft2font.py | 22 +++++++++++++++ src/ft2font_wrapper.cpp | 13 +++++---- 6 files changed, 70 insertions(+), 23 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 79e088b85998..47339d4491dd 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1611,10 +1611,10 @@ def get_font(font_filepaths, hinting_factor=None): Parameters ---------- - font_filepaths : Iterable[str, Path, bytes], str, Path, bytes + font_filepaths : Iterable[str, bytes, os.PathLike], str, bytes, os.PathLike Relative or absolute paths to the font files to be used. - If a single string, bytes, or `pathlib.Path`, then it will be treated + If a single string, bytes, or `os.PathLike`, then it will be treated as a list with that entry only. If more than one filepath is passed, then the returned FT2Font object @@ -1626,7 +1626,7 @@ def get_font(font_filepaths, hinting_factor=None): `.ft2font.FT2Font` """ - if isinstance(font_filepaths, (str, Path, bytes)): + if isinstance(font_filepaths, (str, bytes, os.PathLike)): paths = (_cached_realpath(font_filepaths),) else: paths = tuple(_cached_realpath(fname) for fname in font_filepaths) diff --git a/lib/matplotlib/font_manager.pyi b/lib/matplotlib/font_manager.pyi index e865f67384cd..f5e3910e5f63 100644 --- a/lib/matplotlib/font_manager.pyi +++ b/lib/matplotlib/font_manager.pyi @@ -24,7 +24,7 @@ def list_fonts(directory: str, extensions: Iterable[str]) -> list[str]: ... def win32FontDirectory() -> str: ... def _get_fontconfig_fonts() -> list[Path]: ... def findSystemFonts( - fontpaths: Iterable[str | os.PathLike | Path] | None = ..., fontext: str = ... + fontpaths: Iterable[str | os.PathLike] | None = ..., fontext: str = ... ) -> list[str]: ... @dataclass class FontEntry: @@ -50,7 +50,7 @@ class FontProperties: weight: int | str | None = ..., stretch: int | str | None = ..., size: float | str | None = ..., - fname: str | os.PathLike | Path | None = ..., + fname: str | os.PathLike | None = ..., math_fontfamily: str | None = ..., ) -> None: ... def __hash__(self) -> int: ... @@ -72,7 +72,7 @@ class FontProperties: def set_weight(self, weight: int | str | None) -> None: ... def set_stretch(self, stretch: int | str | None) -> None: ... def set_size(self, size: float | str | None) -> None: ... - def set_file(self, file: str | os.PathLike | Path | None) -> None: ... + def set_file(self, file: str | os.PathLike | None) -> None: ... def set_fontconfig_pattern(self, pattern: str) -> None: ... def get_math_fontfamily(self) -> str: ... def set_math_fontfamily(self, fontfamily: str | None) -> None: ... @@ -83,8 +83,8 @@ class FontProperties: set_slant = set_style get_size_in_points = get_size -def json_dump(data: FontManager, filename: str | Path | os.PathLike) -> None: ... -def json_load(filename: str | Path | os.PathLike) -> FontManager: ... +def json_dump(data: FontManager, filename: str | os.PathLike) -> None: ... +def json_load(filename: str | os.PathLike) -> FontManager: ... class FontManager: __version__: str @@ -93,7 +93,7 @@ class FontManager: afmlist: list[FontEntry] ttflist: list[FontEntry] def __init__(self, size: float | None = ..., weight: str = ...) -> None: ... - def addfont(self, path: str | Path | os.PathLike) -> None: ... + def addfont(self, path: str | os.PathLike) -> None: ... @property def defaultFont(self) -> dict[str, str]: ... def get_default_weight(self) -> str: ... @@ -120,7 +120,7 @@ class FontManager: def is_opentype_cff_font(filename: str) -> bool: ... def get_font( - font_filepaths: Iterable[str | Path | bytes] | str | Path | bytes, + font_filepaths: Iterable[str | bytes | os.PathLike] | str | bytes | os.PathLike, hinting_factor: int | None = ..., ) -> ft2font.FT2Font: ... diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 5257893b380a..997d041c619a 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -1,4 +1,5 @@ from enum import Enum, Flag +from os import PathLike import sys from typing import BinaryIO, Literal, TypedDict, final, overload, cast from typing_extensions import Buffer # < Py 3.12 @@ -187,7 +188,7 @@ class _SfntPcltDict(TypedDict): class FT2Font(Buffer): def __init__( self, - filename: str | BinaryIO, + filename: str | bytes | PathLike | BinaryIO, hinting_factor: int = ..., *, _fallback_list: list[FT2Font] | None = ..., @@ -249,7 +250,7 @@ class FT2Font(Buffer): @property def family_name(self) -> str: ... @property - def fname(self) -> str: ... + def fname(self) -> str | bytes: ... @property def height(self) -> int: ... @property diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index b15647644e04..d51eb8d9837f 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -1,4 +1,4 @@ -from io import BytesIO, StringIO +from io import BytesIO import gc import multiprocessing import os @@ -137,6 +137,32 @@ def test_find_noto(): fig.savefig(BytesIO(), format=fmt) +def test_find_valid(): + class PathLikeClass: + def __init__(self, filename): + self.filename = filename + + def __fspath__(self): + return self.filename + + file_str = findfont('DejaVu Sans') + file_bytes = os.fsencode(file_str) + + font = get_font(file_str) + assert font.fname == file_str + font = get_font(file_bytes) + assert font.fname == file_bytes + font = get_font(PathLikeClass(file_str)) + assert font.fname == file_str + font = get_font(PathLikeClass(file_bytes)) + assert font.fname == file_bytes + + # Note, fallbacks are not currently accessible. + font = get_font([file_str, file_bytes, + PathLikeClass(file_str), PathLikeClass(file_bytes)]) + assert font.fname == file_str + + def test_find_invalid(tmp_path): with pytest.raises(FileNotFoundError): @@ -148,11 +174,6 @@ def test_find_invalid(tmp_path): with pytest.raises(FileNotFoundError): get_font(bytes(tmp_path / 'non-existent-font-name.ttf')) - # Not really public, but get_font doesn't expose non-filename constructor. - from matplotlib.ft2font import FT2Font - with pytest.raises(TypeError, match='font file or a binary-mode file'): - FT2Font(StringIO()) # type: ignore[arg-type] - @pytest.mark.skipif(sys.platform != 'linux' or not has_fclist, reason='only Linux with fontconfig installed') diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 5dd96ce9cafe..80630d35e07b 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -1,5 +1,6 @@ import itertools import io +import os from pathlib import Path import numpy as np @@ -133,6 +134,27 @@ def test_ft2font_stix_bold_attrs(): assert font.bbox == (4, -355, 1185, 2095) +def test_ft2font_valid_args(): + class PathLikeClass: + def __init__(self, filename): + self.filename = filename + + def __fspath__(self): + return self.filename + + file_str = fm.findfont('DejaVu Sans') + file_bytes = os.fsencode(file_str) + + font = ft2font.FT2Font(file_str) + assert font.fname == file_str + font = ft2font.FT2Font(file_bytes) + assert font.fname == file_bytes + font = ft2font.FT2Font(PathLikeClass(file_str)) + assert font.fname == file_str + font = ft2font.FT2Font(PathLikeClass(file_bytes)) + assert font.fname == file_bytes + + def test_ft2font_invalid_args(tmp_path): # filename argument. with pytest.raises(TypeError, match='to a font file or a binary-mode file object'): diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 5ba4bec36874..8df990752234 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -420,7 +420,7 @@ ft_glyph_warn(FT_ULong charcode, std::set family_names) const char *PyFT2Font_init__doc__ = R"""( Parameters ---------- - filename : str or file-like + filename : str, bytes, os.PathLike, or io.BinaryIO The source of the font data in a format (ttf or ttc) that FreeType can read. hinting_factor : int, optional @@ -481,7 +481,10 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, } } - if (py::isinstance(filename) || py::isinstance(filename)) { + auto PathLike = py::module_::import("os").attr("PathLike"); + if (py::isinstance(filename) || py::isinstance(filename) || + py::isinstance(filename, PathLike)) + { self->py_file = py::module_::import("io").attr("open")(filename, "rb"); self->stream.close = &close_file_callback; } else { @@ -507,13 +510,13 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, return self; } -static py::str +static py::object PyFT2Font_fname(PyFT2Font *self) { - if (self->stream.close) { // Called passed a filename to the constructor. + if (self->stream.close) { // User passed a filename to the constructor. return self->py_file.attr("name"); } else { - return py::cast(self->py_file); + return self->py_file; } } From c352088b98cf28d14be7edfe019e4661757f3f5b Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 18 Jul 2025 03:50:41 -0400 Subject: [PATCH 2/6] Expose face index when loading fonts This enables loading a non-initial font from collections (`.ttc` files). Currently exposed for `FT2Font`, only. --- lib/matplotlib/ft2font.pyi | 3 +++ lib/matplotlib/tests/test_ft2font.py | 18 ++++++++++++++++++ src/ft2font.cpp | 5 ++--- src/ft2font.h | 2 +- src/ft2font_wrapper.cpp | 21 ++++++++++++++++----- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 997d041c619a..eea180e4c7b5 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -191,6 +191,7 @@ class FT2Font(Buffer): filename: str | bytes | PathLike | BinaryIO, hinting_factor: int = ..., *, + face_index: int = ..., _fallback_list: list[FT2Font] | None = ..., _kerning_factor: int | None = ... ) -> None: ... @@ -248,6 +249,8 @@ class FT2Font(Buffer): @property def face_flags(self) -> FaceFlags: ... @property + def face_index(self) -> int: ... + @property def family_name(self) -> str: ... @property def fname(self) -> str | bytes: ... diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 80630d35e07b..7ffc83f75e75 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -198,6 +198,24 @@ def test_ft2font_invalid_args(tmp_path): ft2font.FT2Font(file, _kerning_factor=123) +@pytest.mark.parametrize('name, size, skippable', + [('DejaVu Sans', 1, False), ('WenQuanYi Zen Hei', 3, True)]) +def test_ft2font_face_index(name, size, skippable): + try: + file = fm.findfont(name, fallback_to_default=False) + except ValueError: + if skippable: + pytest.skip(r'Font {name} may be missing') + raise + for index in range(size): + font = ft2font.FT2Font(file, face_index=index) + assert font.num_faces >= size + with pytest.raises(ValueError, match='must be between'): # out of bounds for spec + ft2font.FT2Font(file, face_index=0x1ffff) + with pytest.raises(RuntimeError, match='invalid argument'): # invalid for this font + ft2font.FT2Font(file, face_index=0xff) + + def test_ft2font_clear(): file = fm.findfont('DejaVu Sans') font = ft2font.FT2Font(file) diff --git a/src/ft2font.cpp b/src/ft2font.cpp index 1d03ecf10b56..24d965331228 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -207,8 +207,7 @@ FT2Font::get_path(std::vector &vertices, std::vector &cod codes.push_back(CLOSEPOLY); } -FT2Font::FT2Font(FT_Open_Args &open_args, - long hinting_factor_, +FT2Font::FT2Font(FT_Long face_index, FT_Open_Args &open_args, long hinting_factor_, std::vector &fallback_list, FT2Font::WarnFunc warn, bool warn_if_used) : ft_glyph_warn(warn), warn_if_used(warn_if_used), image({1, 1}), face(nullptr), @@ -217,7 +216,7 @@ FT2Font::FT2Font(FT_Open_Args &open_args, kerning_factor(0) { clear(); - FT_CHECK(FT_Open_Face, _ft2Library, &open_args, 0, &face); + FT_CHECK(FT_Open_Face, _ft2Library, &open_args, face_index, &face); if (open_args.stream != nullptr) { face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; } diff --git a/src/ft2font.h b/src/ft2font.h index 0881693e7557..161dc8b8938c 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -99,7 +99,7 @@ class FT2Font typedef void (*WarnFunc)(FT_ULong charcode, std::set family_names); public: - FT2Font(FT_Open_Args &open_args, long hinting_factor, + FT2Font(FT_Long face_index, FT_Open_Args &open_args, long hinting_factor, std::vector &fallback_list, WarnFunc warn, bool warn_if_used); virtual ~FT2Font(); diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 8df990752234..d8c965c5d31b 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -426,6 +426,9 @@ const char *PyFT2Font_init__doc__ = R"""( hinting_factor : int, optional Must be positive. Used to scale the hinting in the x-direction. + face_index : int, optional + The index of the face in the font file to load. + _fallback_list : list of FT2Font, optional A list of FT2Font objects used to find missing glyphs. @@ -440,7 +443,7 @@ const char *PyFT2Font_init__doc__ = R"""( )"""; static PyFT2Font * -PyFT2Font_init(py::object filename, long hinting_factor = 8, +PyFT2Font_init(py::object filename, long hinting_factor = 8, FT_Long face_index = 0, std::optional> fallback_list = std::nullopt, std::optional kerning_factor = std::nullopt, bool warn_if_used = false) @@ -456,6 +459,10 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, kerning_factor = 0; } + if (face_index < 0 || face_index >= 1<<16) { + throw std::range_error("face_index must be between 0 and 65535, inclusive"); + } + PyFT2Font *self = new PyFT2Font(); self->x = nullptr; memset(&self->stream, 0, sizeof(FT_StreamRec)); @@ -502,8 +509,8 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, self->stream.close = nullptr; } - self->x = new FT2Font(open_args, hinting_factor, fallback_fonts, ft_glyph_warn, - warn_if_used); + self->x = new FT2Font(face_index, open_args, hinting_factor, fallback_fonts, + ft_glyph_warn, warn_if_used); self->x->set_kerning_factor(*kerning_factor); @@ -1609,7 +1616,7 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) auto cls = py::class_(m, "FT2Font", py::is_final(), py::buffer_protocol(), PyFT2Font__doc__) .def(py::init(&PyFT2Font_init), - "filename"_a, "hinting_factor"_a=8, py::kw_only(), + "filename"_a, "hinting_factor"_a=8, py::kw_only(), "face_index"_a=0, "_fallback_list"_a=py::none(), "_kerning_factor"_a=py::none(), "_warn_if_used"_a=false, PyFT2Font_init__doc__) @@ -1682,8 +1689,12 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) }, "PostScript name of the font.") .def_property_readonly( "num_faces", [](PyFT2Font *self) { - return self->x->get_face()->num_faces; + return self->x->get_face()->num_faces & 0xffff; }, "Number of faces in file.") + .def_property_readonly( + "face_index", [](PyFT2Font *self) { + return self->x->get_face()->face_index; + }, "The index of the font in the file.") .def_property_readonly( "family_name", [](PyFT2Font *self) { if (const char *name = self->x->get_face()->family_name) { From 24c1576c6944cc6d0e9cde6a1565a197afd4d139 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 18 Jul 2025 04:51:05 -0400 Subject: [PATCH 3/6] Parse data from all fonts within a collection This should allow listing the metadata from the whole collection, which will also pick the right one if specified, though it will not load the specific index yet. --- lib/matplotlib/font_manager.py | 12 +++++++++--- lib/matplotlib/font_manager.pyi | 1 + lib/matplotlib/tests/test_font_manager.py | 11 ++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 47339d4491dd..e9aac793ce4c 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -319,6 +319,7 @@ class FontEntry: """ fname: str = '' + index: int = 0 name: str = '' style: str = 'normal' variant: str = 'normal' @@ -465,7 +466,8 @@ def get_weight(): # From fontconfig's FcFreeTypeQueryFaceInternal. raise NotImplementedError("Non-scalable fonts are not supported") size = 'scalable' - return FontEntry(font.fname, name, style, variant, weight, stretch, size) + return FontEntry(font.fname, font.face_index, name, + style, variant, weight, stretch, size) def afmFontProperty(fontpath, font): @@ -535,7 +537,7 @@ def afmFontProperty(fontpath, font): size = 'scalable' - return FontEntry(fontpath, name, style, variant, weight, stretch, size) + return FontEntry(fontpath, 0, name, style, variant, weight, stretch, size) def _cleanup_fontproperties_init(init_method): @@ -1069,7 +1071,7 @@ class FontManager: # Increment this version number whenever the font cache data # format or behavior has changed and requires an existing font # cache files to be rebuilt. - __version__ = '3.11.0a1' + __version__ = '3.11.0a2' def __init__(self, size=None, weight='normal'): self._version = self.__version__ @@ -1134,6 +1136,10 @@ def addfont(self, path): font = ft2font.FT2Font(path) prop = ttfFontProperty(font) self.ttflist.append(prop) + for face_index in range(1, font.num_faces): + subfont = ft2font.FT2Font(path, face_index=face_index) + prop = ttfFontProperty(subfont) + self.ttflist.append(prop) self._findfont_cached.cache_clear() @property diff --git a/lib/matplotlib/font_manager.pyi b/lib/matplotlib/font_manager.pyi index f5e3910e5f63..6b072f707f66 100644 --- a/lib/matplotlib/font_manager.pyi +++ b/lib/matplotlib/font_manager.pyi @@ -29,6 +29,7 @@ def findSystemFonts( @dataclass class FontEntry: fname: str = ... + index: int = ... name: str = ... style: str = ... variant: str = ... diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index d51eb8d9837f..6301163b4527 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -117,8 +117,13 @@ def test_utf16m_sfnt(): def test_find_ttc(): fp = FontProperties(family=["WenQuanYi Zen Hei"]) - if Path(findfont(fp)).name != "wqy-zenhei.ttc": + fontpath = findfont(fp) + if Path(fontpath).name != "wqy-zenhei.ttc": pytest.skip("Font wqy-zenhei.ttc may be missing") + # All fonts from this collection should have loaded as well. + for name in ["WenQuanYi Zen Hei Mono", "WenQuanYi Zen Hei Sharp"]: + assert findfont(FontProperties(family=[name]), + fallback_to_default=False) == fontpath fig, ax = plt.subplots() ax.text(.5, .5, "\N{KANGXI RADICAL DRAGON}", fontproperties=fp) for fmt in ["raw", "svg", "pdf", "ps"]: @@ -363,6 +368,10 @@ def test_get_font_names(): font = ft2font.FT2Font(path) prop = ttfFontProperty(font) ttf_fonts.append(prop.name) + for face_index in range(1, font.num_faces): + font = ft2font.FT2Font(path, face_index=face_index) + prop = ttfFontProperty(font) + ttf_fonts.append(prop.name) except Exception: pass available_fonts = sorted(list(set(ttf_fonts))) From 1f2b3309a9981dbb02e770757f985b83424a65db Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 25 Jul 2025 03:33:54 -0400 Subject: [PATCH 4/6] Implement loading of any font in a collection For backwards-compatibility, the path+index is passed around in a lightweight subclass of `str`. --- lib/matplotlib/font_manager.py | 89 +++++++++++++++++++---- lib/matplotlib/font_manager.pyi | 19 ++++- lib/matplotlib/tests/test_font_manager.py | 44 ++++++++++- 3 files changed, 133 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index e9aac793ce4c..6810fa8a8930 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -310,6 +310,61 @@ def findSystemFonts(fontpaths=None, fontext='ttf'): return [fname for fname in fontfiles if os.path.exists(fname)] +class FontPath(str): + """ + A class to describe a path to a font with a face index. + + Parameters + ---------- + path : str + The path to a font. + face_index : int + The face index in the font. + """ + + __match_args__ = ('path', 'face_index') + + def __new__(cls, path, face_index): + ret = super().__new__(cls, path) + ret._face_index = face_index + return ret + + @property + def path(self): + """The path to a font.""" + return str(self) + + @property + def face_index(self): + """The face index in a font.""" + return self._face_index + + def _as_tuple(self): + return (self.path, self.face_index) + + def __eq__(self, other): + if isinstance(other, FontPath): + return self._as_tuple() == other._as_tuple() + return super().__eq__(other) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + if isinstance(other, FontPath): + return self._as_tuple() < other._as_tuple() + return super().__lt__(other) + + def __gt__(self, other): + return not (self == other or self < other) + + def __hash__(self): + return hash(self._as_tuple()) + + def __repr__(self): + return f'FontPath{self._as_tuple()}' + + @dataclasses.dataclass(frozen=True) class FontEntry: """ @@ -1326,7 +1381,7 @@ def findfont(self, prop, fontext='ttf', directory=None, Returns ------- - str + FontPath The filename of the best matching font. Notes @@ -1396,7 +1451,7 @@ def _find_fonts_by_props(self, prop, fontext='ttf', directory=None, Returns ------- - list[str] + list[FontPath] The paths of the fonts found. Notes @@ -1542,7 +1597,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default, # actually raised. return cbook._ExceptionInfo(ValueError, "No valid font could be found") - return _cached_realpath(result) + return FontPath(_cached_realpath(result), best_font.index) @_api.deprecated("3.11") @@ -1562,15 +1617,16 @@ def is_opentype_cff_font(filename): @lru_cache(64) def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id, enable_last_resort): - first_fontpath, *rest = font_filepaths + (first_fontpath, first_fontindex), *rest = font_filepaths fallback_list = [ - ft2font.FT2Font(fpath, hinting_factor, _kerning_factor=_kerning_factor) - for fpath in rest + ft2font.FT2Font(fpath, hinting_factor, face_index=index, + _kerning_factor=_kerning_factor) + for fpath, index in rest ] last_resort_path = _cached_realpath( cbook._get_data_path('fonts', 'ttf', 'LastResortHE-Regular.ttf')) try: - last_resort_index = font_filepaths.index(last_resort_path) + last_resort_index = font_filepaths.index((last_resort_path, 0)) except ValueError: last_resort_index = -1 # Add Last Resort font so we always have glyphs regardless of font, unless we're @@ -1582,7 +1638,7 @@ def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id, _warn_if_used=True)) last_resort_index = len(fallback_list) font = ft2font.FT2Font( - first_fontpath, hinting_factor, + first_fontpath, hinting_factor, face_index=first_fontindex, _fallback_list=fallback_list, _kerning_factor=_kerning_factor ) @@ -1617,7 +1673,8 @@ def get_font(font_filepaths, hinting_factor=None): Parameters ---------- - font_filepaths : Iterable[str, bytes, os.PathLike], str, bytes, os.PathLike + font_filepaths : Iterable[str, bytes, os.PathLike, FontPath], \ +str, bytes, os.PathLike, FontPath Relative or absolute paths to the font files to be used. If a single string, bytes, or `os.PathLike`, then it will be treated @@ -1632,10 +1689,16 @@ def get_font(font_filepaths, hinting_factor=None): `.ft2font.FT2Font` """ - if isinstance(font_filepaths, (str, bytes, os.PathLike)): - paths = (_cached_realpath(font_filepaths),) - else: - paths = tuple(_cached_realpath(fname) for fname in font_filepaths) + match font_filepaths: + case FontPath(path, index): + paths = ((_cached_realpath(path), index), ) + case str() | bytes() | os.PathLike() as path: + paths = ((_cached_realpath(path), 0), ) + case _: + paths = tuple( + (_cached_realpath(fname.path), fname.face_index) + if isinstance(fname, FontPath) else (_cached_realpath(fname), 0) + for fname in font_filepaths) hinting_factor = mpl._val_or_rc(hinting_factor, 'text.hinting_factor') diff --git a/lib/matplotlib/font_manager.pyi b/lib/matplotlib/font_manager.pyi index 6b072f707f66..47ee194c671a 100644 --- a/lib/matplotlib/font_manager.pyi +++ b/lib/matplotlib/font_manager.pyi @@ -3,7 +3,7 @@ from dataclasses import dataclass from numbers import Integral import os from pathlib import Path -from typing import Any, Literal +from typing import Any, Final, Literal from matplotlib._afm import AFM from matplotlib import ft2font @@ -26,6 +26,19 @@ def _get_fontconfig_fonts() -> list[Path]: ... def findSystemFonts( fontpaths: Iterable[str | os.PathLike] | None = ..., fontext: str = ... ) -> list[str]: ... + +class FontPath(str): + __match_args__: Final[tuple[str, ...]] + def __new__(cls: type[str], path: str, face_index: int) -> FontPath: ... + @property + def path(self) -> str: ... + @property + def face_index(self) -> int: ... + def _as_tuple(self) -> tuple[str, int]: ... + def __eq__(self, other: Any) -> bool: ... + def __hash__(self) -> int: ... + def __repr__(self) -> str: ... + @dataclass class FontEntry: fname: str = ... @@ -116,12 +129,12 @@ class FontManager: directory: str | None = ..., fallback_to_default: bool = ..., rebuild_if_missing: bool = ..., - ) -> str: ... + ) -> FontPath: ... def get_font_names(self) -> list[str]: ... def is_opentype_cff_font(filename: str) -> bool: ... def get_font( - font_filepaths: Iterable[str | bytes | os.PathLike] | str | bytes | os.PathLike, + font_filepaths: Iterable[str | bytes | os.PathLike | FontPath] | str | bytes | os.PathLike | FontPath, hinting_factor: int | None = ..., ) -> ft2font.FT2Font: ... diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index 6301163b4527..cc8ae03a9f97 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -13,7 +13,7 @@ import matplotlib as mpl from matplotlib.font_manager import ( - findfont, findSystemFonts, FontEntry, FontProperties, fontManager, + findfont, findSystemFonts, FontEntry, FontPath, FontProperties, fontManager, json_dump, json_load, get_font, is_opentype_cff_font, MSUserFontDirectories, ttfFontProperty, _get_fontconfig_fonts, _normalize_weight) @@ -24,6 +24,38 @@ has_fclist = shutil.which('fc-list') is not None +def test_font_path(): + fp = FontPath('foo', 123) + fp2 = FontPath('foo', 321) + assert str(fp) == 'foo' + assert repr(fp) == "FontPath('foo', 123)" + assert fp.path == 'foo' + assert fp.face_index == 123 + # Should be immutable. + with pytest.raises(AttributeError, match='has no setter'): + fp.path = 'bar' + with pytest.raises(AttributeError, match='has no setter'): + fp.face_index = 321 + # Should be comparable with str and itself. + assert fp == 'foo' + assert fp == FontPath('foo', 123) + assert fp <= fp + assert fp >= fp + assert fp != fp2 + assert fp < fp2 + assert fp <= fp2 + assert fp2 > fp + assert fp2 >= fp + # Should be hashable, but not the same as str. + d = {fp: 1, 'bar': 2} + assert fp in d + assert d[fp] == 1 + assert d[FontPath('foo', 123)] == 1 + assert fp2 not in d + assert 'foo' not in d + assert FontPath('bar', 0) not in d + + def test_font_priority(): with rc_context(rc={ 'font.sans-serif': @@ -122,8 +154,12 @@ def test_find_ttc(): pytest.skip("Font wqy-zenhei.ttc may be missing") # All fonts from this collection should have loaded as well. for name in ["WenQuanYi Zen Hei Mono", "WenQuanYi Zen Hei Sharp"]: - assert findfont(FontProperties(family=[name]), - fallback_to_default=False) == fontpath + subfontpath = findfont(FontProperties(family=[name]), fallback_to_default=False) + assert subfontpath.path == fontpath.path + assert subfontpath.face_index != fontpath.face_index + subfont = get_font(subfontpath) + assert subfont.fname == subfontpath.path + assert subfont.face_index == subfontpath.face_index fig, ax = plt.subplots() ax.text(.5, .5, "\N{KANGXI RADICAL DRAGON}", fontproperties=fp) for fmt in ["raw", "svg", "pdf", "ps"]: @@ -161,6 +197,8 @@ def __fspath__(self): assert font.fname == file_str font = get_font(PathLikeClass(file_bytes)) assert font.fname == file_bytes + font = get_font(FontPath(file_str, 0)) + assert font.fname == file_str # Note, fallbacks are not currently accessible. font = get_font([file_str, file_bytes, From 1bc92f0df6ad9cced8bf62b8aefc90ee2e8719f4 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 25 Jul 2025 06:13:59 -0400 Subject: [PATCH 5/6] pdf/ps: Support any font in a collection --- lib/matplotlib/backends/_backend_pdf_ps.py | 11 +- lib/matplotlib/backends/backend_pdf.py | 33 +- lib/matplotlib/backends/backend_ps.py | 14 +- lib/matplotlib/dviread.py | 4 + lib/matplotlib/dviread.pyi | 2 + .../test_backend_pdf/ttc_type3.pdf | Bin 0 -> 21114 bytes .../test_backend_pdf/ttc_type42.pdf | Bin 0 -> 9696 bytes .../test_backend_ps/ttc_type3.eps | 1483 +++++++++++++++++ .../test_backend_ps/ttc_type42.eps | 1483 +++++++++++++++++ lib/matplotlib/tests/test_backend_pdf.py | 35 +- lib/matplotlib/tests/test_backend_ps.py | 36 +- 11 files changed, 3071 insertions(+), 30 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps create mode 100644 lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps diff --git a/lib/matplotlib/backends/_backend_pdf_ps.py b/lib/matplotlib/backends/_backend_pdf_ps.py index a2a878d54156..6e0a348c3d88 100644 --- a/lib/matplotlib/backends/_backend_pdf_ps.py +++ b/lib/matplotlib/backends/_backend_pdf_ps.py @@ -28,7 +28,7 @@ def get_glyphs_subset(fontfile, characters): Parameters ---------- - fontfile : str + fontfile : FontPath Path to the font file characters : str Continuous set of characters to include in subset @@ -66,8 +66,7 @@ def get_glyphs_subset(fontfile, characters): 'xref', # The cross-reference table (some Apple font tooling information). ] # if fontfile is a ttc, specify font number - if fontfile.endswith(".ttc"): - options.font_number = 0 + options.font_number = fontfile.face_index font = subset.load_font(fontfile, options) subsetter = subset.Subsetter(options=options) @@ -110,11 +109,13 @@ def track(self, font, s): """Record that string *s* is being typeset using font *font*.""" char_to_font = font._get_fontmap(s) for _c, _f in char_to_font.items(): - self.used.setdefault(_f.fname, set()).add(ord(_c)) + font_path = font_manager.FontPath(_f.fname, _f.face_index) + self.used.setdefault(font_path, set()).add(ord(_c)) def track_glyph(self, font, glyph): """Record that codepoint *glyph* is being typeset using font *font*.""" - self.used.setdefault(font.fname, set()).add(glyph) + font_path = font_manager.FontPath(font.fname, font.face_index) + self.used.setdefault(font_path, set()).add(glyph) class RendererPDFPSBase(RendererBase): diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index ff351e301176..2e1054e887f2 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -33,7 +33,7 @@ RendererBase) from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.figure import Figure -from matplotlib.font_manager import get_font, fontManager as _fontManager +from matplotlib.font_manager import FontPath, get_font, fontManager as _fontManager from matplotlib._afm import AFM from matplotlib.ft2font import FT2Font, FaceFlags, Kerning, LoadFlags, StyleFlags from matplotlib.transforms import Affine2D, BboxBase @@ -910,8 +910,10 @@ def fontName(self, fontprop): as the filename of the font. """ - if isinstance(fontprop, str): + if isinstance(fontprop, FontPath): filenames = [fontprop] + elif isinstance(fontprop, str): + filenames = [FontPath(fontprop, 0)] elif mpl.rcParams['pdf.use14corefonts']: filenames = _fontManager._find_fonts_by_props( fontprop, fontext='afm', directory=RendererPdf._afm_font_dir @@ -950,9 +952,8 @@ def writeFonts(self): for pdfname, dvifont in sorted(self._dviFontInfo.items()): _log.debug('Embedding Type-1 font %s from dvi.', dvifont.texname) fonts[pdfname] = self._embedTeXFont(dvifont) - for filename in sorted(self._fontNames): - Fx = self._fontNames[filename] - _log.debug('Embedding font %s.', filename) + for filename, Fx in sorted(self._fontNames.items()): + _log.debug('Embedding font %r.', filename) if filename.endswith('.afm'): # from pdf.use14corefonts _log.debug('Writing AFM font.') @@ -1004,7 +1005,8 @@ def _embedTeXFont(self, dvifont): # Reduce the font to only the glyphs used in the document, get the encoding # for that subset, and compute various properties based on the encoding. - chars = frozenset(self._character_tracker.used[dvifont.fname]) + font_path = FontPath(dvifont.fname, dvifont.face_index) + chars = frozenset(self._character_tracker.used[font_path]) t1font = t1font.subset(chars, self._get_subset_prefix(chars)) fontdict['BaseFont'] = Name(t1font.prop['FontName']) # createType1Descriptor writes the font data as a side effect @@ -1113,6 +1115,7 @@ def _get_xobject_glyph_name(self, filename, glyph_name): return "-".join([ Fx.name.decode(), os.path.splitext(os.path.basename(filename))[0], + str(filename.face_index), glyph_name]) _identityToUnicodeCMap = b"""/CIDInit /ProcSet findresource begin @@ -1270,11 +1273,11 @@ def embedTTFType42(font, characters, descriptor): toUnicodeMapObject = self.reserveObject('ToUnicode map') subset_str = "".join(chr(c) for c in characters) - _log.debug("SUBSET %s characters: %s", filename, subset_str) + _log.debug("SUBSET %r characters: %s", filename, subset_str) with _backend_pdf_ps.get_glyphs_subset(filename, subset_str) as subset: fontdata = _backend_pdf_ps.font_as_file(subset) _log.debug( - "SUBSET %s %d -> %d", filename, + "SUBSET %r %d -> %d", filename, os.stat(filename).st_size, fontdata.getbuffer().nbytes ) @@ -2218,7 +2221,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): self.file.output(Op.begin_text) for font, fontsize, num, ox, oy in glyphs: self.file._character_tracker.track_glyph(font, num) - fontname = font.fname + font_path = FontPath(font.fname, font.face_index) if not _font_supports_glyph(fonttype, num): # Unsupported chars (i.e. multibyte in Type 3 or beyond BMP in # Type 42) must be emitted separately (below). @@ -2226,10 +2229,10 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): else: self._setup_textpos(ox, oy, 0, oldx, oldy) oldx, oldy = ox, oy - if (fontname, fontsize) != prev_font: - self.file.output(self.file.fontName(fontname), fontsize, + if (font_path, fontsize) != prev_font: + self.file.output(self.file.fontName(font_path), fontsize, Op.selectfont) - prev_font = fontname, fontsize + prev_font = font_path, fontsize self.file.output(self.encode_string(chr(num), fonttype), Op.show) self.file.output(Op.end_text) @@ -2413,7 +2416,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): self.file.output(Op.begin_text) prev_start_x = 0 for ft_object, start_x, kerns_or_chars in singlebyte_chunks: - ft_name = self.file.fontName(ft_object.fname) + font_path = FontPath(ft_object.fname, ft_object.face_index) + ft_name = self.file.fontName(font_path) self.file.output(ft_name, fontsize, Op.selectfont) self._setup_textpos(start_x, 0, 0, prev_start_x, 0, 0) self.file.output( @@ -2435,7 +2439,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): def _draw_xobject_glyph(self, font, fontsize, glyph_idx, x, y): """Draw a multibyte character from a Type 3 font as an XObject.""" glyph_name = font.get_glyph_name(glyph_idx) - name = self.file._get_xobject_glyph_name(font.fname, glyph_name) + name = self.file._get_xobject_glyph_name(FontPath(font.fname, font.face_index), + glyph_name) self.file.output( Op.gsave, 0.001 * fontsize, 0, 0, 0.001 * fontsize, x, y, Op.concat_matrix, diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 368564a1518d..06c1deb8e5da 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -94,7 +94,7 @@ def _font_to_ps_type3(font_path, chars): Parameters ---------- - font_path : path-like + font_path : FontPath Path to the font to be subsetted. chars : str The characters to include in the subsetted font. @@ -175,7 +175,7 @@ def _font_to_ps_type42(font_path, chars, fh): Parameters ---------- - font_path : path-like + font_path : FontPath Path to the font to be subsetted. chars : str The characters to include in the subsetted font. @@ -183,14 +183,10 @@ def _font_to_ps_type42(font_path, chars, fh): Where to write the font. """ subset_str = ''.join(chr(c) for c in chars) - _log.debug("SUBSET %s characters: %s", font_path, subset_str) + _log.debug("SUBSET %r characters: %s", font_path, subset_str) try: - kw = {} - # fix this once we support loading more fonts from a collection - # https://github.com/matplotlib/matplotlib/issues/3135#issuecomment-571085541 - if font_path.endswith('.ttc'): - kw['fontNumber'] = 0 - with (fontTools.ttLib.TTFont(font_path, **kw) as font, + with (fontTools.ttLib.TTFont(font_path.path, + fontNumber=font_path.face_index) as font, _backend_pdf_ps.get_glyphs_subset(font_path, subset_str) as subset): fontdata = _backend_pdf_ps.font_as_file(subset).getvalue() _log.debug( diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 9e8b6a5facf5..245c19db62fb 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -610,6 +610,10 @@ def fname(self): """A fake filename""" return self.texname.decode('latin-1') + @property + def face_index(self): # For compatibility with FT2Font. + return 0 + def _get_fontmap(self, string): """Get the mapping from characters to the font that includes them. diff --git a/lib/matplotlib/dviread.pyi b/lib/matplotlib/dviread.pyi index 82c0238d39d1..fdacbe751314 100644 --- a/lib/matplotlib/dviread.pyi +++ b/lib/matplotlib/dviread.pyi @@ -68,6 +68,8 @@ class DviFont: def widths(self) -> list[int]: ... @property def fname(self) -> str: ... + @property + def face_index(self) -> int: ... class Vf(Dvi): def __init__(self, filename: str | os.PathLike) -> None: ... diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a3fad017236451b768f01358368b601991bf5cf8 GIT binary patch literal 21114 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 Ch|0hK literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d43f233ef4e6bba524f535b400d38f7fe5a45bac GIT binary patch literal 9696 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 LJG-2QJn?@4aq!mr literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps new file mode 100644 index 000000000000..e066abad29f5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps @@ -0,0 +1,1483 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: ttc_type3.eps +%%Creator: Matplotlib v3.11.0.dev1121+gba80e42970.d20250725, https://matplotlib.org/ +%%CreationDate: Fri Jul 25 06:03:10 2025 +%%Orientation: portrait +%%BoundingBox: 0 0 504 72 +%%HiResBoundingBox: 0.000000 0.000000 504.000000 72.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/sc { setcachedevice } _d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHei def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/space /colon /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /a /e /i /n /u] def +/CharStrings 34 dict dup begin +/.notdef 0 def +/space{307 0 0 0 0 0 sc +ce} _d +/colon{307 0 101 0 215 520 sc +215 404 m +101 404 l +101 520 l +215 520 l +215 404 l + +215 0 m +101 0 l +101 116 l +215 116 l +215 0 l + +ce} _d +/A{573 0 11 0 568 702 sc +568 0 m +478 0 l +408 205 l +147 205 l +85 0 l +11 0 l +239 702 l +340 702 l +568 0 l + +388 271 m +281 608 l +172 271 l +388 271 l + +ce} _d +/B{634 0 83 0 588 702 sc +588 194 m +588 130 565 80 520 45 c +484 16 434 1 370 0 c +347 0 l +83 0 l +83 702 l +348 702 l +405 702 448 694 477 679 c +482 676 487 673 493 670 c +541 637 565 591 566 531 c +566 470 542 424 494 394 c +462 380 l +456 377 449 375 442 374 c +442 372 l +501 359 543 327 568 276 c +581 251 588 224 588 194 c + +479 520 m +479 585 443 621 370 630 c +361 631 351 631 341 631 c +171 631 l +171 401 l +317 401 l +425 401 479 441 479 520 c + +500 198 m +500 241 485 276 454 303 c +453 304 451 306 449 307 c +426 325 389 334 338 334 c +171 334 l +171 75 l +343 75 l +432 75 483 105 497 166 c +499 175 500 186 500 198 c + +ce} _d +/C{634 0 43 -10 589 713 sc +589 219 m +558 90 490 16 386 -5 c +367 -8 348 -10 329 -10 c +224 -10 146 38 94 135 c +60 199 43 273 43 358 c +43 471 72 560 131 626 c +183 684 251 713 336 713 c +435 713 508 669 555 582 c +570 554 582 523 589 488 c +506 473 l +479 573 430 628 359 637 c +350 638 342 639 333 639 c +248 639 190 590 159 492 c +146 449 139 402 139 351 c +139 261 158 189 197 134 c +230 87 274 63 329 63 c +418 63 477 117 506 225 c +507 229 508 233 509 237 c +589 219 l + +ce} _d +/D{675 0 87 0 636 702 sc +636 353 m +636 247 607 160 550 93 c +496 31 425 0 338 0 c +87 0 l +87 702 l +309 702 l +394 702 462 682 512 642 c +525 631 538 618 551 603 c +608 537 636 454 636 353 c + +547 353 m +547 436 525 504 482 557 c +449 599 403 623 344 628 c +304 629 l +175 629 l +175 75 l +304 75 l +382 75 440 97 478 140 c +484 147 490 155 496 164 c +530 216 547 279 547 353 c + +ce} _d +/E{573 0 87 0 542 702 sc +542 0 m +87 0 l +87 702 l +531 702 l +531 627 l +175 627 l +175 403 l +458 403 l +458 333 l +175 333 l +175 76 l +542 76 l +542 0 l + +ce} _d +/F{491 0 84 0 514 702 sc +514 627 m +172 627 l +172 403 l +456 403 l +456 333 l +172 333 l +172 0 l +84 0 l +84 702 l +514 702 l +514 627 l + +ce} _d +/G{675 0 49 -10 614 713 sc +614 -5 m +560 -5 l +537 82 l +497 24 436 -7 355 -10 c +350 -10 346 -10 342 -10 c +237 -10 157 35 104 125 c +67 187 49 260 49 344 c +49 452 77 541 133 610 c +188 679 262 713 353 713 c +457 713 532 670 579 585 c +591 563 600 538 607 511 c +524 490 l +512 553 480 597 428 622 c +403 633 376 639 347 639 c +256 639 195 589 164 488 c +151 447 144 400 144 348 c +144 251 167 176 212 123 c +247 82 292 61 348 61 c +418 61 469 88 500 141 c +516 170 524 203 524 242 c +524 281 l +349 281 l +349 354 l +614 354 l +614 -5 l + +ce} _d +/H{675 0 83 0 585 702 sc +585 0 m +497 0 l +497 334 l +171 334 l +171 0 l +83 0 l +83 702 l +171 702 l +171 411 l +497 411 l +497 702 l +585 702 l +585 0 l + +ce} _d +/I{266 0 88 0 176 702 sc +176 0 m +88 0 l +88 702 l +176 702 l +176 0 l + +ce} _d +/J{409 0 17 -10 331 702 sc +331 229 m +331 104 290 29 207 2 c +182 -6 153 -10 120 -10 c +86 -10 52 -5 17 4 c +17 76 l +50 69 81 66 108 66 c +171 66 211 83 227 118 c +238 139 243 176 243 229 c +243 702 l +331 702 l +331 229 l + +ce} _d +/K{634 0 88 0 643 702 sc +643 0 m +546 0 l +337 387 l +176 187 l +176 0 l +88 0 l +88 702 l +176 702 l +176 295 l +493 702 l +588 702 l +398 457 l +643 0 l + +ce} _d +/L{512 0 86 0 501 702 sc +501 0 m +86 0 l +86 702 l +174 702 l +174 78 l +501 78 l +501 0 l + +ce} _d +/M{839 0 82 0 761 702 sc +761 0 m +673 0 l +673 613 l +669 613 l +446 0 l +387 0 l +160 613 l +156 613 l +156 0 l +82 0 l +82 702 l +213 702 l +425 140 l +632 702 l +761 702 l +761 0 l + +ce} _d +/N{675 0 84 0 601 702 sc +601 0 m +515 0 l +158 612 l +158 0 l +84 0 l +84 702 l +195 702 l +527 130 l +527 702 l +601 702 l +601 0 l + +ce} _d +/O{675 0 45 -10 623 713 sc +623 359 m +623 258 598 173 548 102 c +495 27 424 -10 335 -10 c +230 -10 151 36 98 128 c +63 189 45 262 45 346 c +45 453 71 540 124 609 c +176 678 246 713 334 713 c +435 713 513 669 566 580 c +604 517 623 443 623 359 c + +530 354 m +530 449 509 522 468 575 c +435 618 392 640 337 640 c +250 640 191 591 159 492 c +144 448 137 399 137 345 c +137 258 157 187 197 133 c +232 85 278 61 335 61 c +417 61 474 108 507 203 c +522 248 530 299 530 354 c + +ce} _d +/P{573 0 66 0 542 702 sc +542 492 m +542 436 523 388 485 348 c +480 343 l +441 305 385 286 311 286 c +154 286 l +154 0 l +66 0 l +66 702 l +301 702 l +376 702 433 686 470 655 c +510 622 534 575 541 515 c +542 507 542 499 542 492 c + +453 492 m +453 557 425 600 370 620 c +351 626 331 629 308 629 c +154 629 l +154 358 l +302 358 l +375 358 422 384 442 435 c +449 452 453 471 453 492 c + +ce} _d +/Q{675 0 42 -167 626 713 sc +626 351 m +626 244 599 158 546 91 c +509 46 462 16 407 1 c +407 -14 l +407 -55 425 -80 461 -88 c +468 -90 476 -91 485 -91 c +500 -91 532 -89 580 -84 c +580 -154 l +553 -163 528 -167 504 -167 c +412 -167 357 -130 340 -55 c +337 -41 335 -26 335 -10 c +224 -7 142 41 91 135 c +58 195 42 265 42 346 c +42 456 69 545 124 613 c +177 680 247 713 334 713 c +441 713 520 666 572 572 c +608 509 626 436 626 351 c + +530 349 m +530 482 496 569 428 610 c +401 627 370 635 333 635 c +234 635 172 576 147 459 c +140 424 136 386 136 344 c +136 239 160 161 207 112 c +238 79 278 62 327 62 c +425 62 488 116 516 225 c +525 263 530 304 530 349 c + +ce} _d +/R{634 0 83 0 588 702 sc +588 0 m +496 0 l +366 304 l +171 304 l +171 0 l +83 0 l +83 702 l +346 702 l +436 702 502 676 544 624 c +563 599 575 568 580 532 c +581 524 581 515 581 506 c +581 445 559 396 515 359 c +496 344 474 333 450 326 c +588 0 l + +493 507 m +493 577 454 616 377 625 c +367 626 357 627 346 627 c +171 627 l +171 376 l +336 376 l +422 376 472 406 487 467 c +491 479 493 492 493 507 c + +ce} _d +/S{634 0 43 -10 590 713 sc +590 201 m +590 114 550 53 469 17 c +428 -1 381 -10 328 -10 c +184 -10 89 56 43 189 c +122 207 l +143 134 191 89 266 72 c +286 67 307 65 330 65 c +398 65 447 83 476 120 c +491 139 499 162 499 189 c +499 237 469 273 408 296 c +343 314 l +264 334 221 345 214 348 c +179 359 153 373 135 389 c +97 423 78 466 78 519 c +78 599 115 655 189 688 c +227 705 269 713 316 713 c +413 713 485 678 534 608 c +554 571 l +559 562 563 552 566 541 c +486 519 l +477 565 448 600 398 624 c +371 637 343 643 314 643 c +265 643 226 629 195 601 c +174 582 164 558 164 531 c +164 485 193 451 250 430 c +264 425 308 414 383 397 c +450 382 497 363 524 340 c +568 305 590 258 590 201 c + +ce} _d +/T{512 0 11 0 499 702 sc +499 626 m +299 626 l +299 0 l +211 0 l +211 626 l +11 626 l +11 702 l +499 702 l +499 626 l + +ce} _d +/U{655 0 83 -10 567 702 sc +567 258 m +567 184 556 128 534 91 c +528 83 522 75 516 68 c +473 16 410 -10 327 -10 c +210 -10 135 32 103 117 c +90 154 83 201 83 258 c +83 702 l +171 702 l +171 258 l +171 179 187 126 218 99 c +243 78 282 68 334 68 c +417 68 468 103 485 174 c +491 197 494 225 494 258 c +494 702 l +567 702 l +567 258 l + +ce} _d +/V{573 0 10 0 569 702 sc +569 702 m +332 0 l +248 0 l +10 702 l +102 702 l +298 123 l +493 702 l +569 702 l + +ce} _d +/W{839 0 11 0 831 702 sc +831 702 m +663 0 l +574 0 l +422 545 l +279 0 l +189 0 l +11 702 l +101 702 l +242 133 l +244 133 l +392 702 l +463 702 l +623 133 l +625 133 l +755 702 l +831 702 l + +ce} _d +/X{552 0 9 0 552 702 sc +552 0 m +453 0 l +275 299 l +91 0 l +9 0 l +234 364 l +34 702 l +132 702 l +287 442 l +443 702 l +524 702 l +328 381 l +552 0 l + +ce} _d +/Y{573 0 11 0 568 702 sc +568 702 m +334 296 l +334 0 l +246 0 l +246 296 l +11 702 l +114 702 l +300 379 l +488 702 l +568 702 l + +ce} _d +/Z{552 0 17 0 513 702 sc +513 0 m +17 0 l +17 76 l +399 630 l +35 630 l +35 702 l +502 702 l +502 644 l +116 76 l +513 76 l +513 0 l + +ce} _d +/a{552 0 56 -10 509 534 sc +509 0 m +429 0 l +420 97 l +385 26 324 -10 238 -10 c +171 -10 120 11 87 53 c +66 79 56 110 56 147 c +56 198 78 240 122 273 c +131 281 142 287 153 292 c +198 313 272 324 375 323 c +420 323 l +420 345 l +420 409 397 448 352 463 c +316 470 l +307 471 298 471 288 471 c +205 471 158 440 145 379 c +71 391 l +80 458 124 502 205 522 c +233 530 263 534 295 534 c +384 534 442 510 469 463 c +488 431 498 380 498 311 c +498 110 l +498 63 502 26 509 0 c + +420 228 m +420 262 l +353 262 l +212 262 142 222 142 143 c +142 100 165 71 211 58 c +224 54 239 52 255 52 c +312 52 356 76 388 123 c +409 154 420 189 420 228 c + +ce} _d +/e{552 0 38 -10 506 534 sc +506 254 m +128 254 l +127 187 143 136 174 101 c +200 72 236 57 283 57 c +341 57 384 82 411 133 c +415 140 419 149 422 158 c +498 142 l +479 82 439 38 378 11 c +346 -3 312 -10 276 -10 c +187 -10 121 27 78 100 c +51 145 38 199 38 260 c +38 346 64 415 116 468 c +159 512 213 534 279 534 c +369 534 434 495 473 417 c +495 374 506 323 506 266 c +506 254 l + +418 313 m +419 370 401 413 366 442 c +342 462 313 472 279 472 c +226 472 186 448 158 400 c +142 374 133 345 132 313 c +418 313 l + +ce} _d +/i{245 0 79 0 167 702 sc +167 612 m +79 612 l +79 702 l +167 702 l +167 612 l + +163 0 m +83 0 l +83 520 l +163 520 l +163 0 l + +ce} _d +/n{552 0 71 0 482 534 sc +482 0 m +402 0 l +402 322 l +402 366 398 396 391 412 c +390 414 389 416 388 418 c +373 444 348 459 313 464 c +308 465 304 465 299 465 c +234 465 190 432 166 366 c +156 337 151 306 151 272 c +151 0 l +71 0 l +71 520 l +146 520 l +146 424 l +148 424 l +173 477 211 511 263 526 c +278 531 294 534 310 534 c +375 534 423 508 455 457 c +458 453 l +474 425 482 377 482 309 c +482 0 l + +ce} _d +/u{552 0 71 -10 479 520 sc +479 0 m +407 0 l +407 103 l +404 103 l +386 58 355 25 310 4 c +289 -5 268 -10 245 -10 c +144 -10 87 45 74 156 c +72 171 71 187 71 204 c +71 520 l +151 520 l +151 204 l +151 113 181 65 242 59 c +242 59 245 59 252 59 c +311 59 354 89 380 148 c +393 177 399 209 399 244 c +399 520 l +479 520 l +479 0 l + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHeiMono def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/space /colon /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /a /e /i /n /o /u] def +/CharStrings 35 dict dup begin +/.notdef 0 def +/space{512 0 0 0 0 0 sc +ce} _d +/colon{512 0 195 18 317 571 sc +195 418 m +195 571 l +317 571 l +317 418 l +195 418 l + +195 18 m +195 172 l +317 172 l +317 18 l +195 18 l + +ce} _d +/A{512 0 20 18 492 766 sc +255 694 m +253 694 l +168 305 l +340 305 l +255 694 l + +356 233 m +152 233 l +104 18 l +20 18 l +205 766 l +307 766 l +492 18 l +403 18 l +356 233 l + +ce} _d +/B{512 0 77 8 466 776 sc +161 459 m +207 459 l +262 459 301 469 326 489 c +351 509 364 540 364 582 c +364 621 352 651 327 672 c +302 694 267 705 222 705 c +197 705 177 702 161 696 c +161 459 l + +161 387 m +161 88 l +186 83 217 80 253 80 c +339 80 382 135 382 244 c +382 339 327 387 217 387 c +161 387 l + +466 233 m +466 83 389 8 236 8 c +181 8 128 13 77 24 c +77 761 l +128 771 181 776 236 776 c +375 776 445 715 445 592 c +445 550 435 515 414 486 c +393 457 365 438 328 429 c +328 427 l +367 420 400 398 426 361 c +453 325 466 282 466 233 c + +ce} _d +/C{512 0 56 8 435 776 sc +56 392 m +56 527 77 624 118 685 c +159 746 221 776 302 776 c +347 776 390 766 430 745 c +430 669 l +389 691 348 702 307 702 c +194 702 138 599 138 392 c +138 280 152 200 181 153 c +210 106 252 82 307 82 c +350 82 392 95 435 121 c +435 39 l +395 18 351 8 302 8 c +219 8 157 37 116 96 c +76 155 56 253 56 392 c + +ce} _d +/D{512 0 67 8 476 776 sc +392 392 m +392 507 377 587 347 633 c +318 679 271 702 207 702 c +184 702 166 699 151 694 c +151 90 l +166 85 184 82 207 82 c +251 82 286 90 311 107 c +337 124 357 155 371 200 c +385 246 392 310 392 392 c + +476 392 m +476 251 454 151 411 94 c +368 37 300 8 207 8 c +159 8 112 13 67 24 c +67 761 l +112 771 159 776 207 776 c +300 776 368 747 411 688 c +454 630 476 531 476 392 c + +ce} _d +/E{512 0 82 18 430 766 sc +166 692 m +166 459 l +420 459 l +420 387 l +166 387 l +166 92 l +430 92 l +430 18 l +82 18 l +82 766 l +430 766 l +430 692 l +166 692 l + +ce} _d +/F{512 0 92 18 430 766 sc +176 387 m +176 18 l +92 18 l +92 766 l +430 766 l +430 692 l +176 692 l +176 459 l +420 459 l +420 387 l +176 387 l + +ce} _d +/G{512 0 41 8 461 776 sc +379 105 m +379 387 l +220 387 l +220 459 l +461 459 l +461 49 l +406 22 348 8 287 8 c +206 8 145 38 103 99 c +62 160 41 257 41 392 c +41 526 63 623 106 684 c +149 745 215 776 302 776 c +342 776 386 768 435 751 c +435 672 l +390 692 346 702 302 702 c +243 702 198 677 167 628 c +136 579 121 501 121 392 c +121 185 178 82 292 82 c +323 82 352 90 379 105 c + +ce} _d +/H{512 0 61 18 451 766 sc +143 766 m +143 461 l +365 461 l +365 766 l +451 766 l +451 18 l +365 18 l +365 387 l +143 387 l +143 18 l +61 18 l +61 766 l +143 766 l + +ce} _d +/I{512 0 92 18 420 766 sc +420 18 m +92 18 l +92 90 l +213 90 l +213 694 l +92 694 l +92 766 l +420 766 l +420 694 l +299 694 l +299 90 l +420 90 l +420 18 l + +ce} _d +/J{512 0 61 8 410 766 sc +410 766 m +410 213 l +410 138 395 85 365 54 c +336 23 286 8 215 8 c +159 8 108 18 61 39 c +61 128 l +81 117 107 106 138 96 c +170 87 196 82 215 82 c +251 82 278 92 296 113 c +314 134 323 168 323 215 c +323 694 l +154 694 l +154 766 l +410 766 l + +ce} _d +/K{512 0 77 18 476 766 sc +161 428 m +163 428 l +374 766 l +471 766 l +241 408 l +476 18 l +379 18 l +163 387 l +161 387 l +161 18 l +77 18 l +77 766 l +161 766 l +161 428 l + +ce} _d +/L{512 0 102 18 430 766 sc +186 766 m +186 92 l +430 92 l +430 18 l +102 18 l +102 766 l +186 766 l + +ce} _d +/M{512 0 41 18 471 766 sc +387 571 m +385 571 l +295 223 l +213 223 l +123 571 l +121 571 l +121 18 l +41 18 l +41 766 l +135 766 l +257 305 l +259 305 l +381 766 l +471 766 l +471 18 l +387 18 l +387 571 l + +ce} _d +/N{512 0 67 18 445 766 sc +155 582 m +153 582 l +153 18 l +67 18 l +67 766 l +153 766 l +361 203 l +364 203 l +364 766 l +445 766 l +445 18 l +364 18 l +155 582 l + +ce} _d +/O{512 0 41 8 471 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 251 453 152 418 94 c +383 37 329 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/P{512 0 77 18 466 776 sc +384 551 m +384 605 372 644 347 668 c +322 693 284 705 232 705 c +204 705 180 702 161 696 c +161 397 l +181 394 205 392 232 392 c +285 392 323 404 347 428 c +372 453 384 494 384 551 c + +466 551 m +466 469 448 410 412 374 c +376 339 320 321 243 321 c +219 321 192 323 161 326 c +161 18 l +77 18 l +77 761 l +130 771 185 776 241 776 c +318 776 375 758 411 722 c +448 687 466 630 466 551 c + +ce} _d +/Q{512 0 41 -135 492 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 206 437 89 369 40 c +369 38 l +397 23 422 1 443 -30 c +465 -61 481 -96 492 -135 c +401 -135 l +387 -82 369 -44 346 -23 c +323 -2 293 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/R{512 0 72 18 481 776 sc +379 571 m +379 660 328 705 227 705 c +199 705 175 702 156 696 c +156 418 l +217 418 l +276 418 318 429 342 452 c +367 475 379 514 379 571 c + +156 346 m +156 18 l +72 18 l +72 761 l +125 771 180 776 236 776 c +312 776 368 759 405 725 c +442 692 461 640 461 571 c +461 474 424 408 349 374 c +349 372 l +370 361 393 317 417 238 c +481 18 l +393 18 l +333 240 l +321 283 307 312 290 325 c +274 339 246 346 207 346 c +156 346 l + +ce} _d +/S{512 0 72 8 451 776 sc +266 702 m +234 702 208 692 187 671 c +166 650 156 624 156 592 c +156 558 163 530 178 507 c +193 485 217 466 251 451 c +327 417 379 382 408 345 c +437 309 451 262 451 203 c +451 138 433 90 398 57 c +363 24 312 8 246 8 c +184 8 128 27 77 65 c +77 162 l +132 109 190 82 251 82 c +328 82 367 122 367 203 c +367 240 358 271 340 296 c +322 321 292 342 251 361 c +187 390 141 422 113 459 c +86 496 72 540 72 592 c +72 647 89 691 124 725 c +159 759 204 776 261 776 c +297 776 327 773 350 768 c +373 763 400 752 430 735 c +430 643 l +377 682 323 702 266 702 c + +ce} _d +/T{512 0 56 18 456 766 sc +214 18 m +214 694 l +56 694 l +56 766 l +456 766 l +456 694 l +298 694 l +298 18 l +214 18 l + +ce} _d +/U{512 0 61 8 451 766 sc +402 58 m +369 25 321 8 256 8 c +191 8 143 25 110 58 c +77 91 61 143 61 213 c +61 766 l +147 766 l +147 233 l +147 178 156 139 174 116 c +193 93 221 82 258 82 c +295 82 323 93 341 116 c +360 139 369 178 369 233 c +369 766 l +451 766 l +451 213 l +451 143 435 91 402 58 c + +ce} _d +/V{512 0 31 18 481 766 sc +259 90 m +397 766 l +481 766 l +307 18 l +205 18 l +31 766 l +119 766 l +257 90 l +259 90 l + +ce} _d +/W{512 0 26 18 486 766 sc +157 141 m +159 141 l +214 664 l +306 664 l +361 141 l +364 141 l +410 766 l +486 766 l +425 18 l +313 18 l +257 551 l +255 551 l +199 18 l +87 18 l +26 766 l +111 766 l +157 141 l + +ce} _d +/X{512 0 51 18 461 766 sc +257 469 m +259 469 l +374 766 l +459 766 l +307 402 l +461 18 l +369 18 l +255 331 l +253 331 l +138 18 l +51 18 l +205 402 l +53 766 l +143 766 l +257 469 l + +ce} _d +/Y{512 0 31 18 481 766 sc +257 402 m +259 402 l +394 766 l +481 766 l +298 315 l +298 18 l +214 18 l +214 315 l +31 766 l +123 766 l +257 402 l + +ce} _d +/Z{512 0 77 18 435 766 sc +343 692 m +343 694 l +77 694 l +77 766 l +435 766 l +435 694 l +169 92 l +169 90 l +435 90 l +435 18 l +77 18 l +77 90 l +343 692 l + +ce} _d +/a{512 0 61 8 440 561 sc +261 561 m +330 561 377 547 402 520 c +427 493 440 442 440 367 c +440 18 l +367 18 l +365 95 l +362 95 l +330 37 279 8 210 8 c +165 8 129 22 102 50 c +75 79 61 118 61 167 c +61 229 82 277 124 310 c +166 344 229 361 312 361 c +361 361 l +361 387 l +361 426 353 453 338 469 c +323 485 298 493 261 493 c +238 493 210 489 175 480 c +140 472 111 463 87 452 c +87 525 l +111 536 140 544 174 551 c +208 558 237 561 261 561 c + +361 300 m +312 300 l +196 300 138 257 138 172 c +138 141 146 118 161 101 c +177 85 198 77 225 77 c +266 77 298 93 323 126 c +348 159 361 205 361 264 c +361 300 l + +ce} _d +/e{512 0 56 8 445 561 sc +141 258 m +144 195 157 149 180 121 c +203 93 237 79 282 79 c +323 79 369 91 420 116 c +420 34 l +369 17 321 8 276 8 c +129 8 56 100 56 285 c +56 381 73 451 107 495 c +142 539 193 561 261 561 c +323 561 369 540 399 497 c +430 455 445 386 445 290 c +445 283 444 272 443 258 c +141 258 l + +141 326 m +365 326 l +364 435 330 490 261 490 c +222 490 193 478 174 453 c +155 429 144 387 141 326 c + +ce} _d +/i{512 0 97 18 435 797 sc +324 551 m +324 88 l +435 88 l +435 18 l +97 18 l +97 88 l +240 88 l +240 481 l +128 481 l +128 551 l +324 551 l + +219 674 m +219 797 l +324 797 l +324 674 l +219 674 l + +ce} _d +/n{512 0 72 18 451 561 sc +451 356 m +451 18 l +372 18 l +372 338 l +372 398 365 438 351 458 c +338 478 313 488 276 488 c +242 488 213 469 189 431 c +165 393 153 341 153 276 c +153 18 l +72 18 l +72 551 l +147 551 l +150 474 l +152 474 l +165 500 184 521 211 537 c +238 553 266 561 297 561 c +351 561 390 545 414 514 c +439 483 451 431 451 356 c + +ce} _d +/o{512 0 51 8 461 561 sc +51 284 m +51 469 119 561 256 561 c +393 561 461 469 461 284 c +461 100 393 8 256 8 c +119 8 51 100 51 284 c + +164 125 m +184 94 215 79 256 79 c +297 79 328 94 347 125 c +367 156 377 209 377 284 c +377 359 367 412 347 443 c +328 474 297 490 256 490 c +215 490 184 474 164 443 c +145 412 135 359 135 284 c +135 209 145 156 164 125 c + +ce} _d +/u{512 0 67 8 435 551 sc +67 203 m +67 551 l +145 551 l +145 221 l +145 164 151 127 164 108 c +177 90 201 81 236 81 c +269 81 297 100 320 137 c +343 175 354 227 354 293 c +354 551 l +435 551 l +435 18 l +359 18 l +357 95 l +355 95 l +342 68 323 46 298 31 c +273 16 245 8 215 8 c +162 8 124 23 101 52 c +78 81 67 132 67 203 c + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +0 0 translate +0 0 504 72 rectclip +gsave +0 0 m +504 0 l +504 72 l +0 72 l +cl +1 setgray +fill +grestore +gsave +0 36 m +504 36 l +504 72 l +0 72 l +0 36 l +cl +grestore +0 setgray +/WenQuanYiZenHei 16.000 selectfont +gsave + +55.4375 49.7812 translate +0 rotate +0 0 m /W glyphshow +13.1094 0 m /e glyphshow +21.7344 0 m /n glyphshow +30.3594 0 m /Q glyphshow +40.9062 0 m /u glyphshow +49.5312 0 m /a glyphshow +58.1562 0 m /n glyphshow +66.7812 0 m /Y glyphshow +75.7344 0 m /i glyphshow +79.5625 0 m /space glyphshow +84.3594 0 m /Z glyphshow +92.9844 0 m /e glyphshow +101.609 0 m /n glyphshow +110.234 0 m /space glyphshow +115.031 0 m /H glyphshow +125.578 0 m /e glyphshow +134.203 0 m /i glyphshow +138.031 0 m /colon glyphshow +142.828 0 m /space glyphshow +147.625 0 m /A glyphshow +156.578 0 m /B glyphshow +166.484 0 m /C glyphshow +176.391 0 m /D glyphshow +186.938 0 m /E glyphshow +195.891 0 m /F glyphshow +203.562 0 m /G glyphshow +214.109 0 m /H glyphshow +224.656 0 m /I glyphshow +228.812 0 m /J glyphshow +235.203 0 m /K glyphshow +245.109 0 m /L glyphshow +253.109 0 m /M glyphshow +266.219 0 m /N glyphshow +276.766 0 m /O glyphshow +287.312 0 m /P glyphshow +296.266 0 m /Q glyphshow +306.812 0 m /R glyphshow +316.719 0 m /S glyphshow +326.625 0 m /T glyphshow +334.625 0 m /U glyphshow +344.859 0 m /V glyphshow +353.812 0 m /W glyphshow +366.922 0 m /X glyphshow +375.547 0 m /Y glyphshow +384.5 0 m /Z glyphshow +grestore +gsave +0 0 m +504 0 l +504 36 l +0 36 l +0 0 l +cl +grestore +/WenQuanYiZenHeiMono 16.000 selectfont +gsave + +52 13.6328 translate +0 rotate +0 0 m /W glyphshow +8 0 m /e glyphshow +16 0 m /n glyphshow +24 0 m /Q glyphshow +32 0 m /u glyphshow +40 0 m /a glyphshow +48 0 m /n glyphshow +56 0 m /Y glyphshow +64 0 m /i glyphshow +72 0 m /space glyphshow +80 0 m /Z glyphshow +88 0 m /e glyphshow +96 0 m /n glyphshow +104 0 m /space glyphshow +112 0 m /H glyphshow +120 0 m /e glyphshow +128 0 m /i glyphshow +136 0 m /space glyphshow +144 0 m /M glyphshow +152 0 m /o glyphshow +160 0 m /n glyphshow +168 0 m /o glyphshow +176 0 m /colon glyphshow +184 0 m /space glyphshow +192 0 m /A glyphshow +200 0 m /B glyphshow +208 0 m /C glyphshow +216 0 m /D glyphshow +224 0 m /E glyphshow +232 0 m /F glyphshow +240 0 m /G glyphshow +248 0 m /H glyphshow +256 0 m /I glyphshow +264 0 m /J glyphshow +272 0 m /K glyphshow +280 0 m /L glyphshow +288 0 m /M glyphshow +296 0 m /N glyphshow +304 0 m /O glyphshow +312 0 m /P glyphshow +320 0 m /Q glyphshow +328 0 m /R glyphshow +336 0 m /S glyphshow +344 0 m /T glyphshow +352 0 m /U glyphshow +360 0 m /V glyphshow +368 0 m /W glyphshow +376 0 m /X glyphshow +384 0 m /Y glyphshow +392 0 m /Z glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps new file mode 100644 index 000000000000..3df370bd885e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps @@ -0,0 +1,1483 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: ttc_type42.eps +%%Creator: Matplotlib v3.11.0.dev1121+gba80e42970.d20250725, https://matplotlib.org/ +%%CreationDate: Fri Jul 25 06:03:10 2025 +%%Orientation: portrait +%%BoundingBox: 0 0 504 72 +%%HiResBoundingBox: 0.000000 0.000000 504.000000 72.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/sc { setcachedevice } _d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHei def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/space /colon /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /a /e /i /n /u] def +/CharStrings 34 dict dup begin +/.notdef 0 def +/space{307 0 0 0 0 0 sc +ce} _d +/colon{307 0 101 0 215 520 sc +215 404 m +101 404 l +101 520 l +215 520 l +215 404 l + +215 0 m +101 0 l +101 116 l +215 116 l +215 0 l + +ce} _d +/A{573 0 11 0 568 702 sc +568 0 m +478 0 l +408 205 l +147 205 l +85 0 l +11 0 l +239 702 l +340 702 l +568 0 l + +388 271 m +281 608 l +172 271 l +388 271 l + +ce} _d +/B{634 0 83 0 588 702 sc +588 194 m +588 130 565 80 520 45 c +484 16 434 1 370 0 c +347 0 l +83 0 l +83 702 l +348 702 l +405 702 448 694 477 679 c +482 676 487 673 493 670 c +541 637 565 591 566 531 c +566 470 542 424 494 394 c +462 380 l +456 377 449 375 442 374 c +442 372 l +501 359 543 327 568 276 c +581 251 588 224 588 194 c + +479 520 m +479 585 443 621 370 630 c +361 631 351 631 341 631 c +171 631 l +171 401 l +317 401 l +425 401 479 441 479 520 c + +500 198 m +500 241 485 276 454 303 c +453 304 451 306 449 307 c +426 325 389 334 338 334 c +171 334 l +171 75 l +343 75 l +432 75 483 105 497 166 c +499 175 500 186 500 198 c + +ce} _d +/C{634 0 43 -10 589 713 sc +589 219 m +558 90 490 16 386 -5 c +367 -8 348 -10 329 -10 c +224 -10 146 38 94 135 c +60 199 43 273 43 358 c +43 471 72 560 131 626 c +183 684 251 713 336 713 c +435 713 508 669 555 582 c +570 554 582 523 589 488 c +506 473 l +479 573 430 628 359 637 c +350 638 342 639 333 639 c +248 639 190 590 159 492 c +146 449 139 402 139 351 c +139 261 158 189 197 134 c +230 87 274 63 329 63 c +418 63 477 117 506 225 c +507 229 508 233 509 237 c +589 219 l + +ce} _d +/D{675 0 87 0 636 702 sc +636 353 m +636 247 607 160 550 93 c +496 31 425 0 338 0 c +87 0 l +87 702 l +309 702 l +394 702 462 682 512 642 c +525 631 538 618 551 603 c +608 537 636 454 636 353 c + +547 353 m +547 436 525 504 482 557 c +449 599 403 623 344 628 c +304 629 l +175 629 l +175 75 l +304 75 l +382 75 440 97 478 140 c +484 147 490 155 496 164 c +530 216 547 279 547 353 c + +ce} _d +/E{573 0 87 0 542 702 sc +542 0 m +87 0 l +87 702 l +531 702 l +531 627 l +175 627 l +175 403 l +458 403 l +458 333 l +175 333 l +175 76 l +542 76 l +542 0 l + +ce} _d +/F{491 0 84 0 514 702 sc +514 627 m +172 627 l +172 403 l +456 403 l +456 333 l +172 333 l +172 0 l +84 0 l +84 702 l +514 702 l +514 627 l + +ce} _d +/G{675 0 49 -10 614 713 sc +614 -5 m +560 -5 l +537 82 l +497 24 436 -7 355 -10 c +350 -10 346 -10 342 -10 c +237 -10 157 35 104 125 c +67 187 49 260 49 344 c +49 452 77 541 133 610 c +188 679 262 713 353 713 c +457 713 532 670 579 585 c +591 563 600 538 607 511 c +524 490 l +512 553 480 597 428 622 c +403 633 376 639 347 639 c +256 639 195 589 164 488 c +151 447 144 400 144 348 c +144 251 167 176 212 123 c +247 82 292 61 348 61 c +418 61 469 88 500 141 c +516 170 524 203 524 242 c +524 281 l +349 281 l +349 354 l +614 354 l +614 -5 l + +ce} _d +/H{675 0 83 0 585 702 sc +585 0 m +497 0 l +497 334 l +171 334 l +171 0 l +83 0 l +83 702 l +171 702 l +171 411 l +497 411 l +497 702 l +585 702 l +585 0 l + +ce} _d +/I{266 0 88 0 176 702 sc +176 0 m +88 0 l +88 702 l +176 702 l +176 0 l + +ce} _d +/J{409 0 17 -10 331 702 sc +331 229 m +331 104 290 29 207 2 c +182 -6 153 -10 120 -10 c +86 -10 52 -5 17 4 c +17 76 l +50 69 81 66 108 66 c +171 66 211 83 227 118 c +238 139 243 176 243 229 c +243 702 l +331 702 l +331 229 l + +ce} _d +/K{634 0 88 0 643 702 sc +643 0 m +546 0 l +337 387 l +176 187 l +176 0 l +88 0 l +88 702 l +176 702 l +176 295 l +493 702 l +588 702 l +398 457 l +643 0 l + +ce} _d +/L{512 0 86 0 501 702 sc +501 0 m +86 0 l +86 702 l +174 702 l +174 78 l +501 78 l +501 0 l + +ce} _d +/M{839 0 82 0 761 702 sc +761 0 m +673 0 l +673 613 l +669 613 l +446 0 l +387 0 l +160 613 l +156 613 l +156 0 l +82 0 l +82 702 l +213 702 l +425 140 l +632 702 l +761 702 l +761 0 l + +ce} _d +/N{675 0 84 0 601 702 sc +601 0 m +515 0 l +158 612 l +158 0 l +84 0 l +84 702 l +195 702 l +527 130 l +527 702 l +601 702 l +601 0 l + +ce} _d +/O{675 0 45 -10 623 713 sc +623 359 m +623 258 598 173 548 102 c +495 27 424 -10 335 -10 c +230 -10 151 36 98 128 c +63 189 45 262 45 346 c +45 453 71 540 124 609 c +176 678 246 713 334 713 c +435 713 513 669 566 580 c +604 517 623 443 623 359 c + +530 354 m +530 449 509 522 468 575 c +435 618 392 640 337 640 c +250 640 191 591 159 492 c +144 448 137 399 137 345 c +137 258 157 187 197 133 c +232 85 278 61 335 61 c +417 61 474 108 507 203 c +522 248 530 299 530 354 c + +ce} _d +/P{573 0 66 0 542 702 sc +542 492 m +542 436 523 388 485 348 c +480 343 l +441 305 385 286 311 286 c +154 286 l +154 0 l +66 0 l +66 702 l +301 702 l +376 702 433 686 470 655 c +510 622 534 575 541 515 c +542 507 542 499 542 492 c + +453 492 m +453 557 425 600 370 620 c +351 626 331 629 308 629 c +154 629 l +154 358 l +302 358 l +375 358 422 384 442 435 c +449 452 453 471 453 492 c + +ce} _d +/Q{675 0 42 -167 626 713 sc +626 351 m +626 244 599 158 546 91 c +509 46 462 16 407 1 c +407 -14 l +407 -55 425 -80 461 -88 c +468 -90 476 -91 485 -91 c +500 -91 532 -89 580 -84 c +580 -154 l +553 -163 528 -167 504 -167 c +412 -167 357 -130 340 -55 c +337 -41 335 -26 335 -10 c +224 -7 142 41 91 135 c +58 195 42 265 42 346 c +42 456 69 545 124 613 c +177 680 247 713 334 713 c +441 713 520 666 572 572 c +608 509 626 436 626 351 c + +530 349 m +530 482 496 569 428 610 c +401 627 370 635 333 635 c +234 635 172 576 147 459 c +140 424 136 386 136 344 c +136 239 160 161 207 112 c +238 79 278 62 327 62 c +425 62 488 116 516 225 c +525 263 530 304 530 349 c + +ce} _d +/R{634 0 83 0 588 702 sc +588 0 m +496 0 l +366 304 l +171 304 l +171 0 l +83 0 l +83 702 l +346 702 l +436 702 502 676 544 624 c +563 599 575 568 580 532 c +581 524 581 515 581 506 c +581 445 559 396 515 359 c +496 344 474 333 450 326 c +588 0 l + +493 507 m +493 577 454 616 377 625 c +367 626 357 627 346 627 c +171 627 l +171 376 l +336 376 l +422 376 472 406 487 467 c +491 479 493 492 493 507 c + +ce} _d +/S{634 0 43 -10 590 713 sc +590 201 m +590 114 550 53 469 17 c +428 -1 381 -10 328 -10 c +184 -10 89 56 43 189 c +122 207 l +143 134 191 89 266 72 c +286 67 307 65 330 65 c +398 65 447 83 476 120 c +491 139 499 162 499 189 c +499 237 469 273 408 296 c +343 314 l +264 334 221 345 214 348 c +179 359 153 373 135 389 c +97 423 78 466 78 519 c +78 599 115 655 189 688 c +227 705 269 713 316 713 c +413 713 485 678 534 608 c +554 571 l +559 562 563 552 566 541 c +486 519 l +477 565 448 600 398 624 c +371 637 343 643 314 643 c +265 643 226 629 195 601 c +174 582 164 558 164 531 c +164 485 193 451 250 430 c +264 425 308 414 383 397 c +450 382 497 363 524 340 c +568 305 590 258 590 201 c + +ce} _d +/T{512 0 11 0 499 702 sc +499 626 m +299 626 l +299 0 l +211 0 l +211 626 l +11 626 l +11 702 l +499 702 l +499 626 l + +ce} _d +/U{655 0 83 -10 567 702 sc +567 258 m +567 184 556 128 534 91 c +528 83 522 75 516 68 c +473 16 410 -10 327 -10 c +210 -10 135 32 103 117 c +90 154 83 201 83 258 c +83 702 l +171 702 l +171 258 l +171 179 187 126 218 99 c +243 78 282 68 334 68 c +417 68 468 103 485 174 c +491 197 494 225 494 258 c +494 702 l +567 702 l +567 258 l + +ce} _d +/V{573 0 10 0 569 702 sc +569 702 m +332 0 l +248 0 l +10 702 l +102 702 l +298 123 l +493 702 l +569 702 l + +ce} _d +/W{839 0 11 0 831 702 sc +831 702 m +663 0 l +574 0 l +422 545 l +279 0 l +189 0 l +11 702 l +101 702 l +242 133 l +244 133 l +392 702 l +463 702 l +623 133 l +625 133 l +755 702 l +831 702 l + +ce} _d +/X{552 0 9 0 552 702 sc +552 0 m +453 0 l +275 299 l +91 0 l +9 0 l +234 364 l +34 702 l +132 702 l +287 442 l +443 702 l +524 702 l +328 381 l +552 0 l + +ce} _d +/Y{573 0 11 0 568 702 sc +568 702 m +334 296 l +334 0 l +246 0 l +246 296 l +11 702 l +114 702 l +300 379 l +488 702 l +568 702 l + +ce} _d +/Z{552 0 17 0 513 702 sc +513 0 m +17 0 l +17 76 l +399 630 l +35 630 l +35 702 l +502 702 l +502 644 l +116 76 l +513 76 l +513 0 l + +ce} _d +/a{552 0 56 -10 509 534 sc +509 0 m +429 0 l +420 97 l +385 26 324 -10 238 -10 c +171 -10 120 11 87 53 c +66 79 56 110 56 147 c +56 198 78 240 122 273 c +131 281 142 287 153 292 c +198 313 272 324 375 323 c +420 323 l +420 345 l +420 409 397 448 352 463 c +316 470 l +307 471 298 471 288 471 c +205 471 158 440 145 379 c +71 391 l +80 458 124 502 205 522 c +233 530 263 534 295 534 c +384 534 442 510 469 463 c +488 431 498 380 498 311 c +498 110 l +498 63 502 26 509 0 c + +420 228 m +420 262 l +353 262 l +212 262 142 222 142 143 c +142 100 165 71 211 58 c +224 54 239 52 255 52 c +312 52 356 76 388 123 c +409 154 420 189 420 228 c + +ce} _d +/e{552 0 38 -10 506 534 sc +506 254 m +128 254 l +127 187 143 136 174 101 c +200 72 236 57 283 57 c +341 57 384 82 411 133 c +415 140 419 149 422 158 c +498 142 l +479 82 439 38 378 11 c +346 -3 312 -10 276 -10 c +187 -10 121 27 78 100 c +51 145 38 199 38 260 c +38 346 64 415 116 468 c +159 512 213 534 279 534 c +369 534 434 495 473 417 c +495 374 506 323 506 266 c +506 254 l + +418 313 m +419 370 401 413 366 442 c +342 462 313 472 279 472 c +226 472 186 448 158 400 c +142 374 133 345 132 313 c +418 313 l + +ce} _d +/i{245 0 79 0 167 702 sc +167 612 m +79 612 l +79 702 l +167 702 l +167 612 l + +163 0 m +83 0 l +83 520 l +163 520 l +163 0 l + +ce} _d +/n{552 0 71 0 482 534 sc +482 0 m +402 0 l +402 322 l +402 366 398 396 391 412 c +390 414 389 416 388 418 c +373 444 348 459 313 464 c +308 465 304 465 299 465 c +234 465 190 432 166 366 c +156 337 151 306 151 272 c +151 0 l +71 0 l +71 520 l +146 520 l +146 424 l +148 424 l +173 477 211 511 263 526 c +278 531 294 534 310 534 c +375 534 423 508 455 457 c +458 453 l +474 425 482 377 482 309 c +482 0 l + +ce} _d +/u{552 0 71 -10 479 520 sc +479 0 m +407 0 l +407 103 l +404 103 l +386 58 355 25 310 4 c +289 -5 268 -10 245 -10 c +144 -10 87 45 74 156 c +72 171 71 187 71 204 c +71 520 l +151 520 l +151 204 l +151 113 181 65 242 59 c +242 59 245 59 252 59 c +311 59 354 89 380 148 c +393 177 399 209 399 244 c +399 520 l +479 520 l +479 0 l + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHeiMono def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/space /colon /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /a /e /i /n /o /u] def +/CharStrings 35 dict dup begin +/.notdef 0 def +/space{512 0 0 0 0 0 sc +ce} _d +/colon{512 0 195 18 317 571 sc +195 418 m +195 571 l +317 571 l +317 418 l +195 418 l + +195 18 m +195 172 l +317 172 l +317 18 l +195 18 l + +ce} _d +/A{512 0 20 18 492 766 sc +255 694 m +253 694 l +168 305 l +340 305 l +255 694 l + +356 233 m +152 233 l +104 18 l +20 18 l +205 766 l +307 766 l +492 18 l +403 18 l +356 233 l + +ce} _d +/B{512 0 77 8 466 776 sc +161 459 m +207 459 l +262 459 301 469 326 489 c +351 509 364 540 364 582 c +364 621 352 651 327 672 c +302 694 267 705 222 705 c +197 705 177 702 161 696 c +161 459 l + +161 387 m +161 88 l +186 83 217 80 253 80 c +339 80 382 135 382 244 c +382 339 327 387 217 387 c +161 387 l + +466 233 m +466 83 389 8 236 8 c +181 8 128 13 77 24 c +77 761 l +128 771 181 776 236 776 c +375 776 445 715 445 592 c +445 550 435 515 414 486 c +393 457 365 438 328 429 c +328 427 l +367 420 400 398 426 361 c +453 325 466 282 466 233 c + +ce} _d +/C{512 0 56 8 435 776 sc +56 392 m +56 527 77 624 118 685 c +159 746 221 776 302 776 c +347 776 390 766 430 745 c +430 669 l +389 691 348 702 307 702 c +194 702 138 599 138 392 c +138 280 152 200 181 153 c +210 106 252 82 307 82 c +350 82 392 95 435 121 c +435 39 l +395 18 351 8 302 8 c +219 8 157 37 116 96 c +76 155 56 253 56 392 c + +ce} _d +/D{512 0 67 8 476 776 sc +392 392 m +392 507 377 587 347 633 c +318 679 271 702 207 702 c +184 702 166 699 151 694 c +151 90 l +166 85 184 82 207 82 c +251 82 286 90 311 107 c +337 124 357 155 371 200 c +385 246 392 310 392 392 c + +476 392 m +476 251 454 151 411 94 c +368 37 300 8 207 8 c +159 8 112 13 67 24 c +67 761 l +112 771 159 776 207 776 c +300 776 368 747 411 688 c +454 630 476 531 476 392 c + +ce} _d +/E{512 0 82 18 430 766 sc +166 692 m +166 459 l +420 459 l +420 387 l +166 387 l +166 92 l +430 92 l +430 18 l +82 18 l +82 766 l +430 766 l +430 692 l +166 692 l + +ce} _d +/F{512 0 92 18 430 766 sc +176 387 m +176 18 l +92 18 l +92 766 l +430 766 l +430 692 l +176 692 l +176 459 l +420 459 l +420 387 l +176 387 l + +ce} _d +/G{512 0 41 8 461 776 sc +379 105 m +379 387 l +220 387 l +220 459 l +461 459 l +461 49 l +406 22 348 8 287 8 c +206 8 145 38 103 99 c +62 160 41 257 41 392 c +41 526 63 623 106 684 c +149 745 215 776 302 776 c +342 776 386 768 435 751 c +435 672 l +390 692 346 702 302 702 c +243 702 198 677 167 628 c +136 579 121 501 121 392 c +121 185 178 82 292 82 c +323 82 352 90 379 105 c + +ce} _d +/H{512 0 61 18 451 766 sc +143 766 m +143 461 l +365 461 l +365 766 l +451 766 l +451 18 l +365 18 l +365 387 l +143 387 l +143 18 l +61 18 l +61 766 l +143 766 l + +ce} _d +/I{512 0 92 18 420 766 sc +420 18 m +92 18 l +92 90 l +213 90 l +213 694 l +92 694 l +92 766 l +420 766 l +420 694 l +299 694 l +299 90 l +420 90 l +420 18 l + +ce} _d +/J{512 0 61 8 410 766 sc +410 766 m +410 213 l +410 138 395 85 365 54 c +336 23 286 8 215 8 c +159 8 108 18 61 39 c +61 128 l +81 117 107 106 138 96 c +170 87 196 82 215 82 c +251 82 278 92 296 113 c +314 134 323 168 323 215 c +323 694 l +154 694 l +154 766 l +410 766 l + +ce} _d +/K{512 0 77 18 476 766 sc +161 428 m +163 428 l +374 766 l +471 766 l +241 408 l +476 18 l +379 18 l +163 387 l +161 387 l +161 18 l +77 18 l +77 766 l +161 766 l +161 428 l + +ce} _d +/L{512 0 102 18 430 766 sc +186 766 m +186 92 l +430 92 l +430 18 l +102 18 l +102 766 l +186 766 l + +ce} _d +/M{512 0 41 18 471 766 sc +387 571 m +385 571 l +295 223 l +213 223 l +123 571 l +121 571 l +121 18 l +41 18 l +41 766 l +135 766 l +257 305 l +259 305 l +381 766 l +471 766 l +471 18 l +387 18 l +387 571 l + +ce} _d +/N{512 0 67 18 445 766 sc +155 582 m +153 582 l +153 18 l +67 18 l +67 766 l +153 766 l +361 203 l +364 203 l +364 766 l +445 766 l +445 18 l +364 18 l +155 582 l + +ce} _d +/O{512 0 41 8 471 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 251 453 152 418 94 c +383 37 329 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/P{512 0 77 18 466 776 sc +384 551 m +384 605 372 644 347 668 c +322 693 284 705 232 705 c +204 705 180 702 161 696 c +161 397 l +181 394 205 392 232 392 c +285 392 323 404 347 428 c +372 453 384 494 384 551 c + +466 551 m +466 469 448 410 412 374 c +376 339 320 321 243 321 c +219 321 192 323 161 326 c +161 18 l +77 18 l +77 761 l +130 771 185 776 241 776 c +318 776 375 758 411 722 c +448 687 466 630 466 551 c + +ce} _d +/Q{512 0 41 -135 492 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 206 437 89 369 40 c +369 38 l +397 23 422 1 443 -30 c +465 -61 481 -96 492 -135 c +401 -135 l +387 -82 369 -44 346 -23 c +323 -2 293 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/R{512 0 72 18 481 776 sc +379 571 m +379 660 328 705 227 705 c +199 705 175 702 156 696 c +156 418 l +217 418 l +276 418 318 429 342 452 c +367 475 379 514 379 571 c + +156 346 m +156 18 l +72 18 l +72 761 l +125 771 180 776 236 776 c +312 776 368 759 405 725 c +442 692 461 640 461 571 c +461 474 424 408 349 374 c +349 372 l +370 361 393 317 417 238 c +481 18 l +393 18 l +333 240 l +321 283 307 312 290 325 c +274 339 246 346 207 346 c +156 346 l + +ce} _d +/S{512 0 72 8 451 776 sc +266 702 m +234 702 208 692 187 671 c +166 650 156 624 156 592 c +156 558 163 530 178 507 c +193 485 217 466 251 451 c +327 417 379 382 408 345 c +437 309 451 262 451 203 c +451 138 433 90 398 57 c +363 24 312 8 246 8 c +184 8 128 27 77 65 c +77 162 l +132 109 190 82 251 82 c +328 82 367 122 367 203 c +367 240 358 271 340 296 c +322 321 292 342 251 361 c +187 390 141 422 113 459 c +86 496 72 540 72 592 c +72 647 89 691 124 725 c +159 759 204 776 261 776 c +297 776 327 773 350 768 c +373 763 400 752 430 735 c +430 643 l +377 682 323 702 266 702 c + +ce} _d +/T{512 0 56 18 456 766 sc +214 18 m +214 694 l +56 694 l +56 766 l +456 766 l +456 694 l +298 694 l +298 18 l +214 18 l + +ce} _d +/U{512 0 61 8 451 766 sc +402 58 m +369 25 321 8 256 8 c +191 8 143 25 110 58 c +77 91 61 143 61 213 c +61 766 l +147 766 l +147 233 l +147 178 156 139 174 116 c +193 93 221 82 258 82 c +295 82 323 93 341 116 c +360 139 369 178 369 233 c +369 766 l +451 766 l +451 213 l +451 143 435 91 402 58 c + +ce} _d +/V{512 0 31 18 481 766 sc +259 90 m +397 766 l +481 766 l +307 18 l +205 18 l +31 766 l +119 766 l +257 90 l +259 90 l + +ce} _d +/W{512 0 26 18 486 766 sc +157 141 m +159 141 l +214 664 l +306 664 l +361 141 l +364 141 l +410 766 l +486 766 l +425 18 l +313 18 l +257 551 l +255 551 l +199 18 l +87 18 l +26 766 l +111 766 l +157 141 l + +ce} _d +/X{512 0 51 18 461 766 sc +257 469 m +259 469 l +374 766 l +459 766 l +307 402 l +461 18 l +369 18 l +255 331 l +253 331 l +138 18 l +51 18 l +205 402 l +53 766 l +143 766 l +257 469 l + +ce} _d +/Y{512 0 31 18 481 766 sc +257 402 m +259 402 l +394 766 l +481 766 l +298 315 l +298 18 l +214 18 l +214 315 l +31 766 l +123 766 l +257 402 l + +ce} _d +/Z{512 0 77 18 435 766 sc +343 692 m +343 694 l +77 694 l +77 766 l +435 766 l +435 694 l +169 92 l +169 90 l +435 90 l +435 18 l +77 18 l +77 90 l +343 692 l + +ce} _d +/a{512 0 61 8 440 561 sc +261 561 m +330 561 377 547 402 520 c +427 493 440 442 440 367 c +440 18 l +367 18 l +365 95 l +362 95 l +330 37 279 8 210 8 c +165 8 129 22 102 50 c +75 79 61 118 61 167 c +61 229 82 277 124 310 c +166 344 229 361 312 361 c +361 361 l +361 387 l +361 426 353 453 338 469 c +323 485 298 493 261 493 c +238 493 210 489 175 480 c +140 472 111 463 87 452 c +87 525 l +111 536 140 544 174 551 c +208 558 237 561 261 561 c + +361 300 m +312 300 l +196 300 138 257 138 172 c +138 141 146 118 161 101 c +177 85 198 77 225 77 c +266 77 298 93 323 126 c +348 159 361 205 361 264 c +361 300 l + +ce} _d +/e{512 0 56 8 445 561 sc +141 258 m +144 195 157 149 180 121 c +203 93 237 79 282 79 c +323 79 369 91 420 116 c +420 34 l +369 17 321 8 276 8 c +129 8 56 100 56 285 c +56 381 73 451 107 495 c +142 539 193 561 261 561 c +323 561 369 540 399 497 c +430 455 445 386 445 290 c +445 283 444 272 443 258 c +141 258 l + +141 326 m +365 326 l +364 435 330 490 261 490 c +222 490 193 478 174 453 c +155 429 144 387 141 326 c + +ce} _d +/i{512 0 97 18 435 797 sc +324 551 m +324 88 l +435 88 l +435 18 l +97 18 l +97 88 l +240 88 l +240 481 l +128 481 l +128 551 l +324 551 l + +219 674 m +219 797 l +324 797 l +324 674 l +219 674 l + +ce} _d +/n{512 0 72 18 451 561 sc +451 356 m +451 18 l +372 18 l +372 338 l +372 398 365 438 351 458 c +338 478 313 488 276 488 c +242 488 213 469 189 431 c +165 393 153 341 153 276 c +153 18 l +72 18 l +72 551 l +147 551 l +150 474 l +152 474 l +165 500 184 521 211 537 c +238 553 266 561 297 561 c +351 561 390 545 414 514 c +439 483 451 431 451 356 c + +ce} _d +/o{512 0 51 8 461 561 sc +51 284 m +51 469 119 561 256 561 c +393 561 461 469 461 284 c +461 100 393 8 256 8 c +119 8 51 100 51 284 c + +164 125 m +184 94 215 79 256 79 c +297 79 328 94 347 125 c +367 156 377 209 377 284 c +377 359 367 412 347 443 c +328 474 297 490 256 490 c +215 490 184 474 164 443 c +145 412 135 359 135 284 c +135 209 145 156 164 125 c + +ce} _d +/u{512 0 67 8 435 551 sc +67 203 m +67 551 l +145 551 l +145 221 l +145 164 151 127 164 108 c +177 90 201 81 236 81 c +269 81 297 100 320 137 c +343 175 354 227 354 293 c +354 551 l +435 551 l +435 18 l +359 18 l +357 95 l +355 95 l +342 68 323 46 298 31 c +273 16 245 8 215 8 c +162 8 124 23 101 52 c +78 81 67 132 67 203 c + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +0 0 translate +0 0 504 72 rectclip +gsave +0 0 m +504 0 l +504 72 l +0 72 l +cl +1 setgray +fill +grestore +gsave +0 36 m +504 36 l +504 72 l +0 72 l +0 36 l +cl +grestore +0 setgray +/WenQuanYiZenHei 16.000 selectfont +gsave + +55.4375 49.7812 translate +0 rotate +0 0 m /W glyphshow +13.1094 0 m /e glyphshow +21.7344 0 m /n glyphshow +30.3594 0 m /Q glyphshow +40.9062 0 m /u glyphshow +49.5312 0 m /a glyphshow +58.1562 0 m /n glyphshow +66.7812 0 m /Y glyphshow +75.7344 0 m /i glyphshow +79.5625 0 m /space glyphshow +84.3594 0 m /Z glyphshow +92.9844 0 m /e glyphshow +101.609 0 m /n glyphshow +110.234 0 m /space glyphshow +115.031 0 m /H glyphshow +125.578 0 m /e glyphshow +134.203 0 m /i glyphshow +138.031 0 m /colon glyphshow +142.828 0 m /space glyphshow +147.625 0 m /A glyphshow +156.578 0 m /B glyphshow +166.484 0 m /C glyphshow +176.391 0 m /D glyphshow +186.938 0 m /E glyphshow +195.891 0 m /F glyphshow +203.562 0 m /G glyphshow +214.109 0 m /H glyphshow +224.656 0 m /I glyphshow +228.812 0 m /J glyphshow +235.203 0 m /K glyphshow +245.109 0 m /L glyphshow +253.109 0 m /M glyphshow +266.219 0 m /N glyphshow +276.766 0 m /O glyphshow +287.312 0 m /P glyphshow +296.266 0 m /Q glyphshow +306.812 0 m /R glyphshow +316.719 0 m /S glyphshow +326.625 0 m /T glyphshow +334.625 0 m /U glyphshow +344.859 0 m /V glyphshow +353.812 0 m /W glyphshow +366.922 0 m /X glyphshow +375.547 0 m /Y glyphshow +384.5 0 m /Z glyphshow +grestore +gsave +0 0 m +504 0 l +504 36 l +0 36 l +0 0 l +cl +grestore +/WenQuanYiZenHeiMono 16.000 selectfont +gsave + +52 13.6328 translate +0 rotate +0 0 m /W glyphshow +8 0 m /e glyphshow +16 0 m /n glyphshow +24 0 m /Q glyphshow +32 0 m /u glyphshow +40 0 m /a glyphshow +48 0 m /n glyphshow +56 0 m /Y glyphshow +64 0 m /i glyphshow +72 0 m /space glyphshow +80 0 m /Z glyphshow +88 0 m /e glyphshow +96 0 m /n glyphshow +104 0 m /space glyphshow +112 0 m /H glyphshow +120 0 m /e glyphshow +128 0 m /i glyphshow +136 0 m /space glyphshow +144 0 m /M glyphshow +152 0 m /o glyphshow +160 0 m /n glyphshow +168 0 m /o glyphshow +176 0 m /colon glyphshow +184 0 m /space glyphshow +192 0 m /A glyphshow +200 0 m /B glyphshow +208 0 m /C glyphshow +216 0 m /D glyphshow +224 0 m /E glyphshow +232 0 m /F glyphshow +240 0 m /G glyphshow +248 0 m /H glyphshow +256 0 m /I glyphshow +264 0 m /J glyphshow +272 0 m /K glyphshow +280 0 m /L glyphshow +288 0 m /M glyphshow +296 0 m /N glyphshow +304 0 m /O glyphshow +312 0 m /P glyphshow +320 0 m /Q glyphshow +328 0 m /R glyphshow +336 0 m /S glyphshow +344 0 m /T glyphshow +352 0 m /U glyphshow +360 0 m /V glyphshow +368 0 m /W glyphshow +376 0 m /X glyphshow +384 0 m /Y glyphshow +392 0 m /Z glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/test_backend_pdf.py b/lib/matplotlib/tests/test_backend_pdf.py index f126fb543e78..c2b8d780ab8f 100644 --- a/lib/matplotlib/tests/test_backend_pdf.py +++ b/lib/matplotlib/tests/test_backend_pdf.py @@ -3,6 +3,7 @@ import io import os from pathlib import Path +import string import numpy as np import pytest @@ -363,7 +364,7 @@ def test_glyphs_subset(): nosubfont.set_text(chars) # subsetted FT2Font - with get_glyphs_subset(fpath, chars) as subset: + with get_glyphs_subset(fm.FontPath(fpath, 0), chars) as subset: subfont = FT2Font(font_as_file(subset)) subfont.set_text(chars) @@ -402,6 +403,38 @@ def test_multi_font_type42(): horizontalalignment='center', verticalalignment='center') +@image_comparison(['ttc_type3.pdf'], style='mpl20') +def test_ttc_type3(): + fp = fm.FontProperties(family=['WenQuanYi Zen Hei']) + if Path(fm.findfont(fp)).name != 'wqy-zenhei.ttc': + pytest.skip('Font wqy-zenhei.ttc may be missing') + + fonts = ['WenQuanYi Zen Hei', 'WenQuanYi Zen Hei Mono'] + plt.rc('font', size=16) + plt.rc('pdf', fonttype=3) + + figs = plt.figure(figsize=(7, len(fonts) / 2)).subfigures(len(fonts)) + for font, fig in zip(fonts, figs): + fig.text(0.5, 0.5, f'{font}: {string.ascii_uppercase}', font=font, + horizontalalignment='center', verticalalignment='center') + + +@image_comparison(['ttc_type42.pdf'], style='mpl20') +def test_ttc_type42(): + fp = fm.FontProperties(family=['WenQuanYi Zen Hei']) + if Path(fm.findfont(fp)).name != 'wqy-zenhei.ttc': + pytest.skip('Font wqy-zenhei.ttc may be missing') + + fonts = ['WenQuanYi Zen Hei', 'WenQuanYi Zen Hei Mono'] + plt.rc('font', size=16) + plt.rc('pdf', fonttype=42) + + figs = plt.figure(figsize=(7, len(fonts) / 2)).subfigures(len(fonts)) + for font, fig in zip(fonts, figs): + fig.text(0.5, 0.5, f'{font}: {string.ascii_uppercase}', font=font, + horizontalalignment='center', verticalalignment='center') + + @pytest.mark.parametrize('family_name, file_name', [("Noto Sans", "NotoSans-Regular.otf"), ("FreeMono", "FreeMono.otf")]) diff --git a/lib/matplotlib/tests/test_backend_ps.py b/lib/matplotlib/tests/test_backend_ps.py index f5ec85005079..5fc97c14188b 100644 --- a/lib/matplotlib/tests/test_backend_ps.py +++ b/lib/matplotlib/tests/test_backend_ps.py @@ -1,12 +1,14 @@ from collections import Counter import io +from pathlib import Path import re +import string import tempfile import numpy as np import pytest -from matplotlib import cbook, path, patheffects +from matplotlib import cbook, font_manager, path, patheffects from matplotlib.figure import Figure from matplotlib.patches import Ellipse from matplotlib.testing import _gen_multi_font_text @@ -340,6 +342,38 @@ def test_multi_font_type42(): horizontalalignment='center', verticalalignment='center') +@image_comparison(['ttc_type3.eps'], style='mpl20') +def test_ttc_type3(): + fp = font_manager.FontProperties(family=['WenQuanYi Zen Hei']) + if Path(font_manager.findfont(fp)).name != 'wqy-zenhei.ttc': + pytest.skip('Font wqy-zenhei.ttc may be missing') + + fonts = ['WenQuanYi Zen Hei', 'WenQuanYi Zen Hei Mono'] + plt.rc('font', size=16) + plt.rc('pdf', fonttype=3) + + figs = plt.figure(figsize=(7, len(fonts) / 2)).subfigures(len(fonts)) + for font, fig in zip(fonts, figs): + fig.text(0.5, 0.5, f'{font}: {string.ascii_uppercase}', font=font, + horizontalalignment='center', verticalalignment='center') + + +@image_comparison(['ttc_type42.eps'], style='mpl20') +def test_ttc_type42(): + fp = font_manager.FontProperties(family=['WenQuanYi Zen Hei']) + if Path(font_manager.findfont(fp)).name != 'wqy-zenhei.ttc': + pytest.skip('Font wqy-zenhei.ttc may be missing') + + fonts = ['WenQuanYi Zen Hei', 'WenQuanYi Zen Hei Mono'] + plt.rc('font', size=16) + plt.rc('pdf', fonttype=42) + + figs = plt.figure(figsize=(7, len(fonts) / 2)).subfigures(len(fonts)) + for font, fig in zip(fonts, figs): + fig.text(0.5, 0.5, f'{font}: {string.ascii_uppercase}', font=font, + horizontalalignment='center', verticalalignment='center') + + @image_comparison(["scatter.eps"]) def test_path_collection(): rng = np.random.default_rng(19680801) From d86660b4ab1c44af543b42e1dbd5da3e594b053c Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 25 Jul 2025 19:53:21 -0400 Subject: [PATCH 6/6] pgf: Support any font in a collection Note, this only has an effect if set as the global font. Otherwise, just the font name is recorded, and the TeX engine's normal lookup is performed. --- lib/matplotlib/backends/backend_pgf.py | 25 +++++++++--------- .../test_backend_pgf/ttc_pgf.pdf | Bin 0 -> 15526 bytes lib/matplotlib/tests/test_backend_pgf.py | 20 ++++++++++++++ 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.pdf diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 48b6e8ac152c..ab9782b369a3 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -38,9 +38,17 @@ def _get_preamble(): """Prepare a LaTeX preamble based on the rcParams configuration.""" - font_size_pt = FontProperties( - size=mpl.rcParams["font.size"] - ).get_size_in_points() + def _to_fontspec(): + for command, family in [("setmainfont", "serif"), + ("setsansfont", "sans\\-serif"), + ("setmonofont", "monospace")]: + font_path = fm.findfont(family) + path = pathlib.Path(font_path) + yield r" \%s{%s}[Path=\detokenize{%s/}%s]" % ( + command, path.name, path.parent.as_posix(), + f',FontIndex={font_path.face_index:d}' if path.suffix == '.ttc' else '') + + font_size_pt = FontProperties(size=mpl.rcParams["font.size"]).get_size_in_points() return "\n".join([ # Remove Matplotlib's custom command \mathdefault. (Not using # \mathnormal instead since this looks odd with Computer Modern.) @@ -63,15 +71,8 @@ def _get_preamble(): *([ r"\ifdefined\pdftexversion\else % non-pdftex case.", r" \usepackage{fontspec}", - ] + [ - r" \%s{%s}[Path=\detokenize{%s/}]" - % (command, path.name, path.parent.as_posix()) - for command, path in zip( - ["setmainfont", "setsansfont", "setmonofont"], - [pathlib.Path(fm.findfont(family)) - for family in ["serif", "sans\\-serif", "monospace"]] - ) - ] + [r"\fi"] if mpl.rcParams["pgf.rcfonts"] else []), + *_to_fontspec(), + r"\fi"] if mpl.rcParams["pgf.rcfonts"] else []), # Documented as "must come last". mpl.texmanager._usepackage_if_not_loaded("underscore", option="strings"), ]) diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5d695e734577100ab881040016fbbdb0d76a016a GIT binary patch literal 15526 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 K