3131
3232import numpy as np
3333
34- from matplotlib import _api , cbook
34+ from matplotlib import _api , cbook , font_manager
3535
3636_log = logging .getLogger (__name__ )
3737
@@ -71,8 +71,8 @@ class Text(namedtuple('Text', 'x y font glyph width')):
7171 *glyph*, and *width* attributes are kept public for back-compatibility,
7272 but users wanting to draw the glyph themselves are encouraged to instead
7373 load the font specified by `font_path` at `font_size`, warp it with the
74- effects specified by `font_effects`, and load the glyph specified by
75- `glyph_name_or_index `.
74+ effects specified by `font_effects`, and load the glyph at the FreeType
75+ glyph `index `.
7676 """
7777
7878 def _get_pdftexmap_entry (self ):
@@ -105,6 +105,14 @@ def font_effects(self):
105105 return self ._get_pdftexmap_entry ().effects
106106
107107 @property
108+ def index (self ):
109+ """
110+ The FreeType index of this glyph (that can be passed to FT_Load_Glyph).
111+ """
112+ # See DviFont._index_dvi_to_freetype for details on the index mapping.
113+ return self .font ._index_dvi_to_freetype (self .glyph )
114+
115+ @property # To be deprecated together with font_size, font_effects.
108116 def glyph_name_or_index (self ):
109117 """
110118 Either the glyph name or the native charmap glyph index.
@@ -579,7 +587,7 @@ class DviFont:
579587 Size of the font in Adobe points, converted from the slightly
580588 smaller TeX points.
581589 """
582- __slots__ = ('texname' , 'size' , '_scale' , '_vf' , '_tfm' )
590+ __slots__ = ('texname' , 'size' , '_scale' , '_vf' , '_tfm' , '_encoding' )
583591
584592 def __init__ (self , scale , tfm , texname , vf ):
585593 _api .check_isinstance (bytes , texname = texname )
@@ -588,6 +596,7 @@ def __init__(self, scale, tfm, texname, vf):
588596 self .texname = texname
589597 self ._vf = vf
590598 self .size = scale * (72.0 / (72.27 * 2 ** 16 ))
599+ self ._encoding = None
591600
592601 widths = _api .deprecated ("3.11" )(property (lambda self : [
593602 (1000 * self ._tfm .width .get (char , 0 )) >> 20
@@ -630,6 +639,33 @@ def _height_depth_of(self, char):
630639 hd [- 1 ] = 0
631640 return hd
632641
642+ def _index_dvi_to_freetype (self , idx ):
643+ """Convert dvi glyph indices to FreeType ones."""
644+ # Glyphs indices stored in the dvi file map to FreeType glyph indices
645+ # (i.e., which can be passed to FT_Load_Glyph) in various ways:
646+ # - if pdftex.map specifies an ".enc" file for the font, that file maps
647+ # dvi indices to Adobe glyph names, which can then be converted to
648+ # FreeType glyph indices with FT_Get_Name_Index.
649+ # - if no ".enc" file is specified, then the font must be a Type 1
650+ # font, and dvi indices directly index into the font's CharStrings
651+ # vector.
652+ # - (xetex & luatex, currently unsupported, can also declare "native
653+ # fonts", for which dvi indices are equal to FreeType indices.)
654+ if self ._encoding is None :
655+ psfont = PsfontsMap (find_tex_file ("pdftex.map" ))[self .texname ]
656+ if psfont .filename is None :
657+ raise ValueError ("No usable font file found for {} ({}); "
658+ "the font may lack a Type-1 version"
659+ .format (psfont .psname .decode ("ascii" ),
660+ psfont .texname .decode ("ascii" )))
661+ face = font_manager .get_font (psfont .filename )
662+ if psfont .encoding :
663+ self ._encoding = [face .get_name_index (name )
664+ for name in _parse_enc (psfont .encoding )]
665+ else :
666+ self ._encoding = face ._get_type1_encoding_vector ()
667+ return self ._encoding [idx ]
668+
633669
634670class Vf (Dvi ):
635671 r"""
@@ -1023,8 +1059,7 @@ def _parse_enc(path):
10231059 Returns
10241060 -------
10251061 list
1026- The nth entry of the list is the PostScript glyph name of the nth
1027- glyph.
1062+ The nth list item is the PostScript glyph name of the nth glyph.
10281063 """
10291064 no_comments = re .sub ("%.*" , "" , Path (path ).read_text (encoding = "ascii" ))
10301065 array = re .search (r"(?s)\[(.*)\]" , no_comments ).group (1 )
@@ -1156,12 +1191,7 @@ def _print_fields(*args):
11561191 face = FT2Font (fontpath )
11571192 _print_fields ("x" , "y" , "glyph" , "chr" , "w" )
11581193 for text in group :
1159- if psfont .encoding :
1160- glyph_name = _parse_enc (psfont .encoding )[text .glyph ]
1161- else :
1162- encoding_vector = face ._get_type1_encoding_vector ()
1163- glyph_name = face .get_glyph_name (encoding_vector [text .glyph ])
1164- glyph_str = fontTools .agl .toUnicode (glyph_name )
1194+ glyph_str = fontTools .agl .toUnicode (face .get_glyph_name (text .index ))
11651195 _print_fields (text .x , text .y , text .glyph , glyph_str , text .width )
11661196 if page .boxes :
11671197 print ("--- BOXES ---" )
0 commit comments