Revision: 7764
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7764&view=rev
Author:   leejjoon
Date:     2009-09-15 19:28:09 +0000 (Tue, 15 Sep 2009)

Log Message:
-----------
implement draw_text and draw_tex method of backend_base using the textpath.

Modified Paths:
--------------
    trunk/matplotlib/CHANGELOG
    trunk/matplotlib/lib/matplotlib/backend_bases.py
    trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
    trunk/matplotlib/lib/matplotlib/texmanager.py
    trunk/matplotlib/lib/matplotlib/text.py
    trunk/matplotlib/lib/matplotlib/textpath.py

Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG  2009-09-15 12:37:55 UTC (rev 7763)
+++ trunk/matplotlib/CHANGELOG  2009-09-15 19:28:09 UTC (rev 7764)
@@ -1,3 +1,7 @@
+2009-09-15 Implement draw_text and draw_tex method of backend_base using
+           the textpath module. Implement draw_tex method of the svg 
+           backend. - JJL
+
 2009-09-15 Don't fail on AFM files containing floating-point bounding boxes - 
JKS
 
 2009-09-13 AxesGrid : add modified version of colorbar. Add colorbar 

Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py    2009-09-15 12:37:55 UTC 
(rev 7763)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py    2009-09-15 19:28:09 UTC 
(rev 7764)
@@ -30,13 +30,15 @@
 import matplotlib.colors as colors
 import matplotlib.transforms as transforms
 import matplotlib.widgets as widgets
-import matplotlib.path as path
+#import matplotlib.path as path
 from matplotlib import rcParams
 
 from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
 import cStringIO
 
 import matplotlib.tight_bbox as tight_bbox
+import matplotlib.textpath as textpath
+from matplotlib.path import Path
 
 class RendererBase:
     """An abstract base class to handle drawing/rendering operations.
@@ -58,6 +60,8 @@
     def __init__(self):
         self._texmanager = None
 
+        self._text2path = textpath.TextToPath()
+
     def open_group(self, s, gid=None):
         """
         Open a grouping element with label *s*. If *gid* is given, use
@@ -337,7 +341,9 @@
         return False
 
     def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'):
-        raise NotImplementedError
+        """
+        """
+        self._draw_text_as_path(gc, x, y, s, prop, angle, ismath="TeX")
 
     def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
         """
@@ -372,8 +378,85 @@
         to if 1, and then the actual bounding box will be blotted along with
         your text.
         """
-        raise NotImplementedError
 
+        self._draw_text_as_path(gc, x, y, s, prop, angle, ismath)
+
+    def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
+        """
+        draw the text by converting them to paths using textpath module.
+
+        *prop*
+          font property
+
+        *s*
+          text to be converted
+          
+        *usetex*
+          If True, use matplotlib usetex mode.
+
+        *ismath*
+          If True, use mathtext parser. If "TeX", use *usetex* mode.
+        """
+        
+        text2path = self._text2path
+        color = gc.get_rgb()[:3]
+        fontsize = self.points_to_pixels(prop.get_size_in_points())
+        
+        if ismath == "TeX":
+            verts, codes = text2path.get_text_path(prop, s, ismath=False, 
usetex=True)
+        else:
+            verts, codes = text2path.get_text_path(prop, s, ismath=ismath, 
usetex=False)
+
+        path = Path(verts, codes)
+        angle = angle/180.*3.141592
+        if self.flipy():
+            transform = Affine2D().scale(fontsize/text2path.FONT_SCALE,
+                                         fontsize/text2path.FONT_SCALE).\
+                                         rotate(angle).translate(x, 
self.height-y)
+        else:
+            transform = Affine2D().scale(fontsize/text2path.FONT_SCALE,
+                                         fontsize/text2path.FONT_SCALE).\
+                                         rotate(angle).translate(x, y)
+
+        gc.set_linewidth(0.0)
+        self.draw_path(gc, path, transform, rgbFace=color)
+
+
+    def get_text_width_height_descent(self, s, prop, ismath):
+        """
+        get the width and height, and the offset from the bottom to the
+        baseline (descent), in display coords of the string s with
+        :class:`~matplotlib.font_manager.FontProperties` prop
+        """
+        if ismath=='TeX':
+            # todo: handle props
+            size = prop.get_size_in_points()
+            texmanager = self._text2path.get_texmanager()
+            fontsize = prop.get_size_in_points()
+            w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
+                                                               renderer=self)
+            return w, h, d
+
+        dpi = self.points_to_pixels(72)
+        fontscale = self._text2path.FONT_SCALE
+        if ismath:
+            width, height, descent, glyphs, rects = \
+                   self._text2path.mathtext_parser.parse(s, dpi, prop)
+            return width, height, descent
+
+        flags = self._text2path._get_hinting_flag()
+        font = self._text2path._get_font(prop)
+        size = prop.get_size_in_points()
+        font.set_size(size, dpi)
+        font.set_text(s, 0.0, flags=flags)  # the width and height of 
unrotated string
+        w, h = font.get_width_height()
+        d = font.get_descent()
+        w /= 64.0  # convert from subpixels
+        h /= 64.0
+        d /= 64.0
+        return w, h, d
+
+
     def flipy(self):
         """
         Return true if y small numbers are top for renderer Is used
@@ -395,13 +478,6 @@
             self._texmanager = TexManager()
         return self._texmanager
 
-    def get_text_width_height_descent(self, s, prop, ismath):
-        """
-        get the width and height, and the offset from the bottom to the
-        baseline (descent), in display coords of the string s with
-        :class:`~matplotlib.font_manager.FontProperties` prop
-        """
-        raise NotImplementedError
 
     def new_gc(self):
         """
@@ -741,7 +817,7 @@
         """
         if self._hatch is None:
             return None
-        return path.Path.hatch(self._hatch, density)
+        return Path.hatch(self._hatch, density)
 
 class Event:
     """

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2009-09-15 
12:37:55 UTC (rev 7763)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2009-09-15 
19:28:09 UTC (rev 7764)
@@ -58,6 +58,10 @@
         self._hatchd = {}
         self._n_gradients = 0
         self.mathtext_parser = MathTextParser('SVG')
+
+        RendererBase.__init__(self)
+        self._glyph_map = dict()
+        
         svgwriter.write(svgProlog%(width,height,width,height))
 
     def _draw_svg_element(self, element, details, gc, rgbFace):
@@ -405,7 +409,147 @@
         if url is not None:
             self._svgwriter.write('</a>')
 
+    def _adjust_char_id(self, char_id):
+        return char_id.replace("%20","_")
+    
+    def draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
+        """
+        draw the text by converting them to paths using textpath module.
+
+        *prop*
+          font property
+
+        *s*
+          text to be converted
+          
+        *usetex*
+          If True, use matplotlib usetex mode.
+
+        *ismath*
+          If True, use mathtext parser. If "TeX", use *usetex* mode.
+
+          
+        """
+        # this method works for normal text, mathtext and usetex mode.
+        # But currently only utilized by draw_tex method.
+        
+        glyph_map=self._glyph_map
+        
+        text2path = self._text2path
+        color = rgb2hex(gc.get_rgb()[:3])
+        fontsize = prop.get_size_in_points()
+
+        write = self._svgwriter.write
+        
+        if ismath == False:
+            font = text2path._get_font(prop)
+            _glyphs = text2path.get_glyphs_with_font(font, s, 
glyph_map=glyph_map,
+                                                     
return_new_glyphs_only=True)
+            glyph_info, glyph_map_new, rects = _glyphs
+
+            _flip = Affine2D().scale(1.0, -1.0)
+
+            if glyph_map_new:
+                write('<defs>\n')
+                for char_id, glyph_path in glyph_map_new.iteritems():
+                    path = Path(*glyph_path)
+                    path_data = self._convert_path(path, _flip)
+                    path_element = '<path id="%s" d="%s"/>\n' % (char_id, 
''.join(path_data))
+                    write(path_element)
+                write('</defs>\n')
+
+                glyph_map.update(glyph_map_new)
+                
+            svg = []
+            clipid = self._get_gc_clip_svg(gc)
+            if clipid is not None:
+                svg.append('<g clip-path="url(#%s)">\n' % clipid)
+
+            svg.append('<g style="fill: %s; opacity: %f" transform="' % 
(color, gc.get_alpha()))
+            if angle != 0:
+                svg.append('translate(%f,%f)rotate(%1.1f)' % (x,y,-angle))
+            elif x != 0 or y != 0:
+                svg.append('translate(%f,%f)' % (x, y))
+            svg.append('scale(%f)">\n' % (fontsize / text2path.FONT_SCALE))
+
+            for glyph_id, xposition, yposition, scale in glyph_info:
+                svg.append('<use xlink:href="#%s"' % glyph_id)
+                svg.append(' x="%f" y="%f"' % (xposition, yposition))
+                #(currx * (self.FONT_SCALE / fontsize)))
+                svg.append('/>\n')
+
+            svg.append('</g>\n')
+            if clipid is not None:
+                svg.append('</g>\n')
+            svg = ''.join(svg)
+
+
+
+        else:
+            if ismath == "TeX":
+                _glyphs = text2path.get_glyphs_tex(prop, s, 
glyph_map=glyph_map)
+            else:
+                _glyphs = text2path.get_glyphs_mathtext(prop, s, 
glyph_map=glyph_map)
+
+            glyph_info, glyph_map_new, rects = _glyphs
+
+            # we store the character glyphs w/o flipping. Instead, the
+            # coordinate will be flipped when this characters are
+            # used.
+            if glyph_map_new:
+                write('<defs>\n')
+                for char_id, glyph_path in glyph_map_new.iteritems():
+                    char_id = self._adjust_char_id(char_id)
+                    path = Path(*glyph_path)
+                    path_data = self._convert_path(path, None) #_flip)
+                    path_element = '<path id="%s" d="%s"/>\n' % (char_id, 
''.join(path_data))
+                    write(path_element)
+                write('</defs>\n')
+
+                glyph_map.update(glyph_map_new)
+                
+            svg = []
+            clipid = self._get_gc_clip_svg(gc)
+            if clipid is not None:
+                svg.append('<g clip-path="url(#%s)">\n' % clipid)
+
+            svg.append('<g style="fill: %s; opacity: %f" transform="' % 
(color, gc.get_alpha()))
+            if angle != 0:
+                svg.append('translate(%f,%f)rotate(%1.1f)' % (x,y,-angle))
+            elif x != 0 or y != 0:
+                svg.append('translate(%f,%f)' % (x, y))
+            svg.append('scale(%f,-%f)">\n' % (fontsize / text2path.FONT_SCALE,
+                                              fontsize / text2path.FONT_SCALE))
+
+            for char_id, xposition, yposition, scale in glyph_info:
+                char_id = self._adjust_char_id(char_id)
+                svg.append('<use xlink:href="#%s"' % char_id)
+                svg.append(' x="%f" y="%f" transform="scale(%f)"' % 
(xposition/scale,
+                                                                      
yposition/scale,
+                                                                      scale))
+                svg.append('/>\n')
+
+
+            for verts, codes in rects:
+                path = Path(verts, codes)
+                path_data = self._convert_path(path, None)
+                path_element = '<path d="%s"/>\n' % (''.join(path_data))
+                svg.append(path_element)
+
+
+            svg.append('</g><!-- style -->\n')
+            if clipid is not None:
+                svg.append('</g><!-- clipid -->\n')
+            svg = ''.join(svg)
+
+        write(svg)
+
+
+    def draw_tex(self, gc, x, y, s, prop, angle):
+        self.draw_text_as_path(gc, x, y, s, prop, angle, ismath="TeX")
+
     def draw_text(self, gc, x, y, s, prop, angle, ismath):
+
         if ismath:
             self._draw_mathtext(gc, x, y, s, prop, angle)
             return
@@ -648,6 +792,14 @@
         return self.width, self.height
 
     def get_text_width_height_descent(self, s, prop, ismath):
+        if ismath == "TeX":
+            size = prop.get_size_in_points()
+            texmanager = self._text2path.get_texmanager()
+            fontsize = prop.get_size_in_points()
+            w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
+                                                               renderer=self)
+            return w, h, d
+            
         if ismath:
             width, height, descent, trash, used_characters = \
                 self.mathtext_parser.parse(s, 72, prop)

Modified: trunk/matplotlib/lib/matplotlib/texmanager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/texmanager.py       2009-09-15 12:37:55 UTC 
(rev 7763)
+++ trunk/matplotlib/lib/matplotlib/texmanager.py       2009-09-15 19:28:09 UTC 
(rev 7764)
@@ -304,7 +304,7 @@
 %s
 %s
 \usepackage[active,showbox,tightpage]{preview}
-%%\usepackage[papersize={72in,72in}, body={70in,70in}, 
margin={1in,1in}]{geometry}
+\usepackage[papersize={72in,72in}, body={70in,70in}, 
margin={1in,1in}]{geometry}
 
 %% we override the default showbox as it is treated as an error and makes
 %% the exit status not zero

Modified: trunk/matplotlib/lib/matplotlib/text.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/text.py     2009-09-15 12:37:55 UTC (rev 
7763)
+++ trunk/matplotlib/lib/matplotlib/text.py     2009-09-15 19:28:09 UTC (rev 
7764)
@@ -560,6 +560,7 @@
 
                 renderer.draw_tex(gc, x, y, clean_line,
                                   self._fontproperties, angle)
+            renderer.close_group('text')
             return
 
         for line, wh, x, y in info:

Modified: trunk/matplotlib/lib/matplotlib/textpath.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/textpath.py 2009-09-15 12:37:55 UTC (rev 
7763)
+++ trunk/matplotlib/lib/matplotlib/textpath.py 2009-09-15 19:28:09 UTC (rev 
7764)
@@ -42,6 +42,8 @@
 
         return font
 
+    def _get_hinting_flag(self):
+        return LOAD_NO_HINTING
     
     def _get_char_id(self, font, ccode):
         """
@@ -134,7 +136,8 @@
         return verts, codes
 
             
-    def get_glyphs_with_font(self, font, s, glyph_map=None):
+    def get_glyphs_with_font(self, font, s, glyph_map=None,
+                             return_new_glyphs_only=False):
         """
         convert the string *s* to vertices and codes using the
         provided ttf font. 
@@ -152,6 +155,11 @@
         if glyph_map is None:
             glyph_map = dict()
 
+        if return_new_glyphs_only:
+            glyph_map_new = dict()
+        else:
+            glyph_map_new = glyph_map
+
         # I'm not sure if I get kernings right. Needs to be verified. -JJL
 
         for c in s:
@@ -174,7 +182,7 @@
 
             char_id = self._get_char_id(font, ccode)
             if not char_id in glyph_map:
-                glyph_map[char_id] = self.glyph_to_path(glyph)
+                glyph_map_new[char_id] = self.glyph_to_path(glyph)
 
             currx += (kern / 64.0)
 
@@ -190,12 +198,13 @@
 
         rects = []
         
-        return zip(glyph_ids, xpositions, ypositions, sizes), glyph_map, rects
+        return zip(glyph_ids, xpositions, ypositions, sizes), glyph_map_new, 
rects
 
 
 
 
-    def get_glyphs_mathtext(self, prop, s):
+    def get_glyphs_mathtext(self, prop, s, glyph_map=None,
+                            return_new_glyphs_only=False):
         """
         convert the string *s* to vertices and codes by parsing it with 
mathtext.
         """
@@ -207,8 +216,14 @@
             s, self.DPI, prop)
 
 
-        glyph_map = dict()
-        
+        if glyph_map is None:
+            glyph_map = dict()
+
+        if return_new_glyphs_only:
+            glyph_map_new = dict()
+        else:
+            glyph_map_new = glyph_map
+
         xpositions = []
         ypositions = []
         glyph_ids = []
@@ -223,7 +238,7 @@
                 font.clear()
                 font.set_size(self.FONT_SCALE, self.DPI)
                 glyph = font.load_char(ccode, flags=LOAD_NO_HINTING)
-                glyph_map[char_id] = self.glyph_to_path(glyph)
+                glyph_map_new[char_id] = self.glyph_to_path(glyph)
 
             xpositions.append(ox)
             ypositions.append(oy)
@@ -253,7 +268,8 @@
         return self._texmanager
 
 
-    def get_glyphs_tex(self, prop, s):
+    def get_glyphs_tex(self, prop, s, glyph_map=None,
+                       return_new_glyphs_only=False):
         """
         convert the string *s* to vertices and codes using matplotlib's usetex 
mode.
         """
@@ -275,8 +291,17 @@
         page = iter(dvi).next()
         dvi.close()
 
+
+        if glyph_map is None:
+            glyph_map = dict()
+
+        if return_new_glyphs_only:
+            glyph_map_new = dict()
+        else:
+            glyph_map_new = glyph_map
+
+
         glyph_ids, xpositions, ypositions, sizes = [], [], [], []
-        glyph_map = dict()
 
         # Gather font information and do some setup for combining
         # characters into strings.
@@ -316,7 +341,7 @@
                 else: 
                     glyph0 = font.load_glyph(ng, flags=ft2font_flag)
                     
-                glyph_map[char_id] = self.glyph_to_path(glyph0)
+                glyph_map_new[char_id] = self.glyph_to_path(glyph0)
 
             glyph_ids.append(char_id)
             xpositions.append(x1)


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Come build with us! The BlackBerry&reg; Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9&#45;12, 2009. Register now&#33;
http://p.sf.net/sfu/devconf
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to