From: <md...@us...> - 2007-09-04 19:00:22
|
Revision: 3776 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3776&view=rev Author: mdboom Date: 2007-09-04 12:00:18 -0700 (Tue, 04 Sep 2007) Log Message: ----------- Add support for arbitrary angles of rotation on mathtext in Agg backend. Uses agg to rotate the raster of the text. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/_backend_agg.cpp trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-09-04 19:00:18 UTC (rev 3776) @@ -174,17 +174,10 @@ 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi.get(), prop) - - if angle == 90: - width, height = height, width - ox, oy = oy, ox - x = int(x) - width + ox - y = int(y) - height + oy - font_image.rotate() - else: - x = int(x) + ox - y = int(y) - height + oy - self._renderer.draw_text_image(font_image, x, y + 1, gc) + + x = int(x) + ox + y = int(y) - oy + self._renderer.draw_text_image(font_image, x, y + 1, angle, gc) if 0: self._renderer.draw_rectangle(gc, None, int(x), @@ -205,12 +198,14 @@ if len(s) == 1 and ord(s) > 127: font.load_char(ord(s), flags=LOAD_DEFAULT) else: - font.set_text(s, angle, flags=LOAD_DEFAULT) + font.set_text(s, 0, flags=LOAD_DEFAULT) font.draw_glyphs_to_bitmap() #print x, y, int(x), int(y) - self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, gc) + # We pass '0' for angle here, since is has already been rotated + # (in vector space) in the above call to font.set_text. + self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc) def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): @@ -229,7 +224,7 @@ Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb) m,n,tmp = Z.shape # TODO: descent of TeX text (I am imitating backend_ps here -JKS) - return n, m, m + return n, m, 0 if ismath: ox, oy, width, height, descent, fonts, used_characters = \ Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-09-04 19:00:18 UTC (rev 3776) @@ -275,10 +275,9 @@ l,b,r,t = texmanager.get_ps_bbox(s, fontsize) w = (r-l) h = (t-b) - #print s, w, h # TODO: We need a way to get a good baseline from # text.usetex - return w, h, h + return w, h, 0 if ismath: width, height, descent, pswriter, used_characters = \ Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-09-04 19:00:18 UTC (rev 3776) @@ -541,7 +541,7 @@ self.font = font self.charmap = font.get_charmap() self.glyphmap = dict( - [(glyphind, ccode) for ccode, glyphind in self.charmap.items()]) + [(glyphind, ccode) for ccode, glyphind in self.charmap.iteritems()]) def __repr__(self): return repr(self.font) @@ -671,7 +671,7 @@ def __init__(self, *args, **kwargs): TruetypeFonts.__init__(self, *args, **kwargs) if not len(self.fontmap): - for key, val in self._fontmap.items(): + for key, val in self._fontmap.iteritems(): fullpath = os.path.join(self.basepath, val + ".ttf") self.fontmap[key] = fullpath self.fontmap[val] = fullpath Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/_backend_agg.cpp 2007-09-04 19:00:18 UTC (rev 3776) @@ -16,6 +16,9 @@ #include "agg_scanline_storage_aa.h" #include "agg_scanline_storage_bin.h" #include "agg_renderer_primitives.h" +#include "agg_span_image_filter_gray.h" +#include "agg_span_interpolator_linear.h" +#include "agg_span_allocator.h" #include "util/agg_color_conv_rgb8.h" #include "ft2font.h" @@ -2103,13 +2106,74 @@ } +/** + * This is a custom span generator that converts spans in the + * 8-bit inverted greyscale font buffer to rgba that agg can use. + */ +template< + class ColorT, + class ChildGenerator> +class font_to_rgba : + public agg::span_generator<ColorT, + agg::span_allocator<ColorT> > +{ +public: + typedef ChildGenerator child_type; + typedef ColorT color_type; + typedef agg::span_allocator<color_type> allocator_type; + typedef agg::span_generator< + ColorT, + agg::span_allocator<ColorT> > base_type; +private: + child_type* _gen; + allocator_type _alloc; + color_type _color; + +public: + font_to_rgba(child_type* gen, color_type color) : + base_type(_alloc), + _gen(gen), + _color(color) { + } + color_type* generate(int x, int y, unsigned len) + { + color_type* dst = base_type::allocator().span(); + + typename child_type::color_type* src = _gen->generate(x, y, len); + + do { + *dst = _color; + dst->a = src->v; + ++src; + ++dst; + } while (--len); + + return base_type::allocator().span(); + } + + void prepare(unsigned max_span_len) + { + _alloc.allocate(max_span_len); + _gen->prepare(max_span_len); + } + +}; + Py::Object RendererAgg::draw_text_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_text"); + + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_image_filter_gray<agg::gray8, interpolator_type> + image_span_gen_type; + typedef font_to_rgba<pixfmt::color_type, image_span_gen_type> + span_gen_type; + typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> + renderer_type; - args.verify_length(4); + args.verify_length(5); FT2Image *image = static_cast<FT2Image*>(args[0].ptr()); if (!image->get_buffer()) @@ -2125,70 +2189,48 @@ return Py::Object(); } - GCAgg gc = GCAgg(args[3], dpi); + double angle = Py::Float( args[3] ); + + GCAgg gc = GCAgg(args[4], dpi); - set_clipbox_rasterizer( gc.cliprect); - - - pixfmt::color_type p; - p.r = int(255*gc.color.r); - p.b = int(255*gc.color.b); - p.g = int(255*gc.color.g); - p.a = int(255*gc.color.a); - - //y = y-font->image.height; - unsigned thisx, thisy; - - double l = 0; - double b = 0; - double r = width; - double t = height; - if (gc.cliprect!=NULL) { - l = gc.cliprect[0] ; - b = gc.cliprect[1] ; - double w = gc.cliprect[2]; - double h = gc.cliprect[3]; - r = l+w; - t = b+h; - } - + set_clipbox_rasterizer(gc.cliprect); + const unsigned char* const buffer = image->get_buffer(); + agg::rendering_buffer srcbuf + ((agg::int8u*)buffer, image->get_width(), + image->get_height(), image->get_width()); + agg::pixfmt_gray8 pixf_img(srcbuf); - for (size_t i=0; i< image->get_width(); i++) { - for (size_t j=0; j< image->get_height(); j++) { - thisx = i+x+image->offsetx; - thisy = j+y+image->offsety; - if (thisx<l || thisx>=r) continue; - if (thisy<height-t || thisy>=height-b) continue; - pixFmt->blend_pixel - (thisx, thisy, p, buffer[i + j*image->get_width()]); - } - } + agg::trans_affine mtx; + mtx *= agg::trans_affine_translation(0, -(int)image->get_height()); + mtx *= agg::trans_affine_rotation(-angle * agg::pi / 180.0); + mtx *= agg::trans_affine_translation(x, y); + + agg::path_storage rect; + rect.move_to(0, 0); + rect.line_to(image->get_width(), 0); + rect.line_to(image->get_width(), image->get_height()); + rect.line_to(0, image->get_height()); + rect.line_to(0, 0); + agg::conv_transform<agg::path_storage> rect2(rect, mtx); + + agg::trans_affine inv_mtx(mtx); + inv_mtx.invert(); + + agg::image_filter_lut filter; + filter.calculate(agg::image_filter_spline36()); + interpolator_type interpolator(inv_mtx); + agg::span_allocator<agg::gray8> gray_span_allocator; + image_span_gen_type image_span_generator(gray_span_allocator, + srcbuf, 0, interpolator, filter); + span_gen_type output_span_generator(&image_span_generator, gc.color); + renderer_type ri(*rendererBase, output_span_generator); + agg::rasterizer_scanline_aa<> rasterizer; + agg::scanline_p8 scanline; + rasterizer.add_path(rect2); + agg::render_scanlines(rasterizer, scanline, ri); - /* bbox the text for debug purposes - - agg::path_storage path; - - path.move_to(x, y); - path.line_to(x, y+font->image.height); - path.line_to(x+font->image.width, y+font->image.height); - path.line_to(x+font->image.width, y); - path.close_polygon(); - - agg::rgba edgecolor(1,0,0,1); - - //now fill the edge - agg::conv_stroke<agg::path_storage> stroke(path); - stroke.width(1.0); - rendererAA->color(edgecolor); - //self->theRasterizer->gamma(agg::gamma_power(gamma)); - theRasterizer->add_path(stroke); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - - */ - return Py::Object(); - } Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/ft2font.cpp 2007-09-04 19:00:18 UTC (rev 3776) @@ -43,8 +43,6 @@ FT_Library _ft2Library; FT2Image::FT2Image() : - offsetx(0), offsety(0), - _bRotated(false), _isDirty(true), _buffer(NULL), _width(0), _height(0), @@ -54,8 +52,6 @@ } FT2Image::FT2Image(unsigned long width, unsigned long height) : - offsetx(0), offsety(0), - _bRotated(false), _isDirty(true), _buffer(NULL), _width(0), _height(0), @@ -85,7 +81,6 @@ for (size_t n=0; n<numBytes; n++) _buffer[n] = 0; - _bRotated = false; _isDirty = true; } @@ -113,10 +108,7 @@ _width = 0; _height = 0; - offsetx = 0; - offsety = 0; _isDirty = true; - _bRotated = false; delete [] _buffer; _buffer = NULL; if (_rgbCopy) { @@ -142,58 +134,6 @@ return Py::Object(); } -void FT2Image::rotate() { - // If we have already rotated, just return. - if (_bRotated) - return; - - unsigned long width = _width; - unsigned long height = _height; - - unsigned long newWidth = _height; - unsigned long newHeight = _width; - - unsigned long numBytes = _width * _height; - - unsigned char * buffer = new unsigned char [numBytes]; - - unsigned long i, j, k, offset, nhMinusOne; - - nhMinusOne = newHeight - 1; - - unsigned char * read_it = _buffer; - - for (i=0; i<height; i++) { - offset = i*width; - for (j=0; j<width; j++) { - k = nhMinusOne - j; - buffer[i + k*newWidth] = *(read_it++); - } - } - - delete [] _buffer; - _buffer = buffer; - _width = newWidth; - _height = newHeight; - _bRotated = true; - _isDirty = true; -} -char FT2Image::rotate__doc__[] = -"rotate()\n" -"\n" -"Rotates the image 90 degrees.\n" -; -Py::Object -FT2Image::py_rotate(const Py::Tuple & args) { - _VERBOSE("FT2Image::rotate"); - - args.verify_length(0); - - rotate(); - - return Py::Object(); -} - void FT2Image::draw_bitmap( FT_Bitmap* bitmap, FT_Int x, @@ -404,17 +344,11 @@ unsigned char *src_end = src + (_width * _height); unsigned char *dst = _rgbaCopy->_buffer; - // This pre-multiplies the alpha, which apparently shouldn't - // be necessary for wxGTK, but it sure as heck seems to be. - unsigned int c; - unsigned int tmp; while (src != src_end) { - c = *src++; - tmp = ((255 - c) * c) >> 8; - *dst++ = tmp; - *dst++ = tmp; - *dst++ = tmp; - *dst++ = c; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = *src++; } } @@ -1266,12 +1200,6 @@ image->resize(width, height); } - image->offsetx = (int)(string_bbox.xMin / 64.0); - if (angle==0) - image->offsety = -image->get_height(); - else - image->offsety = (int)(-string_bbox.yMax/64.0); - for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox bbox; @@ -1840,8 +1768,6 @@ FT2Image::clear__doc__); add_varargs_method("resize", &FT2Image::py_resize, FT2Image::resize__doc__); - add_varargs_method("rotate", &FT2Image::py_rotate, - FT2Image::rotate__doc__); add_varargs_method("write_bitmap", &FT2Image::py_write_bitmap, FT2Image::write_bitmap__doc__); add_varargs_method("draw_rect", &FT2Image::py_draw_rect, Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007-09-04 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/ft2font.h 2007-09-04 19:00:18 UTC (rev 3776) @@ -30,7 +30,6 @@ void resize(unsigned long width, unsigned long height); void clear(); - void rotate(); void draw_bitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y); void write_bitmap(const char* filename) const; void draw_rect(unsigned long x0, unsigned long y0, @@ -46,8 +45,6 @@ Py::Object py_clear(const Py::Tuple & args); static char resize__doc__ []; Py::Object py_resize(const Py::Tuple & args); - static char rotate__doc__ []; - Py::Object py_rotate(const Py::Tuple & args); static char write_bitmap__doc__ []; Py::Object py_write_bitmap(const Py::Tuple & args); static char draw_rect__doc__ []; @@ -64,11 +61,7 @@ Py::Object py_get_width(const Py::Tuple & args); Py::Object py_get_height(const Py::Tuple & args); - unsigned long offsetx; - unsigned long offsety; - private: - bool _bRotated; bool _isDirty; unsigned char *_buffer; unsigned long _width; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |