|
6 | 6 | Interface: |
7 | 7 |
|
8 | 8 | 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: |
12 | 12 | fontname, pointsize = dvi.fontinfo(font) |
13 | 13 | ... |
14 | | - for x,y,height,width in boxes: |
| 14 | + for x,y,height,width in page.boxes: |
15 | 15 | ... |
16 | 16 | """ |
17 | 17 |
|
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 |
19 | 20 |
|
20 | 21 | import matplotlib |
21 | 22 | import matplotlib.cbook as mpl_cbook |
| 23 | +import numpy as npy |
22 | 24 | import os |
23 | 25 | import struct |
24 | 26 |
|
@@ -74,20 +76,33 @@ def close(self): |
74 | 76 | def _output(self): |
75 | 77 | """ |
76 | 78 | Output the text and boxes belonging to the most recent page. |
77 | | - text, boxes = dvi._output() |
| 79 | + page = dvi._output() |
78 | 80 | """ |
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 |
81 | 83 | 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 | + |
87 | 98 | d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units |
88 | 99 | text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) for (x,y,f,g,w) in self.text ] |
89 | 100 | 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) |
91 | 106 |
|
92 | 107 | def fontinfo(self, f): |
93 | 108 | """ |
@@ -361,28 +376,36 @@ class Tfm(object): |
361 | 376 | width[i]: width of character #i, needs to be scaled |
362 | 377 | by the factor specified in the dvi file |
363 | 378 | (this is a dict because indexing may not start from 0) |
| 379 | + height[i], depth[i]: height and depth of character #i |
364 | 380 | """ |
365 | 381 |
|
366 | 382 | def __init__(self, filename): |
367 | 383 | file = open(filename, 'rb') |
368 | 384 |
|
369 | 385 | try: |
370 | 386 | 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]) |
373 | 389 | header2 = file.read(4*lh) |
374 | 390 | self.checksum, self.design_size = \ |
375 | 391 | struct.unpack('!2I', header2[:8]) |
376 | 392 | # there is also encoding information etc. |
377 | 393 | char_info = file.read(4*(ec-bc+1)) |
378 | 394 | widths = file.read(4*nw) |
| 395 | + heights = file.read(4*nh) |
| 396 | + depths = file.read(4*nd) |
379 | 397 | finally: |
380 | 398 | file.close() |
381 | 399 |
|
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)] ] |
384 | 404 | for i in range(ec-bc): |
385 | 405 | 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 | + |
386 | 409 |
|
387 | 410 | class PsfontsMap(object): |
388 | 411 | """ |
|
0 commit comments