decorator to put text along a path; based on a patch by Michael J Gruber
[PyX.git] / pyx / dvi / dvifile.py
blob7be184cfdbb9a9b06edf2173b6bc6527b348b615
1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2002-2011 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2003-2004,2006,2007 Michael Schindler <m-schindler@users.sourceforge.net>
6 # Copyright (C) 2002-2011 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 import cStringIO, math, re, string, struct, sys, warnings
25 from pyx import bbox, canvas, canvasitem, color, epsfile, filelocator, path, reader, trafo, unit
26 import texfont, tfmfile
29 _DVI_CHARMIN = 0 # typeset a character and move right (range min)
30 _DVI_CHARMAX = 127 # typeset a character and move right (range max)
31 _DVI_SET1234 = 128 # typeset a character and move right
32 _DVI_SETRULE = 132 # typeset a rule and move right
33 _DVI_PUT1234 = 133 # typeset a character
34 _DVI_PUTRULE = 137 # typeset a rule
35 _DVI_NOP = 138 # no operation
36 _DVI_BOP = 139 # beginning of page
37 _DVI_EOP = 140 # ending of page
38 _DVI_PUSH = 141 # save the current positions (h, v, w, x, y, z)
39 _DVI_POP = 142 # restore positions (h, v, w, x, y, z)
40 _DVI_RIGHT1234 = 143 # move right
41 _DVI_W0 = 147 # move right by w
42 _DVI_W1234 = 148 # move right and set w
43 _DVI_X0 = 152 # move right by x
44 _DVI_X1234 = 153 # move right and set x
45 _DVI_DOWN1234 = 157 # move down
46 _DVI_Y0 = 161 # move down by y
47 _DVI_Y1234 = 162 # move down and set y
48 _DVI_Z0 = 166 # move down by z
49 _DVI_Z1234 = 167 # move down and set z
50 _DVI_FNTNUMMIN = 171 # set current font (range min)
51 _DVI_FNTNUMMAX = 234 # set current font (range max)
52 _DVI_FNT1234 = 235 # set current font
53 _DVI_SPECIAL1234 = 239 # special (dvi extention)
54 _DVI_FNTDEF1234 = 243 # define the meaning of a font number
55 _DVI_PRE = 247 # preamble
56 _DVI_POST = 248 # postamble beginning
57 _DVI_POSTPOST = 249 # postamble ending
59 _DVI_VERSION = 2 # dvi version
61 # position variable indices
62 _POS_H = 0
63 _POS_V = 1
64 _POS_W = 2
65 _POS_X = 3
66 _POS_Y = 4
67 _POS_Z = 5
69 # reader states
70 _READ_PRE = 1
71 _READ_NOPAGE = 2
72 _READ_PAGE = 3
73 _READ_POST = 4 # XXX not used
74 _READ_POSTPOST = 5 # XXX not used
75 _READ_DONE = 6
78 class DVIError(Exception): pass
80 # save and restore colors
82 class _canvasitem(canvasitem.canvasitem):
84 def bbox(self):
85 # TODO: see TODO in bbox method of canvasitem
86 return bbox.empty()
89 class _savecolor(_canvasitem):
90 def processPS(self, file, writer, context, registry, bbox):
91 file.write("currentcolor currentcolorspace\n")
93 def processPDF(self, file, writer, context, registry, bbox):
94 file.write("q\n")
97 class _restorecolor(_canvasitem):
98 def processPS(self, file, writer, context, registry, bbox):
99 file.write("setcolorspace setcolor\n")
101 def processPDF(self, file, writer, context, registry, bbox):
102 file.write("Q\n")
105 class _savetrafo(_canvasitem):
106 def processPS(self, file, writer, context, registry, bbox):
107 file.write("matrix currentmatrix\n")
109 def processPDF(self, file, writer, context, registry, bbox):
110 file.write("q\n")
113 class _restoretrafo(_canvasitem):
114 def processPS(self, file, writer, context, registry, bbox):
115 file.write("setmatrix\n")
117 def processPDF(self, file, writer, context, registry, bbox):
118 file.write("Q\n")
121 class DVIfile:
123 def __init__(self, filename, debug=0, debugfile=sys.stdout):
124 """ opens the dvi file and reads the preamble """
125 self.filename = filename
126 self.debug = debug
127 self.debugfile = debugfile
128 self.debugstack = []
130 self.fonts = {}
131 self.activefont = None
133 # stack of fonts and fontscale currently used (used for VFs)
134 self.fontstack = []
135 self.stack = []
137 # pointer to currently active page
138 self.actpage = None
140 # stack for self.file, self.fonts and self.stack, needed for VF inclusion
141 self.statestack = []
143 self.file = reader.reader(self.filename)
145 # currently read byte in file (for debugging output)
146 self.filepos = None
148 self._read_pre()
150 # helper routines
152 def flushtext(self, fontmap):
153 """ finish currently active text object """
154 if self.activetext:
155 x, y, charcodes = self.activetext
156 x_pt, y_pt = x * self.pyxconv, -y*self.pyxconv
157 self.actpage.insert(self.activefont.text_pt(x_pt, y_pt, charcodes, fontmap=fontmap))
158 if self.debug:
159 self.debugfile.write("[%s]\n" % "".join([chr(char) for char in self.activetext[2]]))
160 self.activetext = None
162 def putrule(self, height, width, advancepos, fontmap):
163 self.flushtext(fontmap)
164 x1 = self.pos[_POS_H] * self.pyxconv
165 y1 = -self.pos[_POS_V] * self.pyxconv
166 w = width * self.pyxconv
167 h = height * self.pyxconv
169 if height > 0 and width > 0:
170 if self.debug:
171 self.debugfile.write("%d: %srule height %d, width %d (???x??? pixels)\n" %
172 (self.filepos, advancepos and "set" or "put", height, width))
173 self.actpage.fill(path.rect_pt(x1, y1, w, h))
174 else:
175 if self.debug:
176 self.debugfile.write("%d: %srule height %d, width %d (invisible)\n" %
177 (self.filepos, advancepos and "set" or "put", height, width))
179 if advancepos:
180 if self.debug:
181 self.debugfile.write(" h:=%d+%d=%d, hh:=???\n" %
182 (self.pos[_POS_H], width, self.pos[_POS_H]+width))
183 self.pos[_POS_H] += width * self.scale
185 def putchar(self, char, advancepos, id1234, fontmap):
186 dx = advancepos and self.activefont.getwidth_dvi(char) or 0
188 if self.debug:
189 self.debugfile.write("%d: %s%s%d h:=%d+%d=%d, hh:=???\n" %
190 (self.filepos,
191 advancepos and "set" or "put",
192 id1234 and "%i " % id1234 or "char",
193 char,
194 self.pos[_POS_H], dx, self.pos[_POS_H]+dx))
196 if isinstance(self.activefont, texfont.virtualfont):
197 # virtual font handling
198 afterpos = list(self.pos)
199 afterpos[_POS_H] += dx
200 self._push_dvistring(self.activefont.getchar(char), self.activefont.getfonts(), afterpos,
201 self.activefont.getsize_pt(), fontmap)
202 else:
203 if self.activetext is None:
204 self.activetext = (self.pos[_POS_H], self.pos[_POS_V], [])
205 self.activetext[2].append(char)
206 self.pos[_POS_H] += dx
208 if (not advancepos) or self.singlecharmode:
209 self.flushtext(fontmap)
211 def usefont(self, fontnum, id1234, fontmap):
212 self.flushtext(fontmap)
213 self.activefont = self.fonts[fontnum]
214 if self.debug:
215 self.debugfile.write("%d: fnt%s%i current font is %s\n" %
216 (self.filepos,
217 id1234 and "%i " % id1234 or "num",
218 fontnum,
219 self.fonts[fontnum].name))
222 def definefont(self, cmdnr, num, c, q, d, fontname):
223 # cmdnr: type of fontdef command (only used for debugging output)
224 # c: checksum
225 # q: scaling factor (fix_word)
226 # Note that q is actually s in large parts of the documentation.
227 # d: design size (fix_word)
229 # check whether it's a virtual font by trying to open it. if this fails, it is an ordinary TeX font
230 try:
231 fontfile = filelocator.open(fontname, [filelocator.format.vf], mode="rb")
232 except IOError:
233 afont = texfont.TeXfont(fontname, c, q/self.tfmconv, d/self.tfmconv, self.tfmconv, self.pyxconv, self.debug>1)
234 else:
235 afont = texfont.virtualfont(fontname, fontfile, c, q/self.tfmconv, d/self.tfmconv, self.tfmconv, self.pyxconv, self.debug>1)
237 self.fonts[num] = afont
239 if self.debug:
240 self.debugfile.write("%d: fntdef%d %i: %s\n" % (self.filepos, cmdnr, num, fontname))
242 # scale = round((1000.0*self.conv*q)/(self.trueconv*d))
243 # m = 1.0*q/d
244 # scalestring = scale!=1000 and " scaled %d" % scale or ""
245 # print ("Font %i: %s%s---loaded at size %d DVI units" %
246 # (num, fontname, scalestring, q))
247 # if scale!=1000:
248 # print " (this font is magnified %d%%)" % round(scale/10)
250 def special(self, s, fontmap):
251 x = self.pos[_POS_H] * self.pyxconv
252 y = -self.pos[_POS_V] * self.pyxconv
253 if self.debug:
254 self.debugfile.write("%d: xxx '%s'\n" % (self.filepos, s))
255 if not s.startswith("PyX:"):
256 warnings.warn("ignoring special '%s'" % s)
257 return
259 # it is in general not safe to continue using the currently active font because
260 # the specials may involve some gsave/grestore operations
261 self.flushtext(fontmap)
263 command, args = s[4:].split()[0], s[4:].split()[1:]
264 if command == "color_begin":
265 if args[0] == "cmyk":
266 c = color.cmyk(float(args[1]), float(args[2]), float(args[3]), float(args[4]))
267 elif args[0] == "gray":
268 c = color.gray(float(args[1]))
269 elif args[0] == "hsb":
270 c = color.hsb(float(args[1]), float(args[2]), float(args[3]))
271 elif args[0] == "rgb":
272 c = color.rgb(float(args[1]), float(args[2]), float(args[3]))
273 elif args[0] == "RGB":
274 c = color.rgb(int(args[1])/255.0, int(args[2])/255.0, int(args[3])/255.0)
275 elif args[0] == "texnamed":
276 try:
277 c = getattr(color.cmyk, args[1])
278 except AttributeError:
279 raise RuntimeError("unknown TeX color '%s', aborting" % args[1])
280 elif args[0] == "pyxcolor":
281 # pyx.color.cmyk.PineGreen or
282 # pyx.color.cmyk(0,0,0,0.0)
283 pat = re.compile(r"(pyx\.)?(color\.)?(?P<model>(cmyk)|(rgb)|(grey)|(gray)|(hsb))[\.]?(?P<arg>.*)")
284 sd = pat.match(" ".join(args[1:]))
285 if sd:
286 sd = sd.groupdict()
287 if sd["arg"][0] == "(":
288 numpat = re.compile(r"[+-]?((\d+\.\d*)|(\d*\.\d+)|(\d+))([eE][+-]\d+)?")
289 arg = tuple([float(x[0]) for x in numpat.findall(sd["arg"])])
290 try:
291 c = getattr(color, sd["model"])(*arg)
292 except TypeError or AttributeError:
293 raise RuntimeError("cannot access PyX color '%s' in TeX, aborting" % " ".join(args[1:]))
294 else:
295 try:
296 c = getattr(getattr(color, sd["model"]), sd["arg"])
297 except AttributeError:
298 raise RuntimeError("cannot access PyX color '%s' in TeX, aborting" % " ".join(args[1:]))
299 else:
300 raise RuntimeError("cannot access PyX color '%s' in TeX, aborting" % " ".join(args[1:]))
301 else:
302 raise RuntimeError("color model '%s' cannot be handled by PyX, aborting" % args[0])
303 self.actpage.insert(_savecolor())
304 self.actpage.insert(c)
305 elif command == "color_end":
306 self.actpage.insert(_restorecolor())
307 elif command == "rotate_begin":
308 self.actpage.insert(_savetrafo())
309 self.actpage.insert(trafo.rotate_pt(float(args[0]), x, y))
310 elif command == "rotate_end":
311 self.actpage.insert(_restoretrafo())
312 elif command == "scale_begin":
313 self.actpage.insert(_savetrafo())
314 self.actpage.insert(trafo.scale_pt(float(args[0]), float(args[1]), x, y))
315 elif command == "scale_end":
316 self.actpage.insert(_restoretrafo())
317 elif command == "epsinclude":
318 # parse arguments
319 argdict = {}
320 for arg in args:
321 name, value = arg.split("=")
322 argdict[name] = value
324 # construct kwargs for epsfile constructor
325 epskwargs = {}
326 epskwargs["filename"] = argdict["file"]
327 epskwargs["bbox"] = bbox.bbox_pt(float(argdict["llx"]), float(argdict["lly"]),
328 float(argdict["urx"]), float(argdict["ury"]))
329 if argdict.has_key("width"):
330 epskwargs["width"] = float(argdict["width"]) * unit.t_pt
331 if argdict.has_key("height"):
332 epskwargs["height"] = float(argdict["height"]) * unit.t_pt
333 if argdict.has_key("clip"):
334 epskwargs["clip"] = int(argdict["clip"])
335 self.actpage.insert(epsfile.epsfile(x * unit.t_pt, y * unit.t_pt, **epskwargs))
336 elif command == "marker":
337 if len(args) != 1:
338 raise RuntimeError("marker contains spaces")
339 for c in args[0]:
340 if c not in string.digits + string.letters + "@":
341 raise RuntimeError("marker contains invalid characters")
342 if self.actpage.markers.has_key(args[0]):
343 raise RuntimeError("marker name occurred several times")
344 self.actpage.markers[args[0]] = x * unit.t_pt, y * unit.t_pt
345 else:
346 raise RuntimeError("unknown PyX special '%s', aborting" % command)
348 # routines for pushing and popping different dvi chunks on the reader
350 def _push_dvistring(self, dvi, fonts, afterpos, fontsize, fontmap):
351 """ push dvi string with defined fonts on top of reader
352 stack. Every positions gets scaled relatively by the factor
353 scale. After interpretating the dvi chunk, continue with self.pos=afterpos.
354 The designsize of the virtual font is passed as a fix_word
358 #if self.debug:
359 # self.debugfile.write("executing new dvi chunk\n")
360 self.debugstack.append(self.debug)
361 self.debug = 0
363 self.statestack.append((self.file, self.fonts, self.activefont, afterpos, self.stack, self.scale))
365 # units in vf files are relative to the size of the font and given as fix_words
366 # which can be converted to floats by diving by 2**20.
367 # This yields the following scale factor for the height and width of rects:
368 self.scale = fontsize/2**20/self.pyxconv
370 self.file = reader.stringreader(dvi)
371 self.fonts = fonts
372 self.stack = []
373 self.filepos = 0
375 self.usefont(0, 0, fontmap)
377 def _pop_dvistring(self, fontmap):
378 self.flushtext(fontmap)
379 #if self.debug:
380 # self.debugfile.write("finished executing dvi chunk\n")
381 self.debug = self.debugstack.pop()
383 self.file.close()
384 self.file, self.fonts, self.activefont, self.pos, self.stack, self.scale = self.statestack.pop()
386 # routines corresponding to the different reader states of the dvi maschine
388 def _read_pre(self):
389 afile = self.file
390 while 1:
391 self.filepos = afile.tell()
392 cmd = afile.readuchar()
393 if cmd == _DVI_NOP:
394 pass
395 elif cmd == _DVI_PRE:
396 if afile.readuchar() != _DVI_VERSION: raise DVIError
397 num = afile.readuint32()
398 den = afile.readuint32()
399 self.mag = afile.readuint32()
401 # For the interpretation of the lengths in dvi and tfm files,
402 # three conversion factors are relevant:
403 # - self.tfmconv: tfm units -> dvi units
404 # - self.pyxconv: dvi units -> (PostScript) points
405 # - self.conv: dvi units -> pixels
406 self.tfmconv = (25400000.0/num)*(den/473628672.0)/16.0
408 # calculate conv as described in the DVIType docu using
409 # a given resolution in dpi
410 self.resolution = 300.0
411 self.conv = (num/254000.0)*(self.resolution/den)
413 # self.pyxconv is the conversion factor from the dvi units
414 # to (PostScript) points. It consists of
415 # - self.mag/1000.0: magstep scaling
416 # - self.conv: conversion from dvi units to pixels
417 # - 1/self.resolution: conversion from pixels to inch
418 # - 72 : conversion from inch to points
419 self.pyxconv = self.mag/1000.0*self.conv/self.resolution*72
421 # scaling used for rules when VF chunks are interpreted
422 self.scale = 1
424 comment = afile.read(afile.readuchar())
425 return
426 else:
427 raise DVIError
429 def readpage(self, pageid=None, fontmap=None, singlecharmode=False):
430 """ reads a page from the dvi file
432 This routine reads a page from the dvi file which is
433 returned as a canvas. When there is no page left in the
434 dvifile, None is returned and the file is closed properly."""
436 self.singlecharmode = singlecharmode
438 while 1:
439 self.filepos = self.file.tell()
440 cmd = self.file.readuchar()
441 if cmd == _DVI_NOP:
442 pass
443 elif cmd == _DVI_BOP:
444 ispageid = [self.file.readuint32() for i in range(10)]
445 if pageid is not None and ispageid != pageid:
446 raise DVIError("invalid pageid")
447 if self.debug:
448 self.debugfile.write("%d: beginning of page %i\n" % (self.filepos, ispageid[0]))
449 self.file.readuint32()
450 break
451 elif cmd == _DVI_POST:
452 self.file.close()
453 return None # nothing left
454 else:
455 raise DVIError
457 self.actpage = canvas.canvas()
458 self.actpage.markers = {}
459 self.pos = [0, 0, 0, 0, 0, 0]
461 # tuple (hpos, vpos, codepoints) to be output, or None if no output is pending
462 self.activetext = None
464 while 1:
465 afile = self.file
466 self.filepos = afile.tell()
467 try:
468 cmd = afile.readuchar()
469 except struct.error:
470 # we most probably (if the dvi file is not corrupt) hit the end of a dvi chunk,
471 # so we have to continue with the rest of the dvi file
472 self._pop_dvistring(fontmap)
473 continue
474 if cmd == _DVI_NOP:
475 pass
476 if cmd >= _DVI_CHARMIN and cmd <= _DVI_CHARMAX:
477 self.putchar(cmd, True, 0, fontmap)
478 elif cmd >= _DVI_SET1234 and cmd < _DVI_SET1234 + 4:
479 self.putchar(afile.readint(cmd - _DVI_SET1234 + 1), True, cmd-_DVI_SET1234+1, fontmap)
480 elif cmd == _DVI_SETRULE:
481 self.putrule(afile.readint32()*self.scale, afile.readint32()*self.scale, True, fontmap)
482 elif cmd >= _DVI_PUT1234 and cmd < _DVI_PUT1234 + 4:
483 self.putchar(afile.readint(cmd - _DVI_PUT1234 + 1), False, cmd-_DVI_SET1234+1, fontmap)
484 elif cmd == _DVI_PUTRULE:
485 self.putrule(afile.readint32()*self.scale, afile.readint32()*self.scale, False, fontmap)
486 elif cmd == _DVI_EOP:
487 self.flushtext(fontmap)
488 if self.debug:
489 self.debugfile.write("%d: eop\n \n" % self.filepos)
490 return self.actpage
491 elif cmd == _DVI_PUSH:
492 self.stack.append(list(self.pos))
493 if self.debug:
494 self.debugfile.write("%s: push\n"
495 "level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=???,vv=???)\n" %
496 ((self.filepos, len(self.stack)-1) + tuple(self.pos)))
497 elif cmd == _DVI_POP:
498 self.flushtext(fontmap)
499 self.pos = self.stack.pop()
500 if self.debug:
501 self.debugfile.write("%s: pop\n"
502 "level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=???,vv=???)\n" %
503 ((self.filepos, len(self.stack)) + tuple(self.pos)))
504 elif cmd >= _DVI_RIGHT1234 and cmd < _DVI_RIGHT1234 + 4:
505 self.flushtext(fontmap)
506 dh = afile.readint(cmd - _DVI_RIGHT1234 + 1, 1) * self.scale
507 if self.debug:
508 self.debugfile.write("%d: right%d %d h:=%d%+d=%d, hh:=???\n" %
509 (self.filepos,
510 cmd - _DVI_RIGHT1234 + 1,
512 self.pos[_POS_H],
514 self.pos[_POS_H]+dh))
515 self.pos[_POS_H] += dh
516 elif cmd == _DVI_W0:
517 self.flushtext(fontmap)
518 if self.debug:
519 self.debugfile.write("%d: w0 %d h:=%d%+d=%d, hh:=???\n" %
520 (self.filepos,
521 self.pos[_POS_W],
522 self.pos[_POS_H],
523 self.pos[_POS_W],
524 self.pos[_POS_H]+self.pos[_POS_W]))
525 self.pos[_POS_H] += self.pos[_POS_W]
526 elif cmd >= _DVI_W1234 and cmd < _DVI_W1234 + 4:
527 self.flushtext(fontmap)
528 self.pos[_POS_W] = afile.readint(cmd - _DVI_W1234 + 1, 1) * self.scale
529 if self.debug:
530 self.debugfile.write("%d: w%d %d h:=%d%+d=%d, hh:=???\n" %
531 (self.filepos,
532 cmd - _DVI_W1234 + 1,
533 self.pos[_POS_W],
534 self.pos[_POS_H],
535 self.pos[_POS_W],
536 self.pos[_POS_H]+self.pos[_POS_W]))
537 self.pos[_POS_H] += self.pos[_POS_W]
538 elif cmd == _DVI_X0:
539 self.flushtext(fontmap)
540 if self.debug:
541 self.debugfile.write("%d: x0 %d h:=%d%+d=%d, hh:=???\n" %
542 (self.filepos,
543 self.pos[_POS_X],
544 self.pos[_POS_H],
545 self.pos[_POS_X],
546 self.pos[_POS_H]+self.pos[_POS_X]))
547 self.pos[_POS_H] += self.pos[_POS_X]
548 elif cmd >= _DVI_X1234 and cmd < _DVI_X1234 + 4:
549 self.flushtext(fontmap)
550 self.pos[_POS_X] = afile.readint(cmd - _DVI_X1234 + 1, 1) * self.scale
551 if self.debug:
552 self.debugfile.write("%d: x%d %d h:=%d%+d=%d, hh:=???\n" %
553 (self.filepos,
554 cmd - _DVI_X1234 + 1,
555 self.pos[_POS_X],
556 self.pos[_POS_H],
557 self.pos[_POS_X],
558 self.pos[_POS_H]+self.pos[_POS_X]))
559 self.pos[_POS_H] += self.pos[_POS_X]
560 elif cmd >= _DVI_DOWN1234 and cmd < _DVI_DOWN1234 + 4:
561 self.flushtext(fontmap)
562 dv = afile.readint(cmd - _DVI_DOWN1234 + 1, 1) * self.scale
563 if self.debug:
564 self.debugfile.write("%d: down%d %d v:=%d%+d=%d, vv:=???\n" %
565 (self.filepos,
566 cmd - _DVI_DOWN1234 + 1,
568 self.pos[_POS_V],
570 self.pos[_POS_V]+dv))
571 self.pos[_POS_V] += dv
572 elif cmd == _DVI_Y0:
573 self.flushtext(fontmap)
574 if self.debug:
575 self.debugfile.write("%d: y0 %d v:=%d%+d=%d, vv:=???\n" %
576 (self.filepos,
577 self.pos[_POS_Y],
578 self.pos[_POS_V],
579 self.pos[_POS_Y],
580 self.pos[_POS_V]+self.pos[_POS_Y]))
581 self.pos[_POS_V] += self.pos[_POS_Y]
582 elif cmd >= _DVI_Y1234 and cmd < _DVI_Y1234 + 4:
583 self.flushtext(fontmap)
584 self.pos[_POS_Y] = afile.readint(cmd - _DVI_Y1234 + 1, 1) * self.scale
585 if self.debug:
586 self.debugfile.write("%d: y%d %d v:=%d%+d=%d, vv:=???\n" %
587 (self.filepos,
588 cmd - _DVI_Y1234 + 1,
589 self.pos[_POS_Y],
590 self.pos[_POS_V],
591 self.pos[_POS_Y],
592 self.pos[_POS_V]+self.pos[_POS_Y]))
593 self.pos[_POS_V] += self.pos[_POS_Y]
594 elif cmd == _DVI_Z0:
595 self.flushtext(fontmap)
596 if self.debug:
597 self.debugfile.write("%d: z0 %d v:=%d%+d=%d, vv:=???\n" %
598 (self.filepos,
599 self.pos[_POS_Z],
600 self.pos[_POS_V],
601 self.pos[_POS_Z],
602 self.pos[_POS_V]+self.pos[_POS_Z]))
603 self.pos[_POS_V] += self.pos[_POS_Z]
604 elif cmd >= _DVI_Z1234 and cmd < _DVI_Z1234 + 4:
605 self.flushtext(fontmap)
606 self.pos[_POS_Z] = afile.readint(cmd - _DVI_Z1234 + 1, 1) * self.scale
607 if self.debug:
608 self.debugfile.write("%d: z%d %d v:=%d%+d=%d, vv:=???\n" %
609 (self.filepos,
610 cmd - _DVI_Z1234 + 1,
611 self.pos[_POS_Z],
612 self.pos[_POS_V],
613 self.pos[_POS_Z],
614 self.pos[_POS_V]+self.pos[_POS_Z]))
615 self.pos[_POS_V] += self.pos[_POS_Z]
616 elif cmd >= _DVI_FNTNUMMIN and cmd <= _DVI_FNTNUMMAX:
617 self.usefont(cmd - _DVI_FNTNUMMIN, 0, fontmap)
618 elif cmd >= _DVI_FNT1234 and cmd < _DVI_FNT1234 + 4:
619 # note that according to the DVI docs, for four byte font numbers,
620 # the font number is signed. Don't ask why!
621 fntnum = afile.readint(cmd - _DVI_FNT1234 + 1, cmd == _DVI_FNT1234 + 3)
622 self.usefont(fntnum, cmd-_DVI_FNT1234+1, fontmap)
623 elif cmd >= _DVI_SPECIAL1234 and cmd < _DVI_SPECIAL1234 + 4:
624 self.special(afile.read(afile.readint(cmd - _DVI_SPECIAL1234 + 1)), fontmap)
625 elif cmd >= _DVI_FNTDEF1234 and cmd < _DVI_FNTDEF1234 + 4:
626 if cmd == _DVI_FNTDEF1234:
627 num = afile.readuchar()
628 elif cmd == _DVI_FNTDEF1234+1:
629 num = afile.readuint16()
630 elif cmd == _DVI_FNTDEF1234+2:
631 num = afile.readuint24()
632 elif cmd == _DVI_FNTDEF1234+3:
633 # Cool, here we have according to docu a signed int. Why?
634 num = afile.readint32()
635 self.definefont(cmd-_DVI_FNTDEF1234+1,
636 num,
637 afile.readint32(),
638 afile.readint32(),
639 afile.readint32(),
640 afile.read(afile.readuchar()+afile.readuchar()))
641 else:
642 raise DVIError