Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0e5344a

Browse files
committed
More work on dviread and usetex in pdf. It is more usable now,
so I am renaming the method from _draw_tex to draw_tex. svn path=/trunk/matplotlib/; revision=3845
1 parent 62717fb commit 0e5344a

3 files changed

Lines changed: 103 additions & 53 deletions

File tree

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2007-09-13 The usetex support in the pdf backend is more usable now,
2+
so I am enabling it. - JKS
3+
14
2007-09-12 Fixed a Axes.bar unit bug - JDH
25

36
2007-09-10 Made skiprows=1 the default on csv2rec - JDH

lib/matplotlib/backends/backend_pdf.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ def embedType1(self, filename, fontinfo):
527527
widths.append(afmdata.get_width_from_char_name(ch))
528528
except KeyError:
529529
matplotlib.verbose.report(
530-
'No width for %s in %s' % (ch, fullname), 'debug')
530+
'No width for %s in %s' % (ch, fullname), 'debug-annoying')
531531
widths.append(0)
532532

533533
differencesArray = [ Name(ch) for ch in enc ]
@@ -561,7 +561,7 @@ def embedType1(self, filename, fontinfo):
561561
except KeyError:
562562
matplotlib.verbose.report(
563563
'No name for glyph %d in %s' % (ch, fullname),
564-
'debug')
564+
'debug-annoying')
565565
need_idx = True
566566

567567

@@ -1449,9 +1449,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
14491449
# Pop off the global transformation
14501450
self.file.output(Op.grestore)
14511451

1452-
def _draw_tex(self, gc, x, y, s, prop, angle):
1453-
# Rename to draw_tex to enable
1454-
1452+
def draw_tex(self, gc, x, y, s, prop, angle):
14551453
texmanager = self.get_texmanager()
14561454
fontsize = prop.get_size_in_points()
14571455
dvifile = texmanager.make_dvi(s, fontsize)
@@ -1494,7 +1492,7 @@ def mytrans(x1, y1, x=x, y=y, a=angle / 180.0 * pi):
14941492
elt[3][-1] += next[3][0]
14951493
elt[4] += next[4]-next[1]
14961494
else:
1497-
elt[3] += [offset, next[3][0]]
1495+
elt[3] += [offset*1000.0/dvifont.size, next[3][0]]
14981496
elt[4] = next[4]
14991497
del seq[i+1]
15001498
continue

lib/matplotlib/dviread.py

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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

372381
class 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+
392414
class 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+
487517
class 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

533564
class 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

629661
class 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

723769
if __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

Comments
 (0)