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()
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()