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