31
31
32
32
import numpy as np
33
33
34
- from matplotlib import _api , cbook
34
+ from matplotlib import _api , cbook , font_manager
35
35
36
36
_log = logging .getLogger (__name__ )
37
37
@@ -71,8 +71,8 @@ class Text(namedtuple('Text', 'x y font glyph width')):
71
71
*glyph*, and *width* attributes are kept public for back-compatibility,
72
72
but users wanting to draw the glyph themselves are encouraged to instead
73
73
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 `.
76
76
"""
77
77
78
78
def _get_pdftexmap_entry (self ):
@@ -105,6 +105,14 @@ def font_effects(self):
105
105
return self ._get_pdftexmap_entry ().effects
106
106
107
107
@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.
108
116
def glyph_name_or_index (self ):
109
117
"""
110
118
Either the glyph name or the native charmap glyph index.
@@ -579,7 +587,7 @@ class DviFont:
579
587
Size of the font in Adobe points, converted from the slightly
580
588
smaller TeX points.
581
589
"""
582
- __slots__ = ('texname' , 'size' , '_scale' , '_vf' , '_tfm' )
590
+ __slots__ = ('texname' , 'size' , '_scale' , '_vf' , '_tfm' , '_encoding' )
583
591
584
592
def __init__ (self , scale , tfm , texname , vf ):
585
593
_api .check_isinstance (bytes , texname = texname )
@@ -588,6 +596,7 @@ def __init__(self, scale, tfm, texname, vf):
588
596
self .texname = texname
589
597
self ._vf = vf
590
598
self .size = scale * (72.0 / (72.27 * 2 ** 16 ))
599
+ self ._encoding = None
591
600
592
601
widths = _api .deprecated ("3.11" )(property (lambda self : [
593
602
(1000 * self ._tfm .width .get (char , 0 )) >> 20
@@ -630,6 +639,33 @@ def _height_depth_of(self, char):
630
639
hd [- 1 ] = 0
631
640
return hd
632
641
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
+
633
669
634
670
class Vf (Dvi ):
635
671
r"""
@@ -1023,8 +1059,7 @@ def _parse_enc(path):
1023
1059
Returns
1024
1060
-------
1025
1061
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.
1028
1063
"""
1029
1064
no_comments = re .sub ("%.*" , "" , Path (path ).read_text (encoding = "ascii" ))
1030
1065
array = re .search (r"(?s)\[(.*)\]" , no_comments ).group (1 )
@@ -1156,12 +1191,7 @@ def _print_fields(*args):
1156
1191
face = FT2Font (fontpath )
1157
1192
_print_fields ("x" , "y" , "glyph" , "chr" , "w" )
1158
1193
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 ))
1165
1195
_print_fields (text .x , text .y , text .glyph , glyph_str , text .width )
1166
1196
if page .boxes :
1167
1197
print ("--- BOXES ---" )
0 commit comments