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

Skip to content

Commit 63c74ad

Browse files
committed
Better bounding boxes for pdf usetex, including descents.
svn path=/trunk/matplotlib/; revision=3827
1 parent 2be79c8 commit 63c74ad

2 files changed

Lines changed: 50 additions & 32 deletions

File tree

lib/matplotlib/backends/backend_pdf.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,14 +1427,14 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
14271427
# Pop off the global transformation
14281428
self.file.output(Op.grestore)
14291429

1430-
def _draw_tex(self, gc, x, y, s, prop, angle):
1430+
def draw_tex(self, gc, x, y, s, prop, angle):
14311431
# Rename to draw_tex to enable
14321432

14331433
texmanager = self.get_texmanager()
14341434
fontsize = prop.get_size_in_points()
14351435
dvifile = texmanager.make_dvi(s, fontsize)
14361436
dvi = dviread.Dvi(dvifile, 72)
1437-
text, boxes = iter(dvi).next()
1437+
page = iter(dvi).next()
14381438
dvi.close()
14391439

14401440
if angle == 0: # avoid rounding errors in common case
@@ -1448,7 +1448,7 @@ def mytrans(x1, y1, x=x, y=y, a=angle / 180.0 * pi):
14481448
# Gather font information and do some setup for combining
14491449
# characters into strings.
14501450
oldfontnum, seq = None, []
1451-
for x1, y1, fontnum, glyph, width in text:
1451+
for x1, y1, fontnum, glyph, width in page.text:
14521452
if fontnum != oldfontnum:
14531453
texname, fontsize = dvi.fontinfo(fontnum)
14541454
fontinfo = self.tex_font_mapping(texname)
@@ -1462,8 +1462,8 @@ def mytrans(x1, y1, x=x, y=y, a=angle / 180.0 * pi):
14621462
seq += [('end',)]
14631463

14641464
# Find consecutive text strings with constant x coordinate and
1465-
# combine into one string (if needed kern would be less than
1466-
# 0.1 points) or several strings interspersed with kerns.
1465+
# combine into a sequence of strings and kerns, or just one
1466+
# string (if any kerns would be less than 0.1 points).
14671467
i, curx = 0, 0
14681468
while i < len(seq)-1:
14691469
elt, next = seq[i:i+2]
@@ -1503,7 +1503,7 @@ def mytrans(x1, y1, x=x, y=y, a=angle / 180.0 * pi):
15031503
boxgc = self.new_gc()
15041504
boxgc.copy_properties(gc)
15051505
boxgc.set_linewidth(0)
1506-
for x1, y1, h, w in boxes:
1506+
for x1, y1, h, w in page.boxes:
15071507
(x1, y1), (x2, y2), (x3, y3), (x4, y4) = \
15081508
mytrans(x1, y1), mytrans(x1+w, y1), \
15091509
mytrans(x1+w, y1+h), mytrans(x1, y1+h)
@@ -1653,14 +1653,9 @@ def get_text_width_height_descent(self, s, prop, ismath):
16531653
fontsize = prop.get_size_in_points()
16541654
dvifile = texmanager.make_dvi(s, fontsize)
16551655
dvi = dviread.Dvi(dvifile, 72)
1656-
text, boxes = iter(dvi).next()
1657-
# TODO: better bounding box -- this is not quite right:
1658-
l = min(p[0] for p in text+boxes)
1659-
r = max(p[0] for p in text+boxes) + fontsize
1660-
b = min(p[1] for p in text+boxes)
1661-
t = max(p[1] for p in text+boxes) + fontsize
1662-
# (not to even mention finding the baseline)
1663-
return r-l, t-b, t-b
1656+
page = iter(dvi).next()
1657+
dvi.close()
1658+
return page.width, page.height, page.descent
16641659
if ismath:
16651660
w, h, d, glyphs, rects, used_characters = \
16661661
self.mathtext_parser.parse(s, 72, prop)

lib/matplotlib/dviread.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@
66
Interface:
77
88
dvi = Dvi(filename, 72)
9-
for text, boxes in dvi: # iterate over pages
10-
text, boxes = dvi.output(72)
11-
for x,y,font,glyph,width in text:
9+
for page in dvi: # iterate over pages
10+
w, h, d = page.width, page.height, page.descent
11+
for x,y,font,glyph,width in page.text:
1212
fontname, pointsize = dvi.fontinfo(font)
1313
...
14-
for x,y,height,width in boxes:
14+
for x,y,height,width in page.boxes:
1515
...
1616
"""
1717

18-
# TODO: support for TeX virtual fonts (*.vf) which are a dvi-like format
18+
# TODO: support TeX virtual fonts (*.vf) which are a sort of
19+
# subroutine collections for dvi files
1920

2021
import matplotlib
2122
import matplotlib.cbook as mpl_cbook
23+
import numpy as npy
2224
import os
2325
import struct
2426

@@ -74,20 +76,33 @@ def close(self):
7476
def _output(self):
7577
"""
7678
Output the text and boxes belonging to the most recent page.
77-
text, boxes = dvi._output()
79+
page = dvi._output()
7880
"""
79-
t0 = self.text[0]
80-
minx, miny, maxx, maxy = t0[0], t0[1], t0[0], t0[1]
81+
minx, miny, maxx, maxy = npy.inf, npy.inf, -npy.inf, -npy.inf
82+
maxy_pure = -npy.inf
8183
for elt in self.text + self.boxes:
82-
x,y = elt[:2]
83-
if x < minx: minx = x
84-
if y < miny: miny = y
85-
if x > maxx: maxx = x
86-
if y > maxy: maxy = y
84+
if len(elt) == 4: # box
85+
x,y,h,w = elt
86+
e = 0 # zero depth
87+
else: # glyph
88+
x,y,f,g,w = elt
89+
font = self.fonts[f]
90+
h = (font.scale * font.tfm.height[g]) >> 20
91+
e = (font.scale * font.tfm.depth[g]) >> 20
92+
minx = min(minx, x)
93+
miny = min(miny, y - h)
94+
maxx = max(maxx, x + w)
95+
maxy = max(maxy, y + e)
96+
maxy_pure = max(maxy_pure, y)
97+
8798
d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units
8899
text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) for (x,y,f,g,w) in self.text ]
89100
boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ]
90-
return text, boxes
101+
102+
return mpl_cbook.Bunch(text=text, boxes=boxes,
103+
width=(maxx-minx)*d,
104+
height=(maxy_pure-miny)*d,
105+
descent=(maxy-maxy_pure)*d)
91106

92107
def fontinfo(self, f):
93108
"""
@@ -361,28 +376,36 @@ class Tfm(object):
361376
width[i]: width of character #i, needs to be scaled
362377
by the factor specified in the dvi file
363378
(this is a dict because indexing may not start from 0)
379+
height[i], depth[i]: height and depth of character #i
364380
"""
365381

366382
def __init__(self, filename):
367383
file = open(filename, 'rb')
368384

369385
try:
370386
header1 = file.read(24)
371-
lh, bc, ec, nw = \
372-
struct.unpack('!4H', header1[2:10])
387+
lh, bc, ec, nw, nh, nd = \
388+
struct.unpack('!6H', header1[2:14])
373389
header2 = file.read(4*lh)
374390
self.checksum, self.design_size = \
375391
struct.unpack('!2I', header2[:8])
376392
# there is also encoding information etc.
377393
char_info = file.read(4*(ec-bc+1))
378394
widths = file.read(4*nw)
395+
heights = file.read(4*nh)
396+
depths = file.read(4*nd)
379397
finally:
380398
file.close()
381399

382-
widths = struct.unpack('!%dI' % nw, widths)
383-
self.width = {}
400+
self.width, self.height, self.depth = {}, {}, {}
401+
widths, heights, depths = \
402+
[ struct.unpack('!%dI' % n, x)
403+
for n,x in [(nw, widths), (nh, heights), (nd, depths)] ]
384404
for i in range(ec-bc):
385405
self.width[bc+i] = widths[ord(char_info[4*i])]
406+
self.height[bc+i] = heights[ord(char_info[4*i+1]) >> 4]
407+
self.depth[bc+i] = depths[ord(char_info[4*i+1]) & 0xf]
408+
386409

387410
class PsfontsMap(object):
388411
"""

0 commit comments

Comments
 (0)