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_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/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/font_manager.py b/lib/matplotlib/font_manager.py index 79e088b85998..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: """ @@ -319,6 +374,7 @@ class FontEntry: """ fname: str = '' + index: int = 0 name: str = '' style: str = 'normal' variant: str = 'normal' @@ -465,7 +521,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 +592,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 +1126,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 +1191,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 @@ -1320,7 +1381,7 @@ def findfont(self, prop, fontext='ttf', directory=None, Returns ------- - str + FontPath The filename of the best matching font. Notes @@ -1390,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 @@ -1536,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") @@ -1556,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 @@ -1576,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 ) @@ -1611,10 +1673,11 @@ 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, FontPath], \ +str, bytes, os.PathLike, FontPath 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,10 +1689,16 @@ def get_font(font_filepaths, hinting_factor=None): `.ft2font.FT2Font` """ - if isinstance(font_filepaths, (str, Path, bytes)): - 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 e865f67384cd..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 @@ -24,11 +24,25 @@ 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]: ... + +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 = ... + index: int = ... name: str = ... style: str = ... variant: str = ... @@ -50,7 +64,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 +86,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 +97,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 +107,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: ... @@ -115,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 | Path | bytes] | str | Path | bytes, + font_filepaths: Iterable[str | bytes | os.PathLike | FontPath] | str | bytes | os.PathLike | FontPath, hinting_factor: int | None = ..., ) -> ft2font.FT2Font: ... diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 5257893b380a..eea180e4c7b5 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,9 +188,10 @@ class _SfntPcltDict(TypedDict): class FT2Font(Buffer): def __init__( self, - filename: str | BinaryIO, + filename: str | bytes | PathLike | BinaryIO, hinting_factor: int = ..., *, + face_index: int = ..., _fallback_list: list[FT2Font] | None = ..., _kerning_factor: int | None = ... ) -> None: ... @@ -247,9 +249,11 @@ 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: ... + def fname(self) -> str | bytes: ... @property def height(self) -> int: ... @property 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 000000000000..a3fad0172364 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf differ 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 000000000000..d43f233ef4e6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf differ 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 000000000000..5d695e734577 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.pdf differ 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_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index e218a81cdceb..e5b73c9450f3 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -1,7 +1,9 @@ import datetime from io import BytesIO import os +from pathlib import Path import shutil +import string import numpy as np from packaging.version import parse as parse_version @@ -9,6 +11,7 @@ import matplotlib as mpl import matplotlib.pyplot as plt +from matplotlib.font_manager import FontProperties, findfont from matplotlib.testing import _has_tex_package, _check_for_pgf from matplotlib.testing.exceptions import ImageComparisonFailure from matplotlib.testing.compare import compare_images @@ -330,6 +333,23 @@ def test_png_transparency(): # Actually, also just testing that png works. assert (t[..., 3] == 0).all() # fully transparent. +@needs_pgf_xelatex +@pytest.mark.backend('pgf') +@image_comparison(['ttc_pgf.pdf'], style='mpl20') +def test_ttc_output(): + fp = FontProperties(family=['WenQuanYi Zen Hei']) + if Path(findfont(fp)).name != 'wqy-zenhei.ttc': + pytest.skip('Font wqy-zenhei.ttc may be missing') + + fonts = {'sans-serif': 'WenQuanYi Zen Hei', 'monospace': 'WenQuanYi Zen Hei Mono'} + plt.rc('font', size=16, **fonts) + + figs = plt.figure(figsize=(7, len(fonts) / 2)).subfigures(len(fonts)) + for font, fig in zip(fonts.values(), figs): + fig.text(0.5, 0.5, f'{font}: {string.ascii_uppercase}', font=font, + horizontalalignment='center', verticalalignment='center') + + @needs_pgf_xelatex def test_unknown_font(caplog): with caplog.at_level("WARNING"): 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) diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index b15647644e04..cc8ae03a9f97 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 @@ -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': @@ -117,8 +149,17 @@ 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"]: + 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"]: @@ -137,6 +178,34 @@ 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 + 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, + PathLikeClass(file_str), PathLikeClass(file_bytes)]) + assert font.fname == file_str + + def test_find_invalid(tmp_path): with pytest.raises(FileNotFoundError): @@ -148,11 +217,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') @@ -342,6 +406,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))) diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 5dd96ce9cafe..7ffc83f75e75 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'): @@ -176,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 5ba4bec36874..d8c965c5d31b 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -420,12 +420,15 @@ 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 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)); @@ -481,7 +488,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 { @@ -499,21 +509,21 @@ 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); 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; } } @@ -1606,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__) @@ -1679,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) {