Пример #1
0
class RendererAgg(RendererBase):
    """
    The renderer handles all the drawing primitives using a graphics
    context instance that controls the colors/styles
    """

    debug = 1
    texd = {}  # a cache of tex image rasters

    def __init__(self, width, height, dpi):
        if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying')
        self.dpi = dpi
        self.width = width
        self.height = height
        self._renderer = _RendererAgg(int(width),
                                      int(height),
                                      dpi.get(),
                                      debug=False)
        self.draw_polygon = self._renderer.draw_polygon
        self.draw_rectangle = self._renderer.draw_rectangle
        self.draw_path = self._renderer.draw_path
        self.draw_lines = self._renderer.draw_lines
        self.draw_markers = self._renderer.draw_markers
        self.draw_image = self._renderer.draw_image
        self.draw_line_collection = self._renderer.draw_line_collection
        self.draw_quad_mesh = self._renderer.draw_quad_mesh
        self.draw_poly_collection = self._renderer.draw_poly_collection
        self.draw_regpoly_collection = self._renderer.draw_regpoly_collection

        self.copy_from_bbox = self._renderer.copy_from_bbox
        self.restore_region = self._renderer.restore_region

        self.texmanager = TexManager()

        self.bbox = lbwh_to_bbox(0, 0, self.width, self.height)

    def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2):
        """
        Draw an arc centered at x,y with width and height and angles
        from 0.0 to 360.0

        If rgbFace is not None, fill the rectangle with that color.  gcEdge
        is a GraphicsContext instance

        Currently, I'm only supporting ellipses, ie angle args are
        ignored
        """
        if __debug__: verbose.report('RendererAgg.draw_arc', 'debug-annoying')
        self._renderer.draw_ellipse(gcEdge, rgbFace, x, y, width / 2,
                                    height / 2)  # ellipse takes radius

    def _draw_image(self, x, y, im):
        """
        Draw the Image instance into the current axes; x, y is the
        upper left hand corner of the image
        """
        if __debug__:
            verbose.report('RendererAgg.draw_image', 'debug-annoying')
        #self._renderer.draw_image(int(x), int(self.height-y), im)
        self._renderer.draw_image(int(x), int(y), im)

    def draw_line(self, gc, x1, y1, x2, y2):
        """
        x and y are equal length arrays, draw lines connecting each
        point in x, y
        """
        if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying')
        x = array([x1, x2], typecode=Float)
        y = array([y1, y2], typecode=Float)
        self._renderer.draw_lines(gc, x, y)

    def draw_point(self, gc, x, y):
        """
        Draw a single point at x,y
        """
        if __debug__:
            verbose.report('RendererAgg.draw_point', 'debug-annoying')
        rgbFace = gc.get_rgb()
        self._renderer.draw_ellipse(gc, rgbFace, x, y, 0.5, 0.5)

    def draw_mathtext(self, gc, x, y, s, prop, angle):
        """
        Draw the math text using matplotlib.mathtext
        """
        if __debug__:
            verbose.report('RendererAgg.draw_mathtext', 'debug-annoying')
        size = prop.get_size_in_points()
        width, height, fonts = math_parse_s_ft2font(s, self.dpi.get(), size,
                                                    angle)

        if angle == 90:
            width, height = height, width
        for font in fonts:
            if angle == 90:
                font.horiz_image_to_vert_image()  # <-- Rotate
                self._renderer.draw_text(font,
                                         int(x) - width,
                                         int(y) - height, gc)
            else:
                self._renderer.draw_text(font, int(x), int(y) - height, gc)
        if 0:
            self._renderer.draw_rectangle(gc, None, int(x),
                                          self.height - int(y), width, height)

    def draw_text(self, gc, x, y, s, prop, angle, ismath):
        """
        Render the text
        """
        if __debug__: verbose.report('RendererAgg.draw_text', 'debug-annoying')

        if ismath:
            return self.draw_mathtext(gc, x, y, s, prop, angle)

        font = self._get_agg_font(prop)
        if font is None: return None
        if len(s) == 1 and ord(s) > 127:

            font.load_char(ord(s))
        else:
            font.set_text(s, angle)
        font.draw_glyphs_to_bitmap()

        #print x, y, int(x), int(y)

        self._renderer.draw_text(font, int(x), int(y), gc)

    def get_text_width_height(self, s, prop, ismath, rgb=(0, 0, 0)):
        """
        get the width and height in display coords of the string s
        with FontPropertry prop

        # passing rgb is a little hack to make cacheing in the
        # texmanager more efficient.  It is not meant to be used
        # outside the backend
        """

        if ismath == 'TeX':
            # todo: handle props
            size = prop.get_size_in_points()
            Z = self.texmanager.get_rgba(s, size, rgb)
            m, n, tmp = Z.shape
            return n, m

        if ismath:
            width, height, fonts = math_parse_s_ft2font(
                s, self.dpi.get(), prop.get_size_in_points())
            return width, height
        font = self._get_agg_font(prop)
        font.set_text(s, 0.0)  # the width and height of unrotated string
        w, h = font.get_width_height()
        w /= 64.0  # convert from subpixels
        h /= 64.0
        return w, h

    def draw_tex(self, gc, x, y, s, prop, angle):
        # todo, handle props, angle, origins
        rgb = gc.get_rgb()
        size = prop.get_size_in_points()

        flip = angle == 90
        w, h = self.get_text_width_height(s, prop, 'TeX', rgb)
        if flip:
            w, h = h, w
            x -= w

        key = s, size, rgb, angle, self.texmanager.get_font_config()
        im = self.texd.get(key)
        if im is None:
            Z = self.texmanager.get_rgba(s, size, rgb)
            if flip:
                r = Z[:, :, 0]
                g = Z[:, :, 1]
                b = Z[:, :, 2]
                a = Z[:, :, 3]
                m, n, tmp = Z.shape

                def func(x):
                    return transpose(fliplr(x))

                Z = zeros((n, m, 4), typecode=Float)
                Z[:, :, 0] = func(r)
                Z[:, :, 1] = func(g)
                Z[:, :, 2] = func(b)
                Z[:, :, 3] = func(a)
            im = fromarray(Z, 1)
            im.flipud_out()
            self.texd[key] = im

        cliprect = gc.get_clip_rectangle()
        if cliprect is None: bbox = None
        else: bbox = lbwh_to_bbox(*cliprect)
        self.draw_image(x, self.height - y, im, bbox)

    def get_canvas_width_height(self):
        'return the canvas width and height in display coords'
        return self.width, self.height

    def _get_agg_font(self, prop):
        """
        Get the font for text instance t, cacheing for efficiency
        """
        if __debug__:
            verbose.report('RendererAgg._get_agg_font', 'debug-annoying')

        key = hash(prop)
        font = _fontd.get(key)

        if font is None:
            fname = fontManager.findfont(prop)
            font = FT2Font(str(fname))
            _fontd[key] = font

        font.clear()
        size = prop.get_size_in_points()
        font.set_size(size, self.dpi.get())

        return font

    def points_to_pixels(self, points):
        """
        convert point measures to pixes using dpi and the pixels per
        inch of the display
        """
        if __debug__:
            verbose.report('RendererAgg.points_to_pixels', 'debug-annoying')
        return points * self.dpi.get() / 72.0

    def tostring_rgb(self):
        if __debug__:
            verbose.report('RendererAgg.tostring_rgb', 'debug-annoying')
        return self._renderer.tostring_rgb()

    def tostring_argb(self):
        if __debug__:
            verbose.report('RendererAgg.tostring_argb', 'debug-annoying')
        return self._renderer.tostring_argb()

    def buffer_rgba(self, x, y):
        if __debug__:
            verbose.report('RendererAgg.buffer_rgba', 'debug-annoying')
        return self._renderer.buffer_rgba(x, y)

    def clear(self):
        self._renderer.clear()
Пример #2
0
class RendererAgg(RendererBase):
    """
    The renderer handles all the drawing primitives using a graphics
    context instance that controls the colors/styles
    """
    
    debug=1
    def __init__(self, width, height, dpi):
        if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying')
        self.dpi = dpi
        self.width = width
        self.height = height
        self._renderer = _RendererAgg(int(width), int(height), dpi.get(),
                                    debug=False)
        self.draw_polygon = self._renderer.draw_polygon
        self.draw_rectangle = self._renderer.draw_rectangle
        self.draw_path = self._renderer.draw_path
        self.draw_lines = self._renderer.draw_lines
        self.draw_markers = self._renderer.draw_markers
        self.draw_image = self._renderer.draw_image
        self.draw_line_collection = self._renderer.draw_line_collection
        self.draw_poly_collection = self._renderer.draw_poly_collection
        self.draw_regpoly_collection = self._renderer.draw_regpoly_collection
        self.cache = self._renderer.cache
        self.blit = self._renderer.blit
        self.texmanager = TexManager()
        self.texd = {}  # a cache of tex image rasters
        self.bbox = lbwh_to_bbox(0,0, self.width, self.height)
        

    def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2):
        """
        Draw an arc centered at x,y with width and height and angles
        from 0.0 to 360.0

        If rgbFace is not None, fill the rectangle with that color.  gcEdge
        is a GraphicsContext instance

        Currently, I'm only supporting ellipses, ie angle args are
        ignored
        """
        if __debug__: verbose.report('RendererAgg.draw_arc', 'debug-annoying')
        self._renderer.draw_ellipse(
            gcEdge, rgbFace, x, y, width/2, height/2)  # ellipse takes radius
        

    def _draw_image(self, x, y, im):
        """
        Draw the Image instance into the current axes; x, y is the
        upper left hand corner of the image
        """
        if __debug__: verbose.report('RendererAgg.draw_image', 'debug-annoying')
        #self._renderer.draw_image(int(x), int(self.height-y), im)
        self._renderer.draw_image(int(x), int(y), im)        

    def draw_line(self, gc, x1, y1, x2, y2):
        """
        x and y are equal length arrays, draw lines connecting each
        point in x, y
        """
        if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying')
        x = array([x1,x2], typecode=Float)
        y = array([y1,y2], typecode=Float)
        self._renderer.draw_lines(gc, x, y)


    def draw_point(self, gc, x, y):
        """
        Draw a single point at x,y
        """
        if __debug__: verbose.report('RendererAgg.draw_point', 'debug-annoying')
        rgbFace = gc.get_rgb()
        self._renderer.draw_ellipse(
            gc, rgbFace, x, y, 0.5, 0.5)        

    def draw_mathtext(self, gc, x, y, s, prop, angle):    
        """
        Draw the math text using matplotlib.mathtext
        """
        if __debug__: verbose.report('RendererAgg.draw_mathtext', 'debug-annoying')
        size = prop.get_size_in_points()
        width, height, fonts = math_parse_s_ft2font(
            s, self.dpi.get(), size, angle)
        
        if angle == 90:
            width, height = height, width
        for font in fonts:
            if angle == 90:             
                font.horiz_image_to_vert_image() # <-- Rotate
                self._renderer.draw_text( font, int(x)-width, int(y)-height, gc)
            else:
                self._renderer.draw_text( font, int(x), int(y)-height, gc)                
        if 0:
            self._renderer.draw_rectangle(gc, None,
                                          int(x),
                                          self.height-int(y),
                                          width, height)


    
    def draw_text(self, gc, x, y, s, prop, angle, ismath):
        """
        Render the text
        """
        if __debug__: verbose.report('RendererAgg.draw_text', 'debug-annoying')

        if ismath:
            return self.draw_mathtext(gc, x, y, s, prop, angle)

        font = self._get_agg_font(prop)
        if font is None: return None
        if len(s)==1 and ord(s)>127:

            font.load_char(ord(s))
        else:
            font.set_text(s, angle)
        font.draw_glyphs_to_bitmap()

        #print x, y, int(x), int(y)
        
        self._renderer.draw_text(font, int(x), int(y), gc)
        

    def get_text_width_height(self, s, prop, ismath, rgb=(0,0,0)):
        """
        get the width and height in display coords of the string s
        with FontPropertry prop

        # passing rgb is a little hack to make cacheing in the
        # texmanager more efficient.  It is not meant to be used
        # outside the backend
        """

        if ismath=='TeX':
            # todo: handle props
            size = prop.get_size_in_points()
            dpi = self.dpi.get()
            Z = self.texmanager.get_rgba(s, size, dpi, rgb)
            m,n,tmp = Z.shape
            return n,m
        
        if ismath:
            width, height, fonts = math_parse_s_ft2font(
                s, self.dpi.get(), prop.get_size_in_points())
            return width, height
        font = self._get_agg_font(prop)
        font.set_text(s, 0.0)  # the width and height of unrotated string
        w, h = font.get_width_height()
        w /= 64.0  # convert from subpixels
        h /= 64.0
        return w, h

    def draw_tex(self, gc, x, y, s, prop, angle):
        # todo, handle props, angle, origins
        rgb = gc.get_rgb()
        size = prop.get_size_in_points()
        dpi = self.dpi.get()

        flip = angle==90
        w,h = self.get_text_width_height(s, prop, 'TeX', rgb)
        if flip:
            w,h = h,w
            x -= w

        key = s, size, dpi, rgb
        im = self.texd.get(key)
        
        if im is None:
            Z = self.texmanager.get_rgba(s, size, dpi, rgb)
            if flip:
                r = Z[:,:,0]
                g = Z[:,:,1]
                b = Z[:,:,2]
                a = Z[:,:,3]
                m,n,tmp = Z.shape

                def func(x):
                    return transpose(fliplr(x))

                Z = zeros((n,m,4), typecode=Float)
                Z[:,:,0] = func(r)
                Z[:,:,1] = func(g)
                Z[:,:,2] = func(b)
                Z[:,:,3] = func(a)
            im = fromarray(Z, 1)
            self.texd[key] = im            

        self.draw_image(x, y-h, im, 'upper', self.bbox)
        
    def get_canvas_width_height(self):
        'return the canvas width and height in display coords'
        return self.width, self.height


    def _get_agg_font(self, prop):
        """
        Get the font for text instance t, cacheing for efficiency
        """
        if __debug__: verbose.report('RendererAgg._get_agg_font', 'debug-annoying')

        key = hash(prop)
        font = _fontd.get(key)
        
        if font is None:
            fname = fontManager.findfont(prop)
            font = FT2Font(str(fname))
            _fontd[key] = font

        font.clear()
        size = prop.get_size_in_points()
        font.set_size(size, self.dpi.get())

        return font


    def points_to_pixels(self, points):
        """
        convert point measures to pixes using dpi and the pixels per
        inch of the display
        """
        if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying')
        return points*self.dpi.get()/72.0

    def tostring_rgb(self):
        if __debug__: verbose.report('RendererAgg.tostring_rgb', 'debug-annoying')
        return self._renderer.tostring_rgb()

    def tostring_argb(self):
        if __debug__: verbose.report('RendererAgg.tostring_argb', 'debug-annoying')
        return self._renderer.tostring_argb()
        
    def buffer_rgba(self):
        if __debug__: verbose.report('RendererAgg.buffer_rgba', 'debug-annoying')
        return self._renderer.buffer_rgba()
        
    def clear(self):
        self._renderer.clear()