|
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.
|