From: <jo...@us...> - 2007-09-13 06:29:33
|
Revision: 3845 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3845&view=rev Author: jouni Date: 2007-09-12 23:29:14 -0700 (Wed, 12 Sep 2007) Log Message: ----------- 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. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-09-12 20:37:41 UTC (rev 3844) +++ trunk/matplotlib/CHANGELOG 2007-09-13 06:29:14 UTC (rev 3845) @@ -1,3 +1,6 @@ +2007-09-13 The usetex support in the pdf backend is more usable now, + so I am enabling it. - JKS + 2007-09-12 Fixed a Axes.bar unit bug - JDH 2007-09-10 Made skiprows=1 the default on csv2rec - JDH Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-12 20:37:41 UTC (rev 3844) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-13 06:29:14 UTC (rev 3845) @@ -527,7 +527,7 @@ widths.append(afmdata.get_width_from_char_name(ch)) except KeyError: matplotlib.verbose.report( - 'No width for %s in %s' % (ch, fullname), 'debug') + 'No width for %s in %s' % (ch, fullname), 'debug-annoying') widths.append(0) differencesArray = [ Name(ch) for ch in enc ] @@ -561,7 +561,7 @@ except KeyError: matplotlib.verbose.report( 'No name for glyph %d in %s' % (ch, fullname), - 'debug') + 'debug-annoying') need_idx = True @@ -1449,9 +1449,7 @@ # Pop off the global transformation self.file.output(Op.grestore) - def _draw_tex(self, gc, x, y, s, prop, angle): - # Rename to draw_tex to enable - + def draw_tex(self, gc, x, y, s, prop, angle): texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) @@ -1494,7 +1492,7 @@ elt[3][-1] += next[3][0] elt[4] += next[4]-next[1] else: - elt[3] += [offset, next[3][0]] + elt[3] += [offset*1000.0/dvifont.size, next[3][0]] elt[4] = next[4] del seq[i+1] continue Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-12 20:37:41 UTC (rev 3844) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-13 06:29:14 UTC (rev 3845) @@ -84,16 +84,22 @@ e = 0 # zero depth else: # glyph x,y,font,g,w = elt - h = (font.scale * font.tfm.height[g]) >> 20 - e = (font.scale * font.tfm.depth[g]) >> 20 + h = _mul2012(font._scale, font._tfm.height[g]) + e = _mul2012(font._scale, font._tfm.depth[g]) minx = min(minx, x) miny = min(miny, y - h) maxx = max(maxx, x + w) maxy = max(maxy, y + e) maxy_pure = max(maxy_pure, y) + if self.dpi is None: + # special case for ease of debugging: output raw dvi coordinates + return mpl_cbook.Bunch(text=self.text, boxes=self.boxes, + width=maxx-minx, height=maxy_pure-miny, + descent=maxy-maxy_pure) + d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units - text = [ ((x-minx)*d, (maxy-y)*d, DviFont(f), g, w*d) + text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) for (x,y,f,g,w) in self.text ] boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ] @@ -110,11 +116,11 @@ while True: byte = ord(self.file.read(1)) self._dispatch(byte) - if self.state == _dvistate.inpage: - matplotlib.verbose.report( - 'Dvi._read: after %d at %f,%f' % - (byte, self.h, self.v), - 'debug-annoying') +# if self.state == _dvistate.inpage: +# matplotlib.verbose.report( +# 'Dvi._read: after %d at %f,%f' % +# (byte, self.h, self.v), +# 'debug-annoying') if byte == 140: # end of page return True if self.state == _dvistate.post_post: # end of file @@ -225,21 +231,11 @@ # I think we can assume this is constant self.state = _dvistate.outer - def _width_of(self, char, font): - width = font.tfm.width.get(char, None) - if width is not None: - return (width * font.scale) >> 20 - - matplotlib.verbose.report( - 'No width for char %d in font %s' % (char, font.name), - 'debug') - return 0 - def _set_char(self, char): if self.state != _dvistate.inpage: raise ValueError, "misplaced set_char in dvi file" self._put_char(char) - self.h += self._width_of(char, self.fonts[self.f]) + self.h += self.fonts[self.f]._width_of(char) def _set_rule(self, a, b): if self.state != _dvistate.inpage: @@ -251,20 +247,33 @@ if self.state != _dvistate.inpage: raise ValueError, "misplaced put_char in dvi file" font = self.fonts[self.f] - if font.vf is None: + if font._vf is None: self.text.append((self.h, self.v, font, char, - self._width_of(char, font))) + font._width_of(char))) +# matplotlib.verbose.report( +# 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char), +# 'debug-annoying') else: - self.text.extend([(self.h + x, self.v + y, f, g, w) - for x, y, f, g, w in font.vf[char].text]) - self.boxes.extend([(self.h + x, self.v + y, a, b) - for x, y, a, b in font.vf[char].boxes]) + scale = font._scale + for x, y, f, g, w in font._vf[char].text: + newf = DviFont(scale=_mul2012(scale, f._scale), + tfm=f._tfm, texname=f.texname, vf=f._vf) + self.text.append((self.h + _mul2012(x, scale), + self.v + _mul2012(y, scale), + newf, g, newf._width_of(g))) + self.boxes.extend([(self.h + _mul2012(x, scale), + self.v + _mul2012(y, scale), + _mul2012(a, scale), _mul2012(b, scale)) + for x, y, a, b in font._vf[char].boxes]) def _put_rule(self, a, b): if self.state != _dvistate.inpage: raise ValueError, "misplaced put_rule in dvi file" if a > 0 and b > 0: self.boxes.append((self.h, self.v, a, b)) +# matplotlib.verbose.report( +# 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b), +# 'debug-annoying') def _nop(self): pass @@ -357,7 +366,7 @@ vf = _vffile(n[-l:]) - self.fonts[k] = mpl_cbook.Bunch(scale=s, tfm=tfm, name=n, vf=vf) + self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf) def _post(self): if self.state != _dvistate.outer: @@ -370,17 +379,20 @@ raise NotImplementedError class DviFont(object): - __slots__ = ('texname', 'size') + """ + Object that holds a font's texname and size and supports comparison. + There are also internal attributes (for use by dviread.py) that + are _not_ used for comparison. - def __init__(self, f): - """ - Object that holds a font's texname and size and supports comparison. + The size is in Adobe points (converted from TeX points). + """ + __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm') - The size is in Adobe points (converted from TeX points). - """ + def __init__(self, scale, tfm, texname, vf): + self._scale, self._tfm, self.texname, self._vf = \ + scale, tfm, texname, vf # TODO: would it make more sense to have the size in dpi units? - self.texname = f.name - self.size = f.scale * (72.0 / (72.27 * 2**16)) + self.size = scale * (72.0 / (72.27 * 2**16)) def __eq__(self, other): return self.__class__ == other.__class__ and \ @@ -389,6 +401,16 @@ def __ne__(self, other): return not self.__eq__(other) + def _width_of(self, char): + width = self._tfm.width.get(char, None) + if width is not None: + return _mul2012(width, self._scale) + + matplotlib.verbose.report( + 'No width for char %d in font %s' % (char, self.texname), + 'debug') + return 0 + class Vf(Dvi): """ A virtual font (*.vf file) containing subroutines for dvi files. @@ -465,7 +487,8 @@ raise ValueError, "pre command in middle of vf file" if i != 202: raise ValueError, "Unknown vf format %d" % i - matplotlib.verbose.report('vf file comment: ' + x, 'debug') + if len(x): + matplotlib.verbose.report('vf file comment: ' + x, 'debug') self.state = _dvistate.outer # cs = checksum, ds = design size @@ -474,7 +497,7 @@ if self._first_font is None: self._first_font = k -def fix2comp(num): +def _fix2comp(num): """ Convert from two's complement to negative. """ @@ -484,6 +507,13 @@ else: return num +def _mul2012(num1, num2): + """ + Multiply two numbers in 20.12 fixed point format. + """ + # Separated into a function because >> has surprising precedence + return (num1*num2) >> 20 + class Tfm(object): """ A TeX Font Metric file. This implementation covers only the bare @@ -497,6 +527,7 @@ (this is a dict because indexing may not start from 0) height[i], depth[i]: height and depth of character #i """ + __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth') def __init__(self, filename): matplotlib.verbose.report('opening tfm file ' + filename, 'debug') @@ -525,9 +556,9 @@ [ struct.unpack('!%dI' % (len(x)/4), x) for x in (widths, heights, depths) ] for i in range(ec-bc): - self.width[bc+i] = fix2comp(widths[ord(char_info[4*i])]) - self.height[bc+i] = fix2comp(heights[ord(char_info[4*i+1]) >> 4]) - self.depth[bc+i] = fix2comp(depths[ord(char_info[4*i+1]) & 0xf]) + self.width[bc+i] = _fix2comp(widths[ord(char_info[4*i])]) + self.height[bc+i] = _fix2comp(heights[ord(char_info[4*i+1]) >> 4]) + self.depth[bc+i] = _fix2comp(depths[ord(char_info[4*i+1]) & 0xf]) class PsfontsMap(object): @@ -552,6 +583,7 @@ the pdf-related files perhaps only avoid the "Base 14" pdf fonts. But the user may have configured these files differently. """ + __slots__ = ('_font',) def __init__(self, filename): self._font = {} @@ -627,7 +659,17 @@ encoding=encoding, filename=filename) class Encoding(object): + """ + Parses a *.enc file referenced from a psfonts.map style file. + The format this class understands is a very limited subset of + PostScript. + Usage (subject to change): + for name in Encoding(filename): + whatever(name) + """ + __slots__ = ('encoding',) + def __init__(self, filename): file = open(filename, 'rt') try: @@ -694,6 +736,10 @@ return result +# With multiple text objects per figure (e.g. tick labels) we may end +# up reading the same tfm and vf files many times, so we implement a +# simple cache. TODO: is this worth making persistent? + _tfmcache = {} _vfcache = {} @@ -721,19 +767,22 @@ if __name__ == '__main__': - matplotlib.verbose.set_level('debug') - dvi = Dvi('foo.dvi', 72) + import sys + matplotlib.verbose.set_level('debug-annoying') + fname = sys.argv[1] + try: dpi = float(sys.argv[2]) + except IndexError: dpi = None + dvi = Dvi(fname, dpi) fontmap = PsfontsMap(find_tex_file('pdftex.map')) - for text,boxes in dvi: + for page in dvi: print '=== new page ===' fPrev = None - for x,y,f,c in text: - texname = dvi.fonts[f].name - print x,y,c,chr(c),texname + for x,y,f,c,w in page.text: if f != fPrev: - print 'font', texname, '=', fontmap[texname].__dict__ + print 'font', f.texname, 'scaled', f._scale/pow(2.0,20) fPrev = f - for x,y,w,h in boxes: + print x,y,c, 32 <= c < 128 and chr(c) or '.', w + for x,y,w,h in page.boxes: print x,y,'BOX',w,h This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |