From 0b67f7fe0ba44035e6df067d1443daaab0acb629 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Wobst?= Date: Wed, 24 Oct 2007 07:23:28 +0000 Subject: [PATCH] allow fontmap as a parameter of the text method git-svn-id: https://pyx.svn.sourceforge.net/svnroot/pyx/trunk/pyx@2938 069f4177-920e-0410-937b-c2a4a81bcd90 --- CHANGES | 4 ++- pyx/dvi/dvifile.py | 74 ++++++++++++++++++++++---------------------- pyx/dvi/mapfile.py | 2 +- pyx/dvi/texfont.py | 14 ++++++--- pyx/text.py | 7 +++-- test/functional/test_text.py | 10 +++--- 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/CHANGES b/CHANGES index 84e9a29d..fc4ef52e 100644 --- a/CHANGES +++ b/CHANGES @@ -97,7 +97,9 @@ TODO: - major reorganization - TeX mapping files are a property of the writer now (TODO: documentation) By that the pdfwriter now uses pdftex.map instead of psfonts.map - - support for font matrices (afm, pfm) for Type1 fonts + (It's also possible to pass a fontmap to a texrunners text method to use + different mappings within a single output file) + - support for font matrices (afm) for Type1 fonts (using fonts without a metrics is still supported, but properly issues a warning now) - interface for basic TeX-less text output diff --git a/pyx/dvi/dvifile.py b/pyx/dvi/dvifile.py index 46557ccc..98a84f7a 100644 --- a/pyx/dvi/dvifile.py +++ b/pyx/dvi/dvifile.py @@ -141,18 +141,18 @@ class DVIfile: # helper routines - def flushtext(self): + def flushtext(self, fontmap): """ finish currently active text object """ if self.activetext: x, y, charcodes = self.activetext x_pt, y_pt = x * self.pyxconv, -y*self.pyxconv - self.actpage.insert(self.activefont.text_pt(x_pt, y_pt, charcodes)) + self.actpage.insert(self.activefont.text_pt(x_pt, y_pt, charcodes, fontmap=fontmap)) if self.debug: self.debugfile.write("[%s]\n" % "".join([chr(char) for char in self.activetext[2]])) self.activetext = None - def putrule(self, height, width, advancepos=1): - self.flushtext() + def putrule(self, height, width, advancepos, fontmap): + self.flushtext(fontmap) x1 = self.pos[_POS_H] * self.pyxconv y1 = -self.pos[_POS_V] * self.pyxconv w = width * self.pyxconv @@ -174,7 +174,7 @@ class DVIfile: (self.pos[_POS_H], width, self.pos[_POS_H]+width)) self.pos[_POS_H] += width - def putchar(self, char, advancepos=1, id1234=0): + def putchar(self, char, advancepos, id1234, fontmap): dx = advancepos and self.activefont.getwidth_dvi(char) or 0 if self.debug: @@ -190,7 +190,7 @@ class DVIfile: afterpos = list(self.pos) afterpos[_POS_H] += dx self._push_dvistring(self.activefont.getchar(char), self.activefont.getfonts(), afterpos, - self.activefont.getsize_pt()) + self.activefont.getsize_pt(), fontmap) else: if self.activetext is None: self.activetext = (self.pos[_POS_H], self.pos[_POS_V], []) @@ -198,10 +198,10 @@ class DVIfile: self.pos[_POS_H] += dx if not advancepos: - self.flushtext() + self.flushtext(fontmap) - def usefont(self, fontnum, id1234=0): - self.flushtext() + def usefont(self, fontnum, id1234, fontmap): + self.flushtext(fontmap) self.activefont = self.fonts[fontnum] if self.debug: self.debugfile.write("%d: fnt%s%i current font is %s\n" % @@ -238,7 +238,7 @@ class DVIfile: # if scale!=1000: # print " (this font is magnified %d%%)" % round(scale/10) - def special(self, s): + def special(self, s, fontmap): x = self.pos[_POS_H] * self.pyxconv y = -self.pos[_POS_V] * self.pyxconv if self.debug: @@ -249,7 +249,7 @@ class DVIfile: # it is in general not safe to continue using the currently active font because # the specials may involve some gsave/grestore operations - self.flushtext() + self.flushtext(fontmap) command, args = s[4:].split()[0], s[4:].split()[1:] if command == "color_begin": @@ -338,7 +338,7 @@ class DVIfile: # routines for pushing and popping different dvi chunks on the reader - def _push_dvistring(self, dvi, fonts, afterpos, fontsize): + def _push_dvistring(self, dvi, fonts, afterpos, fontsize, fontmap): """ push dvi string with defined fonts on top of reader stack. Every positions gets scaled relatively by the factor scale. After the interpreting of the dvi chunk has been finished, @@ -371,10 +371,10 @@ class DVIfile: # since tfmconv converts from tfm units to dvi units, rescale it as well self.tfmconv /= rescale - self.usefont(0) + self.usefont(0, 0, fontmap) - def _pop_dvistring(self): - self.flushtext() + def _pop_dvistring(self, fontmap): + self.flushtext(fontmap) #if self.debug: # self.debugfile.write("finished executing dvi chunk\n") self.debug = self.debugstack.pop() @@ -422,7 +422,7 @@ class DVIfile: else: raise DVIError - def readpage(self, pageid=None): + def readpage(self, pageid=None, fontmap=None): """ reads a page from the dvi file This routine reads a page from the dvi file which is @@ -463,22 +463,22 @@ class DVIfile: except struct.error: # we most probably (if the dvi file is not corrupt) hit the end of a dvi chunk, # so we have to continue with the rest of the dvi file - self._pop_dvistring() + self._pop_dvistring(fontmap) continue if cmd == _DVI_NOP: pass if cmd >= _DVI_CHARMIN and cmd <= _DVI_CHARMAX: - self.putchar(cmd) + self.putchar(cmd, True, 0, fontmap) elif cmd >= _DVI_SET1234 and cmd < _DVI_SET1234 + 4: - self.putchar(afile.readint(cmd - _DVI_SET1234 + 1), id1234=cmd-_DVI_SET1234+1) + self.putchar(afile.readint(cmd - _DVI_SET1234 + 1), True, cmd-_DVI_SET1234+1, fontmap) elif cmd == _DVI_SETRULE: - self.putrule(afile.readint32(), afile.readint32()) + self.putrule(afile.readint32(), afile.readint32(), True, fontmap) elif cmd >= _DVI_PUT1234 and cmd < _DVI_PUT1234 + 4: - self.putchar(afile.readint(cmd - _DVI_PUT1234 + 1), advancepos=0, id1234=cmd-_DVI_SET1234+1) + self.putchar(afile.readint(cmd - _DVI_PUT1234 + 1), False, cmd-_DVI_SET1234+1, fontmap) elif cmd == _DVI_PUTRULE: - self.putrule(afile.readint32(), afile.readint32(), 0) + self.putrule(afile.readint32(), afile.readint32(), False, fontmap) elif cmd == _DVI_EOP: - self.flushtext() + self.flushtext(fontmap) if self.debug: self.debugfile.write("%d: eop\n \n" % self.filepos) return self.actpage @@ -489,14 +489,14 @@ class DVIfile: "level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=???,vv=???)\n" % ((self.filepos, len(self.stack)-1) + tuple(self.pos))) elif cmd == _DVI_POP: - self.flushtext() + self.flushtext(fontmap) self.pos = self.stack.pop() if self.debug: self.debugfile.write("%s: pop\n" "level %d:(h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=???,vv=???)\n" % ((self.filepos, len(self.stack)) + tuple(self.pos))) elif cmd >= _DVI_RIGHT1234 and cmd < _DVI_RIGHT1234 + 4: - self.flushtext() + self.flushtext(fontmap) dh = afile.readint(cmd - _DVI_RIGHT1234 + 1, 1) if self.debug: self.debugfile.write("%d: right%d %d h:=%d%+d=%d, hh:=???\n" % @@ -508,7 +508,7 @@ class DVIfile: self.pos[_POS_H]+dh)) self.pos[_POS_H] += dh elif cmd == _DVI_W0: - self.flushtext() + self.flushtext(fontmap) if self.debug: self.debugfile.write("%d: w0 %d h:=%d%+d=%d, hh:=???\n" % (self.filepos, @@ -518,7 +518,7 @@ class DVIfile: self.pos[_POS_H]+self.pos[_POS_W])) self.pos[_POS_H] += self.pos[_POS_W] elif cmd >= _DVI_W1234 and cmd < _DVI_W1234 + 4: - self.flushtext() + self.flushtext(fontmap) self.pos[_POS_W] = afile.readint(cmd - _DVI_W1234 + 1, 1) if self.debug: self.debugfile.write("%d: w%d %d h:=%d%+d=%d, hh:=???\n" % @@ -530,7 +530,7 @@ class DVIfile: self.pos[_POS_H]+self.pos[_POS_W])) self.pos[_POS_H] += self.pos[_POS_W] elif cmd == _DVI_X0: - self.flushtext() + self.flushtext(fontmap) if self.debug: self.debugfile.write("%d: x0 %d h:=%d%+d=%d, hh:=???\n" % (self.filepos, @@ -540,7 +540,7 @@ class DVIfile: self.pos[_POS_H]+self.pos[_POS_X])) self.pos[_POS_H] += self.pos[_POS_X] elif cmd >= _DVI_X1234 and cmd < _DVI_X1234 + 4: - self.flushtext() + self.flushtext(fontmap) self.pos[_POS_X] = afile.readint(cmd - _DVI_X1234 + 1, 1) if self.debug: self.debugfile.write("%d: x%d %d h:=%d%+d=%d, hh:=???\n" % @@ -552,7 +552,7 @@ class DVIfile: self.pos[_POS_H]+self.pos[_POS_X])) self.pos[_POS_H] += self.pos[_POS_X] elif cmd >= _DVI_DOWN1234 and cmd < _DVI_DOWN1234 + 4: - self.flushtext() + self.flushtext(fontmap) dv = afile.readint(cmd - _DVI_DOWN1234 + 1, 1) if self.debug: self.debugfile.write("%d: down%d %d v:=%d%+d=%d, vv:=???\n" % @@ -564,7 +564,7 @@ class DVIfile: self.pos[_POS_V]+dv)) self.pos[_POS_V] += dv elif cmd == _DVI_Y0: - self.flushtext() + self.flushtext(fontmap) if self.debug: self.debugfile.write("%d: y0 %d v:=%d%+d=%d, vv:=???\n" % (self.filepos, @@ -574,7 +574,7 @@ class DVIfile: self.pos[_POS_V]+self.pos[_POS_Y])) self.pos[_POS_V] += self.pos[_POS_Y] elif cmd >= _DVI_Y1234 and cmd < _DVI_Y1234 + 4: - self.flushtext() + self.flushtext(fontmap) self.pos[_POS_Y] = afile.readint(cmd - _DVI_Y1234 + 1, 1) if self.debug: self.debugfile.write("%d: y%d %d v:=%d%+d=%d, vv:=???\n" % @@ -586,7 +586,7 @@ class DVIfile: self.pos[_POS_V]+self.pos[_POS_Y])) self.pos[_POS_V] += self.pos[_POS_Y] elif cmd == _DVI_Z0: - self.flushtext() + self.flushtext(fontmap) if self.debug: self.debugfile.write("%d: z0 %d v:=%d%+d=%d, vv:=???\n" % (self.filepos, @@ -596,7 +596,7 @@ class DVIfile: self.pos[_POS_V]+self.pos[_POS_Z])) self.pos[_POS_V] += self.pos[_POS_Z] elif cmd >= _DVI_Z1234 and cmd < _DVI_Z1234 + 4: - self.flushtext() + self.flushtext(fontmap) self.pos[_POS_Z] = afile.readint(cmd - _DVI_Z1234 + 1, 1) if self.debug: self.debugfile.write("%d: z%d %d v:=%d%+d=%d, vv:=???\n" % @@ -608,14 +608,14 @@ class DVIfile: self.pos[_POS_V]+self.pos[_POS_Z])) self.pos[_POS_V] += self.pos[_POS_Z] elif cmd >= _DVI_FNTNUMMIN and cmd <= _DVI_FNTNUMMAX: - self.usefont(cmd - _DVI_FNTNUMMIN, 0) + self.usefont(cmd - _DVI_FNTNUMMIN, 0, fontmap) elif cmd >= _DVI_FNT1234 and cmd < _DVI_FNT1234 + 4: # note that according to the DVI docs, for four byte font numbers, # the font number is signed. Don't ask why! fntnum = afile.readint(cmd - _DVI_FNT1234 + 1, cmd == _DVI_FNT1234 + 3) - self.usefont(fntnum, id1234=cmd-_DVI_FNT1234+1) + self.usefont(fntnum, cmd-_DVI_FNT1234+1, fontmap) elif cmd >= _DVI_SPECIAL1234 and cmd < _DVI_SPECIAL1234 + 4: - self.special(afile.read(afile.readint(cmd - _DVI_SPECIAL1234 + 1))) + self.special(afile.read(afile.readint(cmd - _DVI_SPECIAL1234 + 1)), fontmap) elif cmd >= _DVI_FNTDEF1234 and cmd < _DVI_FNTDEF1234 + 4: if cmd == _DVI_FNTDEF1234: num = afile.readuchar() diff --git a/pyx/dvi/mapfile.py b/pyx/dvi/mapfile.py index 62ed986b..2fc2a83f 100644 --- a/pyx/dvi/mapfile.py +++ b/pyx/dvi/mapfile.py @@ -104,7 +104,7 @@ class MAPline: else: afmfilename = "%s.afm" % self.basepsname metricpath = pykpathsea.find_file(afmfilename, pykpathsea.kpse_afm_format) - if metricpath is None: + if not metricpath: raise RuntimeError("cannot find type 1 font metric %s" % afmfilename) self._font = font.T1builtinfont(self.basepsname, afmfile.AFMfile(metricpath)) return self._font diff --git a/pyx/dvi/texfont.py b/pyx/dvi/texfont.py index 02c85bd0..97478f0e 100644 --- a/pyx/dvi/texfont.py +++ b/pyx/dvi/texfont.py @@ -106,8 +106,8 @@ class TeXfont: def getitalic_pt(self, charcode): return self._convert_tfm_to_pt(self.TFMfile.italic[self.TFMfile.char_info[charcode].italic_index]) - def text_pt(self, x_pt, y_pt, charcodes): - return TeXtext_pt(self, x_pt, y_pt, charcodes, self.getsize_pt()) + def text_pt(self, x_pt, y_pt, charcodes, fontmap=None): + return TeXtext_pt(self, x_pt, y_pt, charcodes, self.getsize_pt(), fontmap=fontmap) def getMAPline(self, fontmap): if self.name not in fontmap: @@ -129,18 +129,19 @@ class virtualfont(TeXfont): """ return dvi chunk corresponding to char code cc """ return self.vffile.getchar(cc) - def text_pt(self, x_pt, y_pt, charcodes): + def text_pt(self, *args, **kwargs): raise RuntimeError("you don't know what you're doing") class TeXtext_pt(font.text_pt): - def __init__(self, font, x_pt, y_pt, charcodes, size_pt): + def __init__(self, font, x_pt, y_pt, charcodes, size_pt, fontmap=None): self.font = font self.x_pt = x_pt self.y_pt = y_pt self.charcodes = charcodes self.size_pt = size_pt + self.fontmap = fontmap self.width_pt = sum([self.font.getwidth_pt(charcode) for charcode in charcodes]) self.height_pt = max([self.font.getheight_pt(charcode) for charcode in charcodes]) @@ -153,7 +154,10 @@ class TeXtext_pt(font.text_pt): def processPS(self, file, writer, context, registry, bbox): bbox += self.bbox() - mapline = self.font.getMAPline(writer.getfontmap()) + if self.fontmap is not None: + mapline = self.font.getMAPline(self.fontmap) + else: + mapline = self.font.getMAPline(writer.getfontmap()) font = mapline.getfont() text = font.text_pt(self.x_pt, self.y_pt, self.charcodes, self.size_pt, decoding=mapline.getencoding(), slant=mapline.slant, ignorebbox=True) text.processPS(file, writer, context, registry, bbox) diff --git a/pyx/text.py b/pyx/text.py index efe977d1..dccf7797 100644 --- a/pyx/text.py +++ b/pyx/text.py @@ -1045,7 +1045,7 @@ class texrunner: self.dvifile = dvifile.DVIfile(dvifilename, debug=self.dvidebug) page = 1 for box in self.needdvitextboxes: - box.setdvicanvas(self.dvifile.readpage([ord("P"), ord("y"), ord("X"), page, 0, 0, 0, 0, 0, 0])) + box.setdvicanvas(self.dvifile.readpage([ord("P"), ord("y"), ord("X"), page, 0, 0, 0, 0, 0, 0], fontmap=box.fontmap)) page += 1 if not ignoretail and self.dvifile.readpage(None) is not None: raise RuntimeError("end of dvifile expected") @@ -1162,7 +1162,7 @@ class texrunner: PyXBoxPattern = re.compile(r"PyXBox:page=(?P\d+),lt=(?P-?\d*((\d\.?)|(\.?\d))\d*)pt,rt=(?P-?\d*((\d\.?)|(\.?\d))\d*)pt,ht=(?P-?\d*((\d\.?)|(\.?\d))\d*)pt,dp=(?P-?\d*((\d\.?)|(\.?\d))\d*)pt:") - def text(self, x, y, expr, textattrs=[], texmessages=[]): + def text(self, x, y, expr, textattrs=[], texmessages=[], fontmap=None): """create text by passing expr to TeX/LaTeX - returns a textbox containing the result from running expr thru TeX/LaTeX - the box center is set to x, y @@ -1208,8 +1208,9 @@ class texrunner: # this is quite different from what we do elsewhere!!! # see https://sourceforge.net/mailarchive/forum.php?thread_id=9137692&forum_id=23700 if self.texipc: - box.setdvicanvas(self.dvifile.readpage([ord("P"), ord("y"), ord("X"), self.page, 0, 0, 0, 0, 0, 0])) + box.setdvicanvas(self.dvifile.readpage([ord("P"), ord("y"), ord("X"), self.page, 0, 0, 0, 0, 0, 0], fontmap=fontmap)) else: + box.fontmap = fontmap self.needdvitextboxes.append(box) return box diff --git a/test/functional/test_text.py b/test/functional/test_text.py index aea5cdd4..4ebc8208 100755 --- a/test/functional/test_text.py +++ b/test/functional/test_text.py @@ -62,14 +62,16 @@ unit.set(xscale=1) t = c.text(0, 11, r"scale test", [color.rgb.red]) # test font stripping (proper usedchar selection) +from pyx.dvi import mapfile +fontmap = mapfile.readfontmap(["download35.map"]) c.text(0, 12, r"usechar test (``fl'' should be typed):") -myrunner = text.texrunner(fontmaps="download35.map") +myrunner = text.texrunner() myrunner.preamble(r"\font\pyxfont=phvr8t\pyxfont") -c.insert(myrunner.text(5.5, 12, r"\char'035")) +c.insert(myrunner.text(5.5, 12, r"\char'035", fontmap=fontmap)) -myrunner2 = text.texrunner(fontmaps="download35.map") +myrunner2 = text.texrunner() myrunner2.preamble(r"\font\pyxfont=ptmr8t\pyxfont") -c.insert(myrunner2.text(6.5, 12, r"\char'035")) +c.insert(myrunner2.text(6.5, 12, r"\char'035", fontmap=fontmap)) # test the specials c.stroke(c.text(10, 2, r"Hello, \color{green}world!", [trafo.slant(1)]).path()) -- 2.11.4.GIT