~ubuntu-branches/debian/sid/pyx/sid

« back to all changes in this revision

Viewing changes to pyx/dvi/dvifile.py

  • Committer: Bazaar Package Importer
  • Author(s): Stuart Prescott
  • Date: 2011-05-20 00:13:52 UTC
  • mto: (9.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20110520001352-odcuqpdezuusbbw1
Tags: upstream-0.11.1
Import upstream version 0.11.1

Show diffs side-by-side

added added

removed removed

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