|
From: <md...@us...> - 2007-07-18 15:48:56
|
Revision: 3558
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3558&view=rev
Author: mdboom
Date: 2007-07-18 08:27:58 -0700 (Wed, 18 Jul 2007)
Log Message:
-----------
Got SVG and PS (afm-only) support working. Still kind of tempermental.
Modified Paths:
--------------
branches/mathtext_mgd/lib/matplotlib/backends/backend_pdf.py
branches/mathtext_mgd/lib/matplotlib/backends/backend_ps.py
branches/mathtext_mgd/lib/matplotlib/backends/backend_svg.py
branches/mathtext_mgd/lib/matplotlib/mathtext.py
Modified: branches/mathtext_mgd/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/backends/backend_pdf.py 2007-07-18 13:16:35 UTC (rev 3557)
+++ branches/mathtext_mgd/lib/matplotlib/backends/backend_pdf.py 2007-07-18 15:27:58 UTC (rev 3558)
@@ -15,7 +15,7 @@
from cStringIO import StringIO
from datetime import datetime
from math import ceil, cos, floor, pi, sin
-import sets
+from sets import Set
from matplotlib import __version__, rcParams, agg, get_data_path
from matplotlib._pylab_helpers import Gcf
@@ -457,9 +457,8 @@
else:
realpath, stat_key = get_realpath_and_stat(filename)
chars = self.used_characters.get(stat_key)
- if chars is not None:
- fontdictObject = self.embedTTF(
- *self.used_characters[stat_key])
+ if chars is not None and len(chars[1]):
+ fontdictObject = self.embedTTF(realpath, chars[1])
fonts[Fx] = fontdictObject
#print >>sys.stderr, filename
self.writeObject(self.fontObject, fonts)
@@ -932,14 +931,13 @@
fname = font.fname
realpath, stat_key = get_realpath_and_stat(fname)
used_characters = self.used_characters.setdefault(
- stat_key, (realpath, sets.Set()))
+ stat_key, (realpath, Set()))
used_characters[1].update(s)
- print [(os.path.basename(x), y) for x, y in self.used_characters.values()]
def merge_used_characters(self, other):
for stat_key, (realpath, set) in other.items():
used_characters = self.used_characters.setdefault(
- stat_key, (realpath, sets.Set()))
+ stat_key, (realpath, Set()))
used_characters[1].update(set)
def draw_arc(self, gcEdge, rgbFace, x, y, width, height,
@@ -1103,8 +1101,6 @@
prev_font = None, None
oldx, oldy = 0, 0
for ox, oy, fontname, fontsize, glyph in pswriter:
- #print ox, oy, glyph
- #fontname = fontname.lower()
a = angle / 180.0 * pi
newx = x + cos(a)*ox - sin(a)*oy
newy = y + sin(a)*ox + cos(a)*oy
Modified: branches/mathtext_mgd/lib/matplotlib/backends/backend_ps.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/backends/backend_ps.py 2007-07-18 13:16:35 UTC (rev 3557)
+++ branches/mathtext_mgd/lib/matplotlib/backends/backend_ps.py 2007-07-18 15:27:58 UTC (rev 3558)
@@ -30,7 +30,7 @@
fromstring, nonzero, ones, put, take, where, isnan
import binascii
import re
-import sets
+from sets import Set
if sys.platform.startswith('win'): cmd_split = '&'
else: cmd_split = ';'
@@ -151,13 +151,13 @@
each font."""
realpath, stat_key = get_realpath_and_stat(font.fname)
used_characters = self.used_characters.setdefault(
- stat_key, (realpath, sets.Set()))
+ stat_key, (realpath, Set()))
used_characters[1].update(s)
def merge_used_characters(self, other):
for stat_key, (realpath, set) in other.items():
used_characters = self.used_characters.setdefault(
- stat_key, (realpath, sets.Set()))
+ stat_key, (realpath, Set()))
used_characters[1].update(set)
def set_color(self, r, g, b, store=1):
@@ -1037,13 +1037,14 @@
print >>fh, l.strip()
if not rcParams['ps.useafm']:
for font_filename, chars in renderer.used_characters.values():
- font = FT2Font(font_filename)
- cmap = font.get_charmap()
- glyph_ids = []
- for c in chars:
- gind = cmap.get(ord(c)) or 0
- glyph_ids.append(gind)
- convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
+ if len(chars):
+ font = FT2Font(font_filename)
+ cmap = font.get_charmap()
+ glyph_ids = []
+ for c in chars:
+ gind = cmap.get(ord(c)) or 0
+ glyph_ids.append(gind)
+ convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
print >>fh, "end"
print >>fh, "%%EndProlog"
Modified: branches/mathtext_mgd/lib/matplotlib/backends/backend_svg.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/backends/backend_svg.py 2007-07-18 13:16:35 UTC (rev 3557)
+++ branches/mathtext_mgd/lib/matplotlib/backends/backend_svg.py 2007-07-18 15:27:58 UTC (rev 3558)
@@ -291,9 +291,12 @@
self._svgwriter.write (svg)
def _add_char_def(self, prop, char):
- newprop = prop.copy()
- newprop.set_size(self.FONT_SCALE)
- font = self._get_font(newprop)
+ if isinstance(prop, FontProperties):
+ newprop = prop.copy()
+ font = self._get_font(newprop)
+ else:
+ font = prop
+ font.set_size(self.FONT_SCALE, 72)
ps_name = font.get_sfnt()[(1,0,0,6)]
char_id = urllib.quote('%s-%d' % (ps_name, ord(char)))
if char_id in self._char_defs:
@@ -332,8 +335,8 @@
"""
Draw math text using matplotlib.mathtext
"""
- fontsize = prop.get_size_in_points()
- width, height, svg_elements = math_parse_s_ft2font_svg(s, 72, fontsize)
+ width, height, svg_elements, used_characters = \
+ math_parse_s_ft2font_svg(s, 72, prop)
svg_glyphs = svg_elements.svg_glyphs
svg_lines = svg_elements.svg_lines
color = rgb2hex(gc.get_rgb())
@@ -349,9 +352,8 @@
svg.append('translate(%f,%f)' % (x, y))
svg.append('">\n')
- for fontname, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs:
- prop = FontProperties(family=fontname, size=fontsize)
- charid = self._add_char_def(prop, thetext)
+ for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs:
+ charid = self._add_char_def(font, thetext)
svg.append('<use xlink:href="#%s" transform="translate(%s, %s) scale(%s)"/>\n' %
(charid, new_x, -new_y_mtc, fontsize / self.FONT_SCALE))
@@ -417,8 +419,8 @@
def get_text_width_height(self, s, prop, ismath):
if ismath:
- width, height, trash = math_parse_s_ft2font_svg(
- s, 72, prop.get_size_in_points())
+ width, height, trash, used_characters = \
+ math_parse_s_ft2font_svg(s, 72, prop)
return width, height
font = self._get_font(prop)
font.set_text(s, 0.0)
Modified: branches/mathtext_mgd/lib/matplotlib/mathtext.py
===================================================================
--- branches/mathtext_mgd/lib/matplotlib/mathtext.py 2007-07-18 13:16:35 UTC (rev 3557)
+++ branches/mathtext_mgd/lib/matplotlib/mathtext.py 2007-07-18 15:27:58 UTC (rev 3558)
@@ -229,7 +229,7 @@
The class must be able to take symbol keys and font file names and
return the character metrics as well as do the drawing
"""
-
+
def get_kern(self, facename, symleft, symright, fontsize, dpi):
"""
Get the kerning distance for font between symleft and symright.
@@ -269,7 +269,10 @@
def render(self, ox, oy, facename, sym, fontsize, dpi):
pass
-
+ def get_used_characters(self):
+ return {}
+
+
class DummyFonts(Fonts):
'dummy class for debugging parser'
def get_metrics(self, font, sym, fontsize, dpi):
@@ -566,7 +569,7 @@
'ex' : 'Cmex10'
}
- class FontCache:
+ class CachedFont:
def __init__(self, font):
self.font = font
self.charmap = font.get_charmap()
@@ -577,15 +580,9 @@
self.glyphd = {}
self.fonts = {}
self.used_characters = {}
-
- # MGDTODO: Separate this out into an SVG class
-# if useSVG:
-# self.svg_glyphs = [] # a list of "glyphs" we need to render this thing in SVG
-# else: pass
-# self.usingSVG = useSVG
def _get_font(self, font):
- """Looks up a FontCache with its charmap and inverse charmap.
+ """Looks up a CachedFont with its charmap and inverse charmap.
font may be a TeX font name (cal, rm, it etc.), a Computer Modern
font name (cmtt10, cmr10, etc.) or an FT2Font object."""
if isinstance(font, str):
@@ -596,14 +593,14 @@
else:
basename = font.postscript_name
- font_cache = self.fonts.get(basename)
- if font_cache is None:
+ cached_font = self.fonts.get(basename)
+ if cached_font is None:
if isinstance(font, str):
- font = FT2Font(os.path.join(self.basepath, basename.lower() + '.ttf'))
+ font = FT2Font(os.path.join(self.basepath, basename.lower() + ".ttf"))
basename = font.postscript_name
- font_cache = self.FontCache(font)
- self.fonts[basename] = font_cache
- return basename, font_cache
+ cached_font = self.CachedFont(font)
+ self.fonts[basename] = cached_font
+ return basename, cached_font
def get_fonts(self):
return [x.font for x in self.fonts.values()]
@@ -613,7 +610,7 @@
self._get_info(font, sym, fontsize, dpi)
return metrics
- def _get_offset(self, basename, font_cache, glyph, fontsize, dpi):
+ def _get_offset(self, basename, cached_font, glyph, fontsize, dpi):
if basename.lower() == 'cmex10':
return glyph.height/64.0/2 + 256.0/64.0*dpi/72.0
return 0.
@@ -632,18 +629,18 @@
if font in self.fontmap and latex_to_bakoma.has_key(sym):
basename, num = latex_to_bakoma[sym]
- basename, font_cache = self._get_font(basename.capitalize())
- symbol_name = font_cache.font.get_glyph_name(num)
- num = font_cache.glyphmap[num]
+ basename, cached_font = self._get_font(basename.capitalize())
+ symbol_name = cached_font.font.get_glyph_name(num)
+ num = cached_font.glyphmap[num]
elif len(sym) == 1:
- basename, font_cache = self._get_font(font)
+ basename, cached_font = self._get_font(font)
num = ord(sym)
- symbol_name = font_cache.font.get_glyph_name(font_cache.charmap[num])
+ symbol_name = cached_font.font.get_glyph_name(cached_font.charmap[num])
else:
num = 0
raise ValueError('unrecognized symbol "%s"' % sym)
- font = font_cache.font
+ font = cached_font.font
font.set_size(fontsize, dpi)
glyph = font.load_char(num)
@@ -653,7 +650,7 @@
used_characters[1].update(unichr(num))
xmin, ymin, xmax, ymax = [val/64.0 for val in glyph.bbox]
- offset = self._get_offset(basename, font_cache, glyph, fontsize, dpi)
+ offset = self._get_offset(basename, cached_font, glyph, fontsize, dpi)
metrics = Bunch(
advance = glyph.linearHoriAdvance/65536.0,
height = glyph.height/64.0,
@@ -671,8 +668,8 @@
'Dimension the drawing canvas; may be a noop'
self.width = int(w)
self.height = int(h)
- for font_cache in self.fonts.values():
- font_cache.font.set_bitmap_size(int(w), int(h))
+ for cached_font in self.fonts.values():
+ cached_font.font.set_bitmap_size(int(w), int(h))
def render(self, ox, oy, font, sym, fontsize, dpi):
basename, font, metrics, symbol_name, num, glyph, offset = \
@@ -680,22 +677,7 @@
font.draw_glyph_to_bitmap(
int(ox), int(self.height - oy - metrics.ymax), glyph)
-# else:
-# oy += offset - 512/2048.*10.
-# basename = self.fontmap[font]
-# if latex_to_bakoma.has_key(sym):
-# basename, num = latex_to_bakoma[sym]
-# num = self.glyphmaps[basename][num]
-# elif len(sym) == 1:
-# num = ord(sym)
-# else:
-# num = 0
-# print >>sys.stderr, 'unrecognized symbol "%s"' % sym
-# thetext = unichr(num)
-# thetext.encode('utf-8')
-# self.svg_glyphs.append((basename, fontsize, thetext, ox, oy, metrics))
-
def _old_get_kern(self, font, symleft, symright, fontsize, dpi):
"""
Get the kerning distance for font between symleft and symright.
@@ -715,14 +697,16 @@
#print basename, symleft, symright, key, kern
return kern
-
+ def get_used_characters(self):
+ return self.used_characters
+
class BakomaPSFonts(BakomaFonts):
"""
Use the Bakoma postscript fonts for rendering to backend_ps
"""
- def _get_offset(self, basename, font_cache, glyph, fontsize, dpi):
- head = font_cache.font.get_sfnt_table("head")
+ def _get_offset(self, basename, cached_font, glyph, fontsize, dpi):
+ head = cached_font.font.get_sfnt_table("head")
if basename.lower() == 'cmex10':
return -(head['yMin']+512)/head['unitsPerEm']*10.
return 0.
@@ -759,7 +743,21 @@
self.pswriter.append((ox, oy, filename, fontsize, num))
+class BakomaSVGFonts(BakomaFonts):
+ """Hack of BakomaFonts for SVG support."""
+ def __init__(self):
+ BakomaFonts.__init__(self)
+ self.svg_glyphs = []
+
+ def render(self, ox, oy, font, sym, fontsize, dpi):
+ basename, font, metrics, symbol_name, num, glyph, offset = \
+ self._get_info(font, sym, fontsize, dpi)
+ oy += offset - 512/2048.*10.
+ thetext = unichr(num)
+ thetext.encode('utf-8')
+ self.svg_glyphs.append((font, fontsize, thetext, ox, oy, metrics))
+
class StandardPSFonts(Fonts):
"""
Use the standard postscript fonts for rendering to backend_ps
@@ -768,21 +766,51 @@
# allocate a new set of fonts
basepath = os.path.join( get_data_path(), 'fonts', 'afm' )
- fontmap = { 'cal' : 'pzcmi8a',
- 'rm' : 'pncr8a',
- 'tt' : 'pcrr8a',
- 'it' : 'pncri8a',
+ fontmap = { 'cal' : 'pzcmi8a', # Zapf Chancery
+ 'rm' : 'pncr8a', # New Century Schoolbook
+ 'tt' : 'pcrr8a', # Courier
+ 'it' : 'pncri8a', # New Century Schoolbook Italic
+ 'sf' : 'phvr8a', # Helvetica
+ 'bf' : 'pncb8a', # New Century Schoolbook Bold
+ None : 'psyr' # Symbol
}
def __init__(self):
self.glyphd = {}
- self.fonts = dict(
- [ (name, AFM(file(os.path.join(self.basepath, name) + '.afm')))
- for name in self.fnames])
+ self.fonts = {}
+ def _get_font(self, font):
+ if isinstance(font, str):
+ if font not in self.fontmap.values():
+ basename = self.fontmap[font]
+ else:
+ basename = font
+ else:
+ basename = font.get_fontname()
+
+ cached_font = self.fonts.get(basename)
+ if cached_font is None:
+ if isinstance(font, str):
+ fname = os.path.join(self.basepath, basename + ".afm")
+ cached_font = AFM(file(fname, 'r'))
+ cached_font.fname = fname
+ basename = cached_font.get_fontname()
+ else:
+ cached_font = font
+ self.fonts[basename] = cached_font
+ return basename, cached_font
+
+ def get_fonts(self):
+ return [x.font for x in self.fonts.values()]
+
def _get_info (self, font, sym, fontsize, dpi):
'load the cmfont, metrics and glyph with caching'
- key = font, sym, fontsize, dpi
+ if hasattr(font, 'get_fontname'):
+ fontname = font.get_fontname()
+ else:
+ fontname = font
+
+ key = fontname, sym, fontsize, dpi
tup = self.glyphd.get(key)
if tup is not None:
@@ -790,41 +818,40 @@
if sym in "0123456789()" and font == 'it':
font = 'rm'
- basename = self.fontmap[font]
if latex_to_standard.has_key(sym):
- basename, num = latex_to_standard[sym]
- char = chr(num)
+ font, num = latex_to_standard[sym]
+ glyph = chr(num)
elif len(sym) == 1:
- char = sym
+ glyph = sym
+ num = ord(glyph)
else:
raise ValueError('unrecognized symbol "%s"' % (sym))
-
+ basename, font = self._get_font(font)
+
try:
- sym = self.fonts[basename].get_name_char(char)
+ symbol_name = font.get_name_char(glyph)
except KeyError:
raise ValueError('unrecognized symbol "%s"' % (sym))
offset = 0
- cmfont = self.fonts[basename]
- fontname = cmfont.get_fontname()
scale = 0.001 * fontsize
xmin, ymin, xmax, ymax = [val * scale
- for val in cmfont.get_bbox_char(char)]
+ for val in font.get_bbox_char(glyph)]
metrics = Bunch(
advance = (xmax-xmin),
- width = cmfont.get_width_char(char) * scale,
- height = cmfont.get_width_char(char) * scale,
+ width = font.get_width_char(glyph) * scale,
+ height = font.get_width_char(glyph) * scale,
xmin = xmin,
xmax = xmax,
ymin = ymin+offset,
ymax = ymax+offset
)
- self.glyphd[key] = fontname, basename, metrics, sym, offset, char
- return fontname, basename, metrics, '/'+sym, offset, char
+ self.glyphd[key] = basename, font, metrics, symbol_name, num, glyph, offset
+ return self.glyphd[key]
def set_canvas_size(self, w, h, pswriter):
'Dimension the drawing canvas; may be a noop'
@@ -832,32 +859,33 @@
self.height = h
self.pswriter = pswriter
-
def render(self, ox, oy, font, sym, fontsize, dpi):
- fontname, basename, metrics, glyphname, offset, char = \
+ basename, font, metrics, symbol_name, num, glyph, offset = \
self._get_info(font, sym, fontsize, dpi)
- ps = """/%(fontname)s findfont
+ ps = """/%(basename)s findfont
%(fontsize)s scalefont
setfont
%(ox)f %(oy)f moveto
-/%(glyphname)s glyphshow
+/%(symbol_name)s glyphshow
""" % locals()
self.pswriter.write(ps)
def get_metrics(self, font, sym, fontsize, dpi):
- fontname, basename, metrics, sym, offset, char = \
+ basename, font, metrics, symbol_name, num, glyph, offset = \
self._get_info(font, sym, fontsize, dpi)
return metrics
def get_kern(self, font, symleft, symright, fontsize, dpi):
- fontname, basename, metrics, sym, offset, char1 = \
+ basename, font1, metrics, symbol_name, num, glyph1, offset = \
self._get_info(font, symleft, fontsize, dpi)
- fontname, basename, metrics, sym, offset, char2 = \
+ basename, font2, metrics, symbol_name, num, glyph2, offset = \
self._get_info(font, symright, fontsize, dpi)
- cmfont = self.fonts[basename]
- return cmfont.get_kern_dist(char1, char2) * 0.001 * fontsize
-
+ if font1.get_fontname() == font2.get_fontname():
+ basename, font = self._get_font(font)
+ return font.get_kern_dist(glyph1, glyph2) * 0.001 * fontsize
+ return 0
+
class Element:
fontsize = 12
dpi = 72
@@ -1667,34 +1695,37 @@
w, h, fontlike, used_characters = self.cache[cacheKey]
return w, h, fontlike, used_characters
+ use_afm = False
if self.output == 'SVG':
- self.font_object = BakomaFonts(useSVG=True)
+ self.font_object = BakomaSVGFonts()
#self.font_object = MyUnicodeFonts(output='SVG')
- Element.fonts = self.font_object
elif self.output == 'Agg':
self.font_object = BakomaFonts()
#self.font_object = MyUnicodeFonts()
- Element.fonts = self.font_object
elif self.output == 'PS':
if rcParams['ps.useafm']:
self.font_object = StandardPSFonts()
- Element.fonts = self.font_object
+ use_afm = True
else:
self.font_object = BakomaPSFonts()
#self.font_object = MyUnicodeFonts(output='PS')
- Element.fonts = self.font_object
elif self.output == 'PDF':
self.font_object = BakomaPDFFonts()
- Element.fonts = self.font_object
-
+ Element.fonts = self.font_object
+
fontsize = prop.get_size_in_points()
handler.clear()
expression.parseString( s )
+
+ if use_afm:
+ fname = fontManager.findfont(prop, fontext='afm')
+ default_font = AFM(file(fname, 'r'))
+ default_font.fname = fname
+ else:
+ fname = fontManager.findfont(prop)
+ default_font = FT2Font(fname)
- fname = fontManager.findfont(prop)
- default_font = FT2Font(str(fname))
-
handler.expr.determine_font([default_font])
handler.expr.set_size_info(fontsize, dpi)
@@ -1729,11 +1760,14 @@
# The empty list at the end is for lines
svg_elements = Bunch(svg_glyphs=self.font_object.svg_glyphs,
svg_lines=[])
- self.cache[cacheKey] = w, h, svg_elements, Element.fonts.used_characters
+ self.cache[cacheKey] = \
+ w, h, svg_elements, Element.fonts.get_used_characters()
elif self.output == 'Agg':
- self.cache[cacheKey] = w, h, self.font_object.get_fonts(), Element.fonts.used_characters
+ self.cache[cacheKey] = \
+ w, h, self.font_object.get_fonts(), Element.fonts.get_used_characters()
elif self.output in ('PS', 'PDF'):
- self.cache[cacheKey] = w, h, pswriter, Element.fonts.used_characters
+ self.cache[cacheKey] = \
+ w, h, pswriter, Element.fonts.get_used_characters()
return self.cache[cacheKey]
if rcParams["mathtext.mathtext2"]:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|