From: <md...@us...> - 2007-08-30 15:12:29
|
Revision: 3758 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3758&view=rev Author: mdboom Date: 2007-08-30 08:12:27 -0700 (Thu, 30 Aug 2007) Log Message: ----------- Deal with Unicode and non-ASCII characters correctly when outputting Postscript with ps.useafm == True. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/afm.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py Modified: trunk/matplotlib/lib/matplotlib/afm.py =================================================================== --- trunk/matplotlib/lib/matplotlib/afm.py 2007-08-30 15:11:23 UTC (rev 3757) +++ trunk/matplotlib/lib/matplotlib/afm.py 2007-08-30 15:12:27 UTC (rev 3758) @@ -34,8 +34,8 @@ John D. Hunter <jdh...@ac...> """ - import sys, os +from _mathtext_data import uni2type1 #Convert string the a python type _to_int = int @@ -152,12 +152,13 @@ all the sample afm files I have """ - d = {} + ascii_d = {} + name_d = {} while 1: line = fh.readline() if not line: break line = line.rstrip() - if line.startswith('EndCharMetrics'): return d + if line.startswith('EndCharMetrics'): return ascii_d, name_d vals = line.split(';')[:4] if len(vals) !=4 : raise RuntimeError('Bad char metrics line: %s' % line) num = _to_int(vals[0].split()[1]) @@ -169,7 +170,8 @@ if name == 'Euro': num = 128 if num != -1: - d[num] = (wx, name, bbox) + ascii_d[num] = (wx, name, bbox) + name_d[name] = (wx, bbox) raise RuntimeError('Bad parse') def _parse_kern_pairs(fh): @@ -277,9 +279,9 @@ """ _sanity_check(fh) dhead = _parse_header(fh) - dcmetrics = _parse_char_metrics(fh) + dcmetrics_ascii, dcmetrics_name = _parse_char_metrics(fh) doptional = _parse_optional(fh) - return dhead, dcmetrics, doptional[0], doptional[1] + return dhead, dcmetrics_ascii, dcmetrics_name, doptional[0], doptional[1] class AFM: @@ -288,10 +290,12 @@ """ Parse the AFM file in file object fh """ - (dhead, dcmetrics, dkernpairs, dcomposite) = parse_afm(fh) + (dhead, dcmetrics_ascii, dcmetrics_name, dkernpairs, dcomposite) = \ + parse_afm(fh) self._header = dhead self._kern = dkernpairs - self._metrics = dcmetrics + self._metrics = dcmetrics_ascii + self._metrics_by_name = dcmetrics_name self._composite = dcomposite @@ -340,9 +344,16 @@ miny = 1e9 maxy = 0 left = 0 + if not isinstance(s, unicode): + s = s.decode() for c in s: if c == '\n': continue - wx, name, bbox = self._metrics[ord(c)] + name = uni2type1.get(ord(c), 'question') + try: + wx, bbox = self._metrics_by_name[name] + except KeyError: + name = 'question' + wx, bbox = self._metrics_by_name[name] l,b,w,h = bbox if l<left: left = l # find the width with kerning @@ -377,6 +388,13 @@ wx, name, bbox = self._metrics[c] return wx + def get_width_from_char_name(self, name): + """ + Get the width of the character from a type1 character name + """ + wx, bbox = self._metrics_by_name[name] + return wx + def get_height_char(self, c, isord=False): """ Get the height of character c from the bounding box. This is @@ -392,9 +410,16 @@ c2 """ name1, name2 = self.get_name_char(c1), self.get_name_char(c2) + return self.get_kern_dist_from_name(name1, name2) + + def get_kern_dist_from_name(self, name1, name2): + """ + Return the kerning pair distance (possibly 0) for chars c1 and + c2 + """ try: return self._kern[ (name1, name2) ] except: return 0 - + def get_fontname(self): "Return the font name, eg, Times-Roman" return self._header['FontName'] Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-30 15:11:23 UTC (rev 3757) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-30 15:12:27 UTC (rev 3758) @@ -22,6 +22,7 @@ from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING from matplotlib.ttconv import convert_ttf_to_ps from matplotlib.mathtext import MathTextParser +from matplotlib._mathtext_data import uni2type1 from matplotlib.text import Text from matplotlib.transforms import get_vec6_scales @@ -700,8 +701,10 @@ elif ismath: return self.draw_mathtext(gc, x, y, s, prop, angle) + elif isinstance(s, unicode): + return self.draw_unicode(gc, x, y, s, prop, angle) + elif rcParams['ps.useafm']: - if ismath: s = s[1:-1] font = self._get_font_afm(prop) l,b,w,h = font.get_str_bbox(s) @@ -735,8 +738,6 @@ """ % locals() self._draw_ps(ps, gc, None) - elif isinstance(s, unicode): - return self.draw_unicode(gc, x, y, s, prop, angle) else: font = self._get_font_ttf(prop) font.set_text(s, 0, flags=LOAD_NO_HINTING) @@ -762,50 +763,92 @@ """draw a unicode string. ps doesn't have unicode support, so we have to do this the hard way """ + if rcParams['ps.useafm']: + self.set_color(*gc.get_rgb()) - font = self._get_font_ttf(prop) + font = self._get_font_afm(prop) + fontname = font.get_fontname() + fontsize = prop.get_size_in_points() + scale = 0.001*fontsize - self.set_color(*gc.get_rgb()) - self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points()) - self.track_characters(font, s) + thisx, thisy = 0, 0 + last_name = None + lines = [] + for c in s: + name = uni2type1.get(ord(c), 'question') + try: + width = font.get_width_from_char_name(name) + except KeyError: + name = 'question' + width = font.get_width_char('?') + if last_name is not None: + kern = font.get_kern_dist_from_name(last_name, name) + else: + kern = 0 + last_name = name + thisx += kern * scale + + lines.append('%f %f m /%s glyphshow'%(thisx, thisy, name)) - cmap = font.get_charmap() - lastgind = None - #print 'text', s - lines = [] - thisx, thisy = 0,0 - for c in s: - ccode = ord(c) - gind = cmap.get(ccode) - if gind is None: - ccode = ord('?') - name = '.notdef' - gind = 0 - else: - name = font.get_glyph_name(gind) - glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) + thisx += width * scale - if lastgind is not None: - kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT) - else: - kern = 0 - lastgind = gind - thisx += kern/64.0 - - lines.append('%f %f m /%s glyphshow'%(thisx, thisy, name)) - thisx += glyph.linearHoriAdvance/65536.0 - - - thetext = '\n'.join(lines) - ps = """gsave + thetext = "\n".join(lines) + ps = """\ +gsave +/%(fontname)s findfont +%(fontsize)s scalefont +setfont %(x)f %(y)f translate %(angle)f rotate %(thetext)s grestore -""" % locals() - self._pswriter.write(ps) + """ % locals() + self._pswriter.write(ps) + + else: + font = self._get_font_ttf(prop) + self.set_color(*gc.get_rgb()) + self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points()) + self.track_characters(font, s) + cmap = font.get_charmap() + lastgind = None + #print 'text', s + lines = [] + thisx, thisy = 0,0 + for c in s: + ccode = ord(c) + gind = cmap.get(ccode) + if gind is None: + ccode = ord('?') + name = '.notdef' + gind = 0 + else: + name = font.get_glyph_name(gind) + glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) + + if lastgind is not None: + kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT) + else: + kern = 0 + lastgind = gind + thisx += kern/64.0 + + lines.append('%f %f m /%s glyphshow'%(thisx, thisy, name)) + thisx += glyph.linearHoriAdvance/65536.0 + + + thetext = '\n'.join(lines) + ps = """gsave + %(x)f %(y)f translate + %(angle)f rotate + %(thetext)s + grestore + """ % locals() + self._pswriter.write(ps) + + def draw_mathtext(self, gc, x, y, s, prop, angle): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |