@@ -88,14 +88,16 @@ def _move_path_to_path_or_stream(src, dst):
8888 shutil .move (src , dst , copy_function = shutil .copyfile )
8989
9090
91- def _font_to_ps_type3 (font_path , glyph_indices ):
91+ def _font_to_ps_type3 (font_path , subset_index , glyph_indices ):
9292 """
9393 Subset *glyphs_indices* from the font at *font_path* into a Type 3 font.
9494
9595 Parameters
9696 ----------
9797 font_path : path-like
9898 Path to the font to be subsetted.
99+ subset_index : int
100+ The subset of the above font being created.
99101 glyph_indices : set[int]
100102 The glyphs to include in the subsetted font.
101103
@@ -111,15 +113,15 @@ def _font_to_ps_type3(font_path, glyph_indices):
111113 %!PS-Adobe-3.0 Resource-Font
112114%%Creator: Converted from TrueType to Type 3 by Matplotlib.
11311510 dict begin
114- /FontName /{font_name} def
116+ /FontName /{font_name}-{subset} def
115117/PaintType 0 def
116118/FontMatrix [{inv_units_per_em} 0 0 {inv_units_per_em} 0 0] def
117119/FontBBox [{bbox}] def
118120/FontType 3 def
119121/Encoding [{encoding}] def
120122/CharStrings {num_glyphs} dict dup begin
121123/.notdef 0 def
122- """ .format (font_name = font .postscript_name ,
124+ """ .format (font_name = font .postscript_name , subset = subset_index ,
123125 inv_units_per_em = 1 / font .units_per_EM ,
124126 bbox = " " .join (map (str , font .bbox )),
125127 encoding = " " .join (f"/{ font .get_glyph_name (glyph_index )} "
@@ -168,20 +170,22 @@ def _font_to_ps_type3(font_path, glyph_indices):
168170 return preamble + "\n " .join (entries ) + postamble
169171
170172
171- def _font_to_ps_type42 (font_path , glyph_indices , fh ):
173+ def _font_to_ps_type42 (font_path , subset_index , glyph_indices , fh ):
172174 """
173175 Subset *glyph_indices* from the font at *font_path* into a Type 42 font at *fh*.
174176
175177 Parameters
176178 ----------
177179 font_path : path-like
178180 Path to the font to be subsetted.
181+ subset_index : int
182+ The subset of the above font being created.
179183 glyph_indices : set[int]
180184 The glyphs to include in the subsetted font.
181185 fh : file-like
182186 Where to write the font.
183187 """
184- _log .debug ("SUBSET %s characters: %s" , font_path , glyph_indices )
188+ _log .debug ("SUBSET %s:%d characters: %s" , font_path , subset_index , glyph_indices )
185189 try :
186190 kw = {}
187191 # fix this once we support loading more fonts from a collection
@@ -192,25 +196,27 @@ def _font_to_ps_type42(font_path, glyph_indices, fh):
192196 _backend_pdf_ps .get_glyphs_subset (font_path , glyph_indices ) as subset ):
193197 fontdata = _backend_pdf_ps .font_as_file (subset ).getvalue ()
194198 _log .debug (
195- "SUBSET %s %d -> %d" , font_path , os . stat ( font_path ). st_size ,
196- len (fontdata )
199+ "SUBSET %s:%d %d -> %d" , font_path , subset_index ,
200+ os . stat ( font_path ). st_size , len (fontdata )
197201 )
198- fh .write (_serialize_type42 (font , subset , fontdata ))
202+ fh .write (_serialize_type42 (font , subset_index , subset , fontdata ))
199203 except RuntimeError :
200204 _log .warning (
201205 "The PostScript backend does not currently support the selected font (%s)." ,
202206 font_path )
203207 raise
204208
205209
206- def _serialize_type42 (font , subset , fontdata ):
210+ def _serialize_type42 (font , subset_index , subset , fontdata ):
207211 """
208212 Output a PostScript Type-42 format representation of font
209213
210214 Parameters
211215 ----------
212216 font : fontTools.ttLib.ttFont.TTFont
213217 The original font object
218+ subset_index : int
219+ The subset of the above font to be created.
214220 subset : fontTools.ttLib.ttFont.TTFont
215221 The subset font object
216222 fontdata : bytes
@@ -231,7 +237,7 @@ def _serialize_type42(font, subset, fontdata):
231237 10 dict begin
232238 /FontType 42 def
233239 /FontMatrix [1 0 0 1 0 0] def
234- /FontName /{ name .getDebugName (6 )} def
240+ /FontName /{ name .getDebugName (6 )} - { subset_index } def
235241 /FontInfo 7 dict dup begin
236242 /FullName ({ name .getDebugName (4 )} ) def
237243 /FamilyName ({ name .getDebugName (1 )} ) def
@@ -425,7 +431,8 @@ def __init__(self, width, height, pswriter, imagedpi=72):
425431 self ._clip_paths = {}
426432 self ._path_collection_id = 0
427433
428- self ._character_tracker = _backend_pdf_ps .CharacterTracker ()
434+ self ._character_tracker = _backend_pdf_ps .CharacterTracker (
435+ _backend_pdf_ps ._FONT_MAX_GLYPH .get (mpl .rcParams ['ps.fonttype' ], 0 ))
429436 self ._logwarn_once = functools .cache (_log .warning )
430437
431438 def _is_transparent (self , rgb_or_rgba ):
@@ -793,12 +800,16 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
793800 else :
794801 language = mtext .get_language () if mtext is not None else None
795802 font = self ._get_font_ttf (prop )
796- self ._character_tracker .track (font , s )
797803 for item in _text_helpers .layout (s , font , language = language ):
804+ # NOTE: We ignore the character code in the subset, because PS uses the
805+ # glyph name to write text. The subset is only used to ensure that each
806+ # one does not overflow format limits.
807+ subset , _ = self ._character_tracker .track_glyph (
808+ item .ft_object , item .char , item .glyph_index )
798809 ps_name = (item .ft_object .postscript_name
799810 .encode ("ascii" , "replace" ).decode ("ascii" ))
800811 glyph_name = item .ft_object .get_glyph_name (item .glyph_index )
801- stream .append ((ps_name , item .x , glyph_name ))
812+ stream .append ((f' { ps_name } - { subset } ' , item .x , glyph_name ))
802813 self .set_color (* gc .get_rgb ())
803814
804815 for ps_name , group in itertools . \
@@ -827,11 +838,15 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
827838 f"{ angle :g} rotate\n " )
828839 lastfont = None
829840 for font , fontsize , ccode , glyph_index , ox , oy in glyphs :
830- self ._character_tracker .track_glyph (font , ccode , glyph_index )
831- if (font .postscript_name , fontsize ) != lastfont :
832- lastfont = font .postscript_name , fontsize
841+ # NOTE: We ignore the character code in the subset, because PS uses the
842+ # glyph name to write text. The subset is only used to ensure that each one
843+ # does not overflow format limits.
844+ subset , _ = self ._character_tracker .track_glyph (
845+ font , ccode , glyph_index )
846+ if (font .postscript_name , subset , fontsize ) != lastfont :
847+ lastfont = font .postscript_name , subset , fontsize
833848 self ._pswriter .write (
834- f"/{ font .postscript_name } { fontsize } selectfont\n " )
849+ f"/{ font .postscript_name } - { subset } { fontsize } selectfont\n " )
835850 glyph_name = font .get_glyph_name (glyph_index )
836851 self ._pswriter .write (
837852 f"{ ox :g} { oy :g} moveto\n "
@@ -1071,18 +1086,15 @@ def print_figure_impl(fh):
10711086 print ("\n " .join (_psDefs ), file = fh )
10721087 if not mpl .rcParams ['ps.useafm' ]:
10731088 for font , subsets in ps_renderer ._character_tracker .used .items ():
1074- for charmap in subsets :
1089+ for subset , charmap in enumerate ( subsets ) :
10751090 if not charmap :
10761091 continue
10771092 fonttype = mpl .rcParams ['ps.fonttype' ]
1078- # Can't use more than 255 chars from a single Type 3 font.
1079- if len (charmap ) > 255 :
1080- fonttype = 42
10811093 fh .flush ()
10821094 if fonttype == 3 :
1083- fh .write (_font_to_ps_type3 (font , charmap .values ()))
1095+ fh .write (_font_to_ps_type3 (font , subset , charmap .values ()))
10841096 else : # Type 42 only.
1085- _font_to_ps_type42 (font , charmap .values (), fh )
1097+ _font_to_ps_type42 (font , subset , charmap .values (), fh )
10861098 print ("end" , file = fh )
10871099 print ("%%EndProlog" , file = fh )
10881100
0 commit comments