1515from cStringIO import StringIO
1616from datetime import datetime
1717from math import ceil , cos , floor , pi , sin
18+ import sets
1819
1920from matplotlib import __version__ , rcParams , agg , get_data_path
2021from matplotlib ._pylab_helpers import Gcf
2930from matplotlib .mathtext import math_parse_s_pdf
3031from matplotlib .numerix import Float32 , UInt8 , fromstring , arange , infinity , isnan , asarray
3132from matplotlib .transforms import Bbox
33+ from matplotlib import ttconv
3234
3335# Overview
3436#
@@ -453,7 +455,8 @@ def writeFonts(self):
453455 if filename .endswith ('.afm' ):
454456 fontdictObject = self ._write_afm_font (filename )
455457 else :
456- fontdictObject = self .embedTTF (filename )
458+ fontdictObject = self .embedTTF (
459+ filename , self .used_characters [filename ])
457460 fonts [Fx ] = fontdictObject
458461 #print >>sys.stderr, filename
459462 self .writeObject (self .fontObject , fonts )
@@ -471,10 +474,11 @@ def _write_afm_font(self, filename):
471474 self .writeObject (fontdictObject , fontdict )
472475 return fontdictObject
473476
474- def embedTTF (self , filename ):
477+ def embedTTF (self , filename , characters ):
475478 """Embed the TTF font from the named file into the document."""
476479
477480 font = FT2Font (str (filename ))
481+ fonttype = rcParams ['pdf.fonttype' ]
478482
479483 def cvt (length , upe = font .units_per_EM , nearest = True ):
480484 "Convert font coordinates to PDF glyph coordinates"
@@ -515,21 +519,36 @@ def get_char_width(charcode):
515519
516520 firstchar , lastchar = 0 , 255
517521 widths = [ get_char_width (charcode ) for charcode in range (firstchar , lastchar + 1 ) ]
522+ font_bbox = [ cvt (x , nearest = False ) for x in font .bbox ]
518523
519524 widthsObject = self .reserveObject ('font widths' )
520525 fontdescObject = self .reserveObject ('font descriptor' )
521526 # TODO: "WinAnsiEncoding" could become a parameter of PdfFile. The PDF encoding
522527 # "WinAnsiEncoding" matches the Python enconding "cp1252" used in method
523528 # RendererPdf.draw_text and RendererPdf.get_text_width_height to encode Unicode strings.
524529 fontdict = { 'Type' : Name ('Font' ),
525- 'Subtype' : Name ('TrueType' ),
526- 'Encoding' : Name ('WinAnsiEncoding' ),
527530 'BaseFont' : ps_name ,
528531 'FirstChar' : firstchar ,
529532 'LastChar' : lastchar ,
530533 'Widths' : widthsObject ,
531534 'FontDescriptor' : fontdescObject }
532535
536+ if fonttype == 3 :
537+ charprocsObject = self .reserveObject ('character procs' )
538+ differencesArray = []
539+ fontdict ['Subtype' ] = Name ('Type3' )
540+ fontdict ['Name' ] = ps_name
541+ fontdict ['FontBBox' ] = font_bbox
542+ fontdict ['FontMatrix' ] = [ .001 , 0 , 0 , .001 , 0 , 0 ]
543+ fontdict ['CharProcs' ] = charprocsObject
544+ fontdict ['Encoding' ] = {
545+ 'Type' : Name ('Encoding' ),
546+ 'Differences' : differencesArray }
547+ elif fonttype == 42 :
548+ fontdict ['Subtype' ] = Name ('TrueType' )
549+ fontdict ['Encoding' ] = Name ('WinAnsiEncoding' ),
550+
551+
533552 flags = 0
534553 symbolic = False #ps_name.name in ('Cmsy10', 'Cmmi10', 'Cmex10')
535554 if ff & FIXED_WIDTH : flags |= 1 << 0
@@ -551,11 +570,13 @@ def get_char_width(charcode):
551570 'CapHeight' : cvt (pclt ['capHeight' ], nearest = False ),
552571 'XHeight' : cvt (pclt ['xHeight' ]),
553572 'ItalicAngle' : post ['italicAngle' ][1 ], # ???
554- 'FontFile2' : self .reserveObject ('font file' ),
555573 'MaxWidth' : max (widths ),
556574 'StemV' : 0 # ???
557575 }
558576
577+ if fonttype == 42 :
578+ descriptor ['FontFile2' ] = self .reserveObject ('font file' )
579+
559580 # Other FontDescriptor keys include:
560581 # /FontFamily /Times (optional)
561582 # /FontStretch /Normal (optional)
@@ -584,24 +605,57 @@ def get_char_width(charcode):
584605
585606 widths = [ firstchar , widths ]
586607
608+ if fonttype == 3 :
609+ cmap = font .get_charmap ()
610+ glyph_ids = []
611+ differences = []
612+ for c in characters :
613+ ccode = ord (c )
614+ gind = cmap .get (ccode ) or 0
615+ glyph_ids .append (gind )
616+ differences .append ((ccode , font .get_glyph_name (gind )))
617+ differences .sort ()
618+
619+ last_c = - 256
620+ for c , name in differences :
621+ if c != last_c + 1 :
622+ differencesArray .append (c )
623+ differencesArray .append (Name (name ))
624+ last_c = c
625+
626+ rawcharprocs = ttconv .get_pdf_charprocs (filename , glyph_ids )
627+ charprocs = {}
628+ charprocsRef = {}
629+ for charname , stream in rawcharprocs .items ():
630+ charprocObject = self .reserveObject ('charProc for %s' % name )
631+ self .beginStream (charprocObject .id ,
632+ None ,
633+ {'Length' : len (stream )})
634+ self .currentstream .write (stream )
635+ self .endStream ()
636+ charprocs [charname ] = charprocObject
637+ self .writeObject (charprocsObject , charprocs )
638+
639+ elif fonttype == 42 :
640+ length1Object = self .reserveObject ('decoded length of a font' )
641+ self .beginStream (descriptor ['FontFile2' ].id ,
642+ self .reserveObject ('length of font stream' ),
643+ {'Length1' : length1Object })
644+ fontfile = open (filename , 'rb' )
645+ length1 = 0
646+ while True :
647+ data = fontfile .read (4096 )
648+ if not data : break
649+ length1 += len (data )
650+ self .currentstream .write (data )
651+ fontfile .close ()
652+ self .endStream ()
653+ self .writeObject (length1Object , length1 )
654+
587655 fontdictObject = self .reserveObject ('font dictionary' )
588- length1Object = self .reserveObject ('decoded length of a font' )
589656 self .writeObject (fontdictObject , fontdict )
590657 self .writeObject (widthsObject , widths )
591658 self .writeObject (fontdescObject , descriptor )
592- self .beginStream (descriptor ['FontFile2' ].id ,
593- self .reserveObject ('length of font stream' ),
594- {'Length1' : length1Object })
595- fontfile = open (filename , 'rb' )
596- length1 = 0
597- while True :
598- data = fontfile .read (4096 )
599- if not data : break
600- length1 += len (data )
601- self .currentstream .write (data )
602- fontfile .close ()
603- self .endStream ()
604- self .writeObject (length1Object , length1 )
605659
606660 return fontdictObject
607661
@@ -849,6 +903,7 @@ def __init__(self, file):
849903 self .gc = self .new_gc ()
850904 self .truetype_font_cache = {}
851905 self .afm_font_cache = {}
906+ self .file .used_characters = self .used_characters = {}
852907
853908 def finalize (self ):
854909 self .gc .finalize ()
@@ -865,6 +920,16 @@ def check_gc(self, gc, fillcolor=None):
865920 # Restore gc to avoid unwanted side effects
866921 gc ._fillcolor = orig_fill
867922
923+ def track_characters (self , font , s ):
924+ """Keeps track of which characters are required from
925+ each font."""
926+ if isinstance (font , (str , unicode )):
927+ fname = font
928+ else :
929+ fname = font .fname
930+ used_characters = self .used_characters .setdefault (fname , sets .Set ())
931+ used_characters .update (s )
932+
868933 def draw_arc (self , gcEdge , rgbFace , x , y , width , height ,
869934 angle1 , angle2 , rotation ):
870935 """
@@ -1018,7 +1083,7 @@ def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0):
10181083 def draw_mathtext (self , gc , x , y , s , prop , angle ):
10191084 # TODO: fix positioning and encoding
10201085 fontsize = prop .get_size_in_points ()
1021- width , height , pswriter = math_parse_s_pdf (s , 72 , fontsize )
1086+ width , height , pswriter = math_parse_s_pdf (s , 72 , fontsize , 0 , self . track_characters )
10221087
10231088 self .check_gc (gc , gc ._rgb )
10241089 self .file .output (Op .begin_text )
@@ -1114,6 +1179,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
11141179 y -= b * fontsize / 1000
11151180 else :
11161181 font = self ._get_font_ttf (prop )
1182+ self .track_characters (font , s )
11171183 font .set_text (s , 0.0 )
11181184 y += font .get_descent () / 64.0
11191185
@@ -1131,7 +1197,8 @@ def get_text_width_height(self, s, prop, ismath):
11311197
11321198 if ismath :
11331199 fontsize = prop .get_size_in_points ()
1134- w , h , pswriter = math_parse_s_pdf (s , 72 , fontsize )
1200+ w , h , pswriter = math_parse_s_pdf (
1201+ s , 72 , fontsize , 0 , self .track_characters )
11351202
11361203 elif rcParams ['pdf.use14corefonts' ]:
11371204 font = self ._get_font_afm (prop )
0 commit comments