15
15
from cStringIO import StringIO
16
16
from datetime import datetime
17
17
from math import ceil , cos , floor , pi , sin
18
+ import sets
18
19
19
20
from matplotlib import __version__ , rcParams , agg , get_data_path
20
21
from matplotlib ._pylab_helpers import Gcf
29
30
from matplotlib .mathtext import math_parse_s_pdf
30
31
from matplotlib .numerix import Float32 , UInt8 , fromstring , arange , infinity , isnan , asarray
31
32
from matplotlib .transforms import Bbox
33
+ from matplotlib import ttconv
32
34
33
35
# Overview
34
36
#
@@ -453,7 +455,8 @@ def writeFonts(self):
453
455
if filename .endswith ('.afm' ):
454
456
fontdictObject = self ._write_afm_font (filename )
455
457
else :
456
- fontdictObject = self .embedTTF (filename )
458
+ fontdictObject = self .embedTTF (
459
+ filename , self .used_characters [filename ])
457
460
fonts [Fx ] = fontdictObject
458
461
#print >>sys.stderr, filename
459
462
self .writeObject (self .fontObject , fonts )
@@ -471,10 +474,11 @@ def _write_afm_font(self, filename):
471
474
self .writeObject (fontdictObject , fontdict )
472
475
return fontdictObject
473
476
474
- def embedTTF (self , filename ):
477
+ def embedTTF (self , filename , characters ):
475
478
"""Embed the TTF font from the named file into the document."""
476
479
477
480
font = FT2Font (str (filename ))
481
+ fonttype = rcParams ['pdf.fonttype' ]
478
482
479
483
def cvt (length , upe = font .units_per_EM , nearest = True ):
480
484
"Convert font coordinates to PDF glyph coordinates"
@@ -515,21 +519,36 @@ def get_char_width(charcode):
515
519
516
520
firstchar , lastchar = 0 , 255
517
521
widths = [ get_char_width (charcode ) for charcode in range (firstchar , lastchar + 1 ) ]
522
+ font_bbox = [ cvt (x , nearest = False ) for x in font .bbox ]
518
523
519
524
widthsObject = self .reserveObject ('font widths' )
520
525
fontdescObject = self .reserveObject ('font descriptor' )
521
526
# TODO: "WinAnsiEncoding" could become a parameter of PdfFile. The PDF encoding
522
527
# "WinAnsiEncoding" matches the Python enconding "cp1252" used in method
523
528
# RendererPdf.draw_text and RendererPdf.get_text_width_height to encode Unicode strings.
524
529
fontdict = { 'Type' : Name ('Font' ),
525
- 'Subtype' : Name ('TrueType' ),
526
- 'Encoding' : Name ('WinAnsiEncoding' ),
527
530
'BaseFont' : ps_name ,
528
531
'FirstChar' : firstchar ,
529
532
'LastChar' : lastchar ,
530
533
'Widths' : widthsObject ,
531
534
'FontDescriptor' : fontdescObject }
532
535
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
+
533
552
flags = 0
534
553
symbolic = False #ps_name.name in ('Cmsy10', 'Cmmi10', 'Cmex10')
535
554
if ff & FIXED_WIDTH : flags |= 1 << 0
@@ -551,11 +570,13 @@ def get_char_width(charcode):
551
570
'CapHeight' : cvt (pclt ['capHeight' ], nearest = False ),
552
571
'XHeight' : cvt (pclt ['xHeight' ]),
553
572
'ItalicAngle' : post ['italicAngle' ][1 ], # ???
554
- 'FontFile2' : self .reserveObject ('font file' ),
555
573
'MaxWidth' : max (widths ),
556
574
'StemV' : 0 # ???
557
575
}
558
576
577
+ if fonttype == 42 :
578
+ descriptor ['FontFile2' ] = self .reserveObject ('font file' )
579
+
559
580
# Other FontDescriptor keys include:
560
581
# /FontFamily /Times (optional)
561
582
# /FontStretch /Normal (optional)
@@ -584,24 +605,57 @@ def get_char_width(charcode):
584
605
585
606
widths = [ firstchar , widths ]
586
607
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
+
587
655
fontdictObject = self .reserveObject ('font dictionary' )
588
- length1Object = self .reserveObject ('decoded length of a font' )
589
656
self .writeObject (fontdictObject , fontdict )
590
657
self .writeObject (widthsObject , widths )
591
658
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 )
605
659
606
660
return fontdictObject
607
661
@@ -849,6 +903,7 @@ def __init__(self, file):
849
903
self .gc = self .new_gc ()
850
904
self .truetype_font_cache = {}
851
905
self .afm_font_cache = {}
906
+ self .file .used_characters = self .used_characters = {}
852
907
853
908
def finalize (self ):
854
909
self .gc .finalize ()
@@ -865,6 +920,16 @@ def check_gc(self, gc, fillcolor=None):
865
920
# Restore gc to avoid unwanted side effects
866
921
gc ._fillcolor = orig_fill
867
922
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
+
868
933
def draw_arc (self , gcEdge , rgbFace , x , y , width , height ,
869
934
angle1 , angle2 , rotation ):
870
935
"""
@@ -1018,7 +1083,7 @@ def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0):
1018
1083
def draw_mathtext (self , gc , x , y , s , prop , angle ):
1019
1084
# TODO: fix positioning and encoding
1020
1085
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 )
1022
1087
1023
1088
self .check_gc (gc , gc ._rgb )
1024
1089
self .file .output (Op .begin_text )
@@ -1114,6 +1179,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
1114
1179
y -= b * fontsize / 1000
1115
1180
else :
1116
1181
font = self ._get_font_ttf (prop )
1182
+ self .track_characters (font , s )
1117
1183
font .set_text (s , 0.0 )
1118
1184
y += font .get_descent () / 64.0
1119
1185
@@ -1131,7 +1197,8 @@ def get_text_width_height(self, s, prop, ismath):
1131
1197
1132
1198
if ismath :
1133
1199
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 )
1135
1202
1136
1203
elif rcParams ['pdf.use14corefonts' ]:
1137
1204
font = self ._get_font_afm (prop )
0 commit comments