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 io
, logging
, math
, re
, string
, struct
, sys
25 from pyx
import bbox
, canvas
, color
, epsfile
, config
, path
, reader
, trafo
, unit
26 from . import texfont
, tfmfile
28 logger
= logging
.getLogger("pyx")
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
61 _DVI_VERSION
= 2 # dvi version
63 # position variable indices
75 _READ_POST
= 4 # XXX not used
76 _READ_POSTPOST
= 5 # XXX not used
80 class DVIError(Exception): pass
85 def __init__(self
, filename
, debug
=0, debugfile
=sys
.stdout
):
86 """ opens the dvi file and reads the preamble """
87 self
.filename
= filename
89 self
.debugfile
= debugfile
93 self
.activefont
= None
95 # stack of fonts and fontscale currently used (used for VFs)
99 # pointer to currently active page
102 # stack for self.file, self.fonts and self.stack, needed for VF inclusion
105 self
.file = reader
.reader(self
.filename
)
107 # currently read byte in file (for debugging output)
114 def beginsubpage(self
, attrs
):
115 c
= canvas
.canvas(attrs
)
116 c
.parent
= self
.actpage
118 self
.actpage
.insert(c
)
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
126 def flushtext(self
, fontmap
):
127 """ finish currently active text object """
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
))
133 self
.debugfile
.write("[%s]\n" % "".join([chr(char
) for char
in self
.activetext
[2]]))
134 self
.activetext
= None
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
143 if height
> 0 and width
> 0:
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
))
150 self
.debugfile
.write("%d: %srule height %d, width %d (invisible)\n" %
151 (self
.filepos
, advancepos
and "set" or "put", height
, width
))
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
159 def putchar(self
, char
, advancepos
, id1234
, fontmap
):
160 dx
= advancepos
and self
.activefont
.getwidth_dvi(char
) or 0
163 self
.debugfile
.write("%d: %s%s%d h:=%d+%d=%d, hh:=???\n" %
165 advancepos
and "set" or "put",
166 id1234
and "%i " % id1234
or "char",
168 self
.pos
[_POS_H
], dx
, self
.pos
[_POS_H
]+dx
))
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
)
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
182 if (not advancepos
) or self
.singlecharmode
:
183 self
.flushtext(fontmap
)
185 def usefont(self
, fontnum
, id1234
, fontmap
):
186 self
.flushtext(fontmap
)
187 self
.activefont
= self
.fonts
[fontnum
]
189 self
.debugfile
.write("%d: fnt%s%i current font is %s\n" %
191 id1234
and "%i " % id1234
or "num",
193 self
.fonts
[fontnum
].name
))
196 def definefont(self
, cmdnr
, num
, c
, q
, d
, fontname
):
197 # cmdnr: type of fontdef command (only used for debugging output)
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)
203 # check whether it's a virtual font by trying to open it. if this fails, it is an ordinary TeX font
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)
210 self
.fonts
[num
] = afont
213 self
.debugfile
.write("%d: fntdef%d %i: %s\n" % (self
.filepos
, cmdnr
, num
, fontname
))
215 # scale = round((1000.0*self.conv*q)/(self.trueconv*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))
221 # print " (this font is magnified %d%%)" % round(scale/10)
223 def special(self
, s
, fontmap
):
224 x
= self
.pos
[_POS_H
] * self
.pyxconv
225 y
= -self
.pos
[_POS_V
] * self
.pyxconv
227 self
.debugfile
.write("%d: xxx '%s'\n" % (self
.filepos
, s
))
228 if not s
.startswith("PyX:"):
229 logger
.warning("ignoring special '%s'" % s
)
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
)
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":
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:]))
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"])])
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:]))
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:]))
273 raise RuntimeError("cannot access PyX color '%s' in TeX, aborting" % " ".join(args
[1:]))
275 raise RuntimeError("color model '%s' cannot be handled by PyX, aborting" % args
[0])
277 self
.beginsubpage([c
])
278 elif command
== "color_end":
280 elif command
== "rotate_begin":
281 self
.beginsubpage([trafo
.rotate_pt(float(args
[0]), x
, y
)])
282 elif command
== "rotate_end":
284 elif command
== "scale_begin":
285 self
.beginsubpage([trafo
.scale_pt(float(args
[0]), float(args
[1]), x
, y
)])
286 elif command
== "scale_end":
288 elif command
== "epsinclude":
292 name
, value
= arg
.split("=")
293 argdict
[name
] = value
295 # construct kwargs for epsfile constructor
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":
309 raise RuntimeError("marker contains spaces")
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
317 raise RuntimeError("unknown PyX special '%s', aborting" % command
)
319 # routines for pushing and popping different dvi chunks on the reader
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
330 # self.debugfile.write("executing new dvi chunk\n")
331 self
.debugstack
.append(self
.debug
)
334 self
.statestack
.append((self
.file, self
.fonts
, self
.activefont
, afterpos
, self
.stack
, self
.scale
))
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
341 self
.file = reader
.bytesreader(dvi
)
346 self
.usefont(0, 0, fontmap
)
348 def _pop_dvistring(self
, fontmap
):
349 self
.flushtext(fontmap
)
351 # self.debugfile.write("finished executing dvi chunk\n")
352 self
.debug
= self
.debugstack
.pop()
355 self
.file, self
.fonts
, self
.activefont
, self
.pos
, self
.stack
, self
.scale
= self
.statestack
.pop()
357 # routines corresponding to the different reader states of the dvi maschine
362 self
.filepos
= afile
.tell()
363 cmd
= afile
.readuchar()
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()
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
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
)
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
392 # scaling used for rules when VF chunks are interpreted
395 comment
= afile
.read(afile
.readuchar())
400 def readpage(self
, pageid
=None, fontmap
=None, singlecharmode
=False, attrs
=[]):
401 """ reads a page from the dvi file
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."""
407 self
.singlecharmode
= singlecharmode
410 self
.filepos
= self
.file.tell()
411 cmd
= self
.file.readuchar()
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")
419 self
.debugfile
.write("%d: beginning of page %i\n" % (self
.filepos
, ispageid
[0]))
420 self
.file.readuint32()
422 elif cmd
== _DVI_POST
:
424 return None # nothing left
428 self
.actpage
= canvas
.canvas(attrs
)
429 self
.actpage
.markers
= {}
430 self
.pos
= [0, 0, 0, 0, 0, 0]
432 # tuple (hpos, vpos, codepoints) to be output, or None if no output is pending
433 self
.activetext
= None
437 self
.filepos
= afile
.tell()
439 cmd
= afile
.readuchar()
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
)
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
)
460 self
.debugfile
.write("%d: eop\n \n" % self
.filepos
)
462 elif cmd
== _DVI_PUSH
:
463 self
.stack
.append(list(self
.pos
))
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()
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
479 self
.debugfile
.write("%d: right%d %d h:=%d%+d=%d, hh:=???\n" %
481 cmd
- _DVI_RIGHT1234
+ 1,
485 self
.pos
[_POS_H
]+dh
))
486 self
.pos
[_POS_H
] += dh
488 self
.flushtext(fontmap
)
490 self
.debugfile
.write("%d: w0 %d h:=%d%+d=%d, hh:=???\n" %
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
501 self
.debugfile
.write("%d: w%d %d h:=%d%+d=%d, hh:=???\n" %
503 cmd
- _DVI_W1234
+ 1,
507 self
.pos
[_POS_H
]+self
.pos
[_POS_W
]))
508 self
.pos
[_POS_H
] += self
.pos
[_POS_W
]
510 self
.flushtext(fontmap
)
512 self
.debugfile
.write("%d: x0 %d h:=%d%+d=%d, hh:=???\n" %
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
523 self
.debugfile
.write("%d: x%d %d h:=%d%+d=%d, hh:=???\n" %
525 cmd
- _DVI_X1234
+ 1,
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
535 self
.debugfile
.write("%d: down%d %d v:=%d%+d=%d, vv:=???\n" %
537 cmd
- _DVI_DOWN1234
+ 1,
541 self
.pos
[_POS_V
]+dv
))
542 self
.pos
[_POS_V
] += dv
544 self
.flushtext(fontmap
)
546 self
.debugfile
.write("%d: y0 %d v:=%d%+d=%d, vv:=???\n" %
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
557 self
.debugfile
.write("%d: y%d %d v:=%d%+d=%d, vv:=???\n" %
559 cmd
- _DVI_Y1234
+ 1,
563 self
.pos
[_POS_V
]+self
.pos
[_POS_Y
]))
564 self
.pos
[_POS_V
] += self
.pos
[_POS_Y
]
566 self
.flushtext(fontmap
)
568 self
.debugfile
.write("%d: z0 %d v:=%d%+d=%d, vv:=???\n" %
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
579 self
.debugfile
.write("%d: z%d %d v:=%d%+d=%d, vv:=???\n" %
581 cmd
- _DVI_Z1234
+ 1,
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,
611 afile
.read(afile
.readuchar()+afile
.readuchar()).decode("ascii"))