@@ -84,16 +84,22 @@ def _output(self):
8484 e = 0 # zero depth
8585 else : # glyph
8686 x ,y ,font ,g ,w = elt
87- h = (font .scale * font .tfm .height [g ]) >> 20
88- e = (font .scale * font .tfm .depth [g ]) >> 20
87+ h = _mul2012 (font ._scale , font ._tfm .height [g ])
88+ e = _mul2012 (font ._scale , font ._tfm .depth [g ])
8989 minx = min (minx , x )
9090 miny = min (miny , y - h )
9191 maxx = max (maxx , x + w )
9292 maxy = max (maxy , y + e )
9393 maxy_pure = max (maxy_pure , y )
9494
95+ if self .dpi is None :
96+ # special case for ease of debugging: output raw dvi coordinates
97+ return mpl_cbook .Bunch (text = self .text , boxes = self .boxes ,
98+ width = maxx - minx , height = maxy_pure - miny ,
99+ descent = maxy - maxy_pure )
100+
95101 d = self .dpi / (72.27 * 2 ** 16 ) # from TeX's "scaled points" to dpi units
96- text = [ ((x - minx )* d , (maxy - y )* d , DviFont ( f ) , g , w * d )
102+ text = [ ((x - minx )* d , (maxy - y )* d , f , g , w * d )
97103 for (x ,y ,f ,g ,w ) in self .text ]
98104 boxes = [ ((x - minx )* d , (maxy - y )* d , h * d , w * d ) for (x ,y ,h ,w ) in self .boxes ]
99105
@@ -110,11 +116,11 @@ def _read(self):
110116 while True :
111117 byte = ord (self .file .read (1 ))
112118 self ._dispatch (byte )
113- if self .state == _dvistate .inpage :
114- matplotlib .verbose .report (
115- 'Dvi._read: after %d at %f,%f' %
116- (byte , self .h , self .v ),
117- 'debug-annoying' )
119+ # if self.state == _dvistate.inpage:
120+ # matplotlib.verbose.report(
121+ # 'Dvi._read: after %d at %f,%f' %
122+ # (byte, self.h, self.v),
123+ # 'debug-annoying')
118124 if byte == 140 : # end of page
119125 return True
120126 if self .state == _dvistate .post_post : # end of file
@@ -225,21 +231,11 @@ def _pre(self, i, num, den, mag, comment):
225231 # I think we can assume this is constant
226232 self .state = _dvistate .outer
227233
228- def _width_of (self , char , font ):
229- width = font .tfm .width .get (char , None )
230- if width is not None :
231- return (width * font .scale ) >> 20
232-
233- matplotlib .verbose .report (
234- 'No width for char %d in font %s' % (char , font .name ),
235- 'debug' )
236- return 0
237-
238234 def _set_char (self , char ):
239235 if self .state != _dvistate .inpage :
240236 raise ValueError , "misplaced set_char in dvi file"
241237 self ._put_char (char )
242- self .h += self ._width_of ( char , self . fonts [self .f ])
238+ self .h += self .fonts [self .f ]. _width_of ( char )
243239
244240 def _set_rule (self , a , b ):
245241 if self .state != _dvistate .inpage :
@@ -251,20 +247,33 @@ def _put_char(self, char):
251247 if self .state != _dvistate .inpage :
252248 raise ValueError , "misplaced put_char in dvi file"
253249 font = self .fonts [self .f ]
254- if font .vf is None :
250+ if font ._vf is None :
255251 self .text .append ((self .h , self .v , font , char ,
256- self ._width_of (char , font )))
252+ font ._width_of (char )))
253+ # matplotlib.verbose.report(
254+ # 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char),
255+ # 'debug-annoying')
257256 else :
258- self .text .extend ([(self .h + x , self .v + y , f , g , w )
259- for x , y , f , g , w in font .vf [char ].text ])
260- self .boxes .extend ([(self .h + x , self .v + y , a , b )
261- for x , y , a , b in font .vf [char ].boxes ])
257+ scale = font ._scale
258+ for x , y , f , g , w in font ._vf [char ].text :
259+ newf = DviFont (scale = _mul2012 (scale , f ._scale ),
260+ tfm = f ._tfm , texname = f .texname , vf = f ._vf )
261+ self .text .append ((self .h + _mul2012 (x , scale ),
262+ self .v + _mul2012 (y , scale ),
263+ newf , g , newf ._width_of (g )))
264+ self .boxes .extend ([(self .h + _mul2012 (x , scale ),
265+ self .v + _mul2012 (y , scale ),
266+ _mul2012 (a , scale ), _mul2012 (b , scale ))
267+ for x , y , a , b in font ._vf [char ].boxes ])
262268
263269 def _put_rule (self , a , b ):
264270 if self .state != _dvistate .inpage :
265271 raise ValueError , "misplaced put_rule in dvi file"
266272 if a > 0 and b > 0 :
267273 self .boxes .append ((self .h , self .v , a , b ))
274+ # matplotlib.verbose.report(
275+ # 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b),
276+ # 'debug-annoying')
268277
269278 def _nop (self ):
270279 pass
@@ -357,7 +366,7 @@ def _fnt_def(self, k, c, s, d, a, l, n):
357366
358367 vf = _vffile (n [- l :])
359368
360- self .fonts [k ] = mpl_cbook . Bunch (scale = s , tfm = tfm , name = n , vf = vf )
369+ self .fonts [k ] = DviFont (scale = s , tfm = tfm , texname = n , vf = vf )
361370
362371 def _post (self ):
363372 if self .state != _dvistate .outer :
@@ -370,17 +379,20 @@ def _post_post(self):
370379 raise NotImplementedError
371380
372381class DviFont (object ):
373- __slots__ = ('texname' , 'size' )
382+ """
383+ Object that holds a font's texname and size and supports comparison.
384+ There are also internal attributes (for use by dviread.py) that
385+ are _not_ used for comparison.
374386
375- def __init__ ( self , f ):
376- """
377- Object that holds a font's texname and size and supports comparison.
387+ The size is in Adobe points (converted from TeX points).
388+ """
389+ __slots__ = ( ' texname' , ' size' , '_scale' , '_vf' , '_tfm' )
378390
379- The size is in Adobe points (converted from TeX points).
380- """
391+ def __init__ (self , scale , tfm , texname , vf ):
392+ self ._scale , self ._tfm , self .texname , self ._vf = \
393+ scale , tfm , texname , vf
381394 # TODO: would it make more sense to have the size in dpi units?
382- self .texname = f .name
383- self .size = f .scale * (72.0 / (72.27 * 2 ** 16 ))
395+ self .size = scale * (72.0 / (72.27 * 2 ** 16 ))
384396
385397 def __eq__ (self , other ):
386398 return self .__class__ == other .__class__ and \
@@ -389,6 +401,16 @@ def __eq__(self, other):
389401 def __ne__ (self , other ):
390402 return not self .__eq__ (other )
391403
404+ def _width_of (self , char ):
405+ width = self ._tfm .width .get (char , None )
406+ if width is not None :
407+ return _mul2012 (width , self ._scale )
408+
409+ matplotlib .verbose .report (
410+ 'No width for char %d in font %s' % (char , self .texname ),
411+ 'debug' )
412+ return 0
413+
392414class Vf (Dvi ):
393415 """
394416 A virtual font (*.vf file) containing subroutines for dvi files.
@@ -465,7 +487,8 @@ def _pre(self, i, x, cs, ds):
465487 raise ValueError , "pre command in middle of vf file"
466488 if i != 202 :
467489 raise ValueError , "Unknown vf format %d" % i
468- matplotlib .verbose .report ('vf file comment: ' + x , 'debug' )
490+ if len (x ):
491+ matplotlib .verbose .report ('vf file comment: ' + x , 'debug' )
469492 self .state = _dvistate .outer
470493 # cs = checksum, ds = design size
471494
@@ -474,7 +497,7 @@ def _fnt_def(self, k, *args):
474497 if self ._first_font is None :
475498 self ._first_font = k
476499
477- def fix2comp (num ):
500+ def _fix2comp (num ):
478501 """
479502 Convert from two's complement to negative.
480503 """
@@ -484,6 +507,13 @@ def fix2comp(num):
484507 else :
485508 return num
486509
510+ def _mul2012 (num1 , num2 ):
511+ """
512+ Multiply two numbers in 20.12 fixed point format.
513+ """
514+ # Separated into a function because >> has surprising precedence
515+ return (num1 * num2 ) >> 20
516+
487517class Tfm (object ):
488518 """
489519 A TeX Font Metric file. This implementation covers only the bare
@@ -497,6 +527,7 @@ class Tfm(object):
497527 (this is a dict because indexing may not start from 0)
498528 height[i], depth[i]: height and depth of character #i
499529 """
530+ __slots__ = ('checksum' , 'design_size' , 'width' , 'height' , 'depth' )
500531
501532 def __init__ (self , filename ):
502533 matplotlib .verbose .report ('opening tfm file ' + filename , 'debug' )
@@ -525,9 +556,9 @@ def __init__(self, filename):
525556 [ struct .unpack ('!%dI' % (len (x )/ 4 ), x )
526557 for x in (widths , heights , depths ) ]
527558 for i in range (ec - bc ):
528- self .width [bc + i ] = fix2comp (widths [ord (char_info [4 * i ])])
529- self .height [bc + i ] = fix2comp (heights [ord (char_info [4 * i + 1 ]) >> 4 ])
530- self .depth [bc + i ] = fix2comp (depths [ord (char_info [4 * i + 1 ]) & 0xf ])
559+ self .width [bc + i ] = _fix2comp (widths [ord (char_info [4 * i ])])
560+ self .height [bc + i ] = _fix2comp (heights [ord (char_info [4 * i + 1 ]) >> 4 ])
561+ self .depth [bc + i ] = _fix2comp (depths [ord (char_info [4 * i + 1 ]) & 0xf ])
531562
532563
533564class PsfontsMap (object ):
@@ -552,6 +583,7 @@ class PsfontsMap(object):
552583 the pdf-related files perhaps only avoid the "Base 14" pdf fonts.
553584 But the user may have configured these files differently.
554585 """
586+ __slots__ = ('_font' ,)
555587
556588 def __init__ (self , filename ):
557589 self ._font = {}
@@ -627,6 +659,16 @@ def _register(self, words):
627659 encoding = encoding , filename = filename )
628660
629661class Encoding (object ):
662+ """
663+ Parses a *.enc file referenced from a psfonts.map style file.
664+ The format this class understands is a very limited subset of
665+ PostScript.
666+
667+ Usage (subject to change):
668+ for name in Encoding(filename):
669+ whatever(name)
670+ """
671+ __slots__ = ('encoding' ,)
630672
631673 def __init__ (self , filename ):
632674 file = open (filename , 'rt' )
@@ -694,6 +736,10 @@ def find_tex_file(filename, format=None):
694736
695737 return result
696738
739+ # With multiple text objects per figure (e.g. tick labels) we may end
740+ # up reading the same tfm and vf files many times, so we implement a
741+ # simple cache. TODO: is this worth making persistent?
742+
697743_tfmcache = {}
698744_vfcache = {}
699745
@@ -721,19 +767,22 @@ def _vffile(texname):
721767
722768
723769if __name__ == '__main__' :
724- matplotlib .verbose .set_level ('debug' )
725- dvi = Dvi ('foo.dvi' , 72 )
770+ import sys
771+ matplotlib .verbose .set_level ('debug-annoying' )
772+ fname = sys .argv [1 ]
773+ try : dpi = float (sys .argv [2 ])
774+ except IndexError : dpi = None
775+ dvi = Dvi (fname , dpi )
726776 fontmap = PsfontsMap (find_tex_file ('pdftex.map' ))
727- for text , boxes in dvi :
777+ for page in dvi :
728778 print '=== new page ==='
729779 fPrev = None
730- for x ,y ,f ,c in text :
731- texname = dvi .fonts [f ].name
732- print x ,y ,c ,chr (c ),texname
780+ for x ,y ,f ,c ,w in page .text :
733781 if f != fPrev :
734- print 'font' , texname , '= ' , fontmap [ texname ]. __dict__
782+ print 'font' , f . texname , 'scaled ' , f . _scale / pow ( 2.0 , 20 )
735783 fPrev = f
736- for x ,y ,w ,h in boxes :
784+ print x ,y ,c , 32 <= c < 128 and chr (c ) or '.' , w
785+ for x ,y ,w ,h in page .boxes :
737786 print x ,y ,'BOX' ,w ,h
738787
739788
0 commit comments