Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ba1d8d5

Browse files
committed
Add support for arbitrary angles of rotation on mathtext in Agg
backend. Uses agg to rotate the raster of the text. svn path=/trunk/matplotlib/; revision=3776
1 parent dc4dcc0 commit ba1d8d5

6 files changed

Lines changed: 119 additions & 164 deletions

File tree

lib/matplotlib/backends/backend_agg.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,10 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
174174
'debug-annoying')
175175
ox, oy, width, height, descent, font_image, used_characters = \
176176
self.mathtext_parser.parse(s, self.dpi.get(), prop)
177-
178-
if angle == 90:
179-
width, height = height, width
180-
ox, oy = oy, ox
181-
x = int(x) - width + ox
182-
y = int(y) - height + oy
183-
font_image.rotate()
184-
else:
185-
x = int(x) + ox
186-
y = int(y) - height + oy
187-
self._renderer.draw_text_image(font_image, x, y + 1, gc)
177+
178+
x = int(x) + ox
179+
y = int(y) - oy
180+
self._renderer.draw_text_image(font_image, x, y + 1, angle, gc)
188181
if 0:
189182
self._renderer.draw_rectangle(gc, None,
190183
int(x),
@@ -205,12 +198,14 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
205198
if len(s) == 1 and ord(s) > 127:
206199
font.load_char(ord(s), flags=LOAD_DEFAULT)
207200
else:
208-
font.set_text(s, angle, flags=LOAD_DEFAULT)
201+
font.set_text(s, 0, flags=LOAD_DEFAULT)
209202
font.draw_glyphs_to_bitmap()
210203

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

213-
self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, gc)
206+
# We pass '0' for angle here, since is has already been rotated
207+
# (in vector space) in the above call to font.set_text.
208+
self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc)
214209

215210

216211
def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)):
@@ -229,7 +224,7 @@ def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)):
229224
Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb)
230225
m,n,tmp = Z.shape
231226
# TODO: descent of TeX text (I am imitating backend_ps here -JKS)
232-
return n, m, m
227+
return n, m, 0
233228

234229
if ismath:
235230
ox, oy, width, height, descent, fonts, used_characters = \

lib/matplotlib/backends/backend_ps.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,9 @@ def get_text_width_height_descent(self, s, prop, ismath):
275275
l,b,r,t = texmanager.get_ps_bbox(s, fontsize)
276276
w = (r-l)
277277
h = (t-b)
278-
#print s, w, h
279278
# TODO: We need a way to get a good baseline from
280279
# text.usetex
281-
return w, h, h
280+
return w, h, 0
282281

283282
if ismath:
284283
width, height, descent, pswriter, used_characters = \

lib/matplotlib/mathtext.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ def __init__(self, font):
541541
self.font = font
542542
self.charmap = font.get_charmap()
543543
self.glyphmap = dict(
544-
[(glyphind, ccode) for ccode, glyphind in self.charmap.items()])
544+
[(glyphind, ccode) for ccode, glyphind in self.charmap.iteritems()])
545545

546546
def __repr__(self):
547547
return repr(self.font)
@@ -671,7 +671,7 @@ class BakomaFonts(TruetypeFonts):
671671
def __init__(self, *args, **kwargs):
672672
TruetypeFonts.__init__(self, *args, **kwargs)
673673
if not len(self.fontmap):
674-
for key, val in self._fontmap.items():
674+
for key, val in self._fontmap.iteritems():
675675
fullpath = os.path.join(self.basepath, val + ".ttf")
676676
self.fontmap[key] = fullpath
677677
self.fontmap[val] = fullpath

src/_backend_agg.cpp

Lines changed: 103 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
#include "agg_scanline_storage_aa.h"
1717
#include "agg_scanline_storage_bin.h"
1818
#include "agg_renderer_primitives.h"
19+
#include "agg_span_image_filter_gray.h"
20+
#include "agg_span_interpolator_linear.h"
21+
#include "agg_span_allocator.h"
1922
#include "util/agg_color_conv_rgb8.h"
2023

2124
#include "ft2font.h"
@@ -2103,13 +2106,74 @@ RendererAgg::draw_path(const Py::Tuple& args) {
21032106

21042107
}
21052108

2109+
/**
2110+
* This is a custom span generator that converts spans in the
2111+
* 8-bit inverted greyscale font buffer to rgba that agg can use.
2112+
*/
2113+
template<
2114+
class ColorT,
2115+
class ChildGenerator>
2116+
class font_to_rgba :
2117+
public agg::span_generator<ColorT,
2118+
agg::span_allocator<ColorT> >
2119+
{
2120+
public:
2121+
typedef ChildGenerator child_type;
2122+
typedef ColorT color_type;
2123+
typedef agg::span_allocator<color_type> allocator_type;
2124+
typedef agg::span_generator<
2125+
ColorT,
2126+
agg::span_allocator<ColorT> > base_type;
2127+
2128+
private:
2129+
child_type* _gen;
2130+
allocator_type _alloc;
2131+
color_type _color;
2132+
2133+
public:
2134+
font_to_rgba(child_type* gen, color_type color) :
2135+
base_type(_alloc),
2136+
_gen(gen),
2137+
_color(color) {
2138+
}
21062139

2140+
color_type* generate(int x, int y, unsigned len)
2141+
{
2142+
color_type* dst = base_type::allocator().span();
2143+
2144+
typename child_type::color_type* src = _gen->generate(x, y, len);
2145+
2146+
do {
2147+
*dst = _color;
2148+
dst->a = src->v;
2149+
++src;
2150+
++dst;
2151+
} while (--len);
2152+
2153+
return base_type::allocator().span();
2154+
}
2155+
2156+
void prepare(unsigned max_span_len)
2157+
{
2158+
_alloc.allocate(max_span_len);
2159+
_gen->prepare(max_span_len);
2160+
}
2161+
2162+
};
21072163

21082164
Py::Object
21092165
RendererAgg::draw_text_image(const Py::Tuple& args) {
21102166
_VERBOSE("RendererAgg::draw_text");
2167+
2168+
typedef agg::span_interpolator_linear<> interpolator_type;
2169+
typedef agg::span_image_filter_gray<agg::gray8, interpolator_type>
2170+
image_span_gen_type;
2171+
typedef font_to_rgba<pixfmt::color_type, image_span_gen_type>
2172+
span_gen_type;
2173+
typedef agg::renderer_scanline_aa<renderer_base, span_gen_type>
2174+
renderer_type;
21112175

2112-
args.verify_length(4);
2176+
args.verify_length(5);
21132177

21142178
FT2Image *image = static_cast<FT2Image*>(args[0].ptr());
21152179
if (!image->get_buffer())
@@ -2125,70 +2189,48 @@ RendererAgg::draw_text_image(const Py::Tuple& args) {
21252189
return Py::Object();
21262190
}
21272191

2128-
GCAgg gc = GCAgg(args[3], dpi);
2129-
2130-
set_clipbox_rasterizer( gc.cliprect);
2131-
2132-
2133-
pixfmt::color_type p;
2134-
p.r = int(255*gc.color.r);
2135-
p.b = int(255*gc.color.b);
2136-
p.g = int(255*gc.color.g);
2137-
p.a = int(255*gc.color.a);
2138-
2139-
//y = y-font->image.height;
2140-
unsigned thisx, thisy;
2141-
2142-
double l = 0;
2143-
double b = 0;
2144-
double r = width;
2145-
double t = height;
2146-
if (gc.cliprect!=NULL) {
2147-
l = gc.cliprect[0] ;
2148-
b = gc.cliprect[1] ;
2149-
double w = gc.cliprect[2];
2150-
double h = gc.cliprect[3];
2151-
r = l+w;
2152-
t = b+h;
2153-
}
2192+
double angle = Py::Float( args[3] );
2193+
2194+
GCAgg gc = GCAgg(args[4], dpi);
21542195

2196+
set_clipbox_rasterizer(gc.cliprect);
2197+
21552198
const unsigned char* const buffer = image->get_buffer();
2156-
2157-
for (size_t i=0; i< image->get_width(); i++) {
2158-
for (size_t j=0; j< image->get_height(); j++) {
2159-
thisx = i+x+image->offsetx;
2160-
thisy = j+y+image->offsety;
2161-
if (thisx<l || thisx>=r) continue;
2162-
if (thisy<height-t || thisy>=height-b) continue;
2163-
pixFmt->blend_pixel
2164-
(thisx, thisy, p, buffer[i + j*image->get_width()]);
2165-
}
2166-
}
2167-
2168-
/* bbox the text for debug purposes
2169-
2170-
agg::path_storage path;
2171-
2172-
path.move_to(x, y);
2173-
path.line_to(x, y+font->image.height);
2174-
path.line_to(x+font->image.width, y+font->image.height);
2175-
path.line_to(x+font->image.width, y);
2176-
path.close_polygon();
2177-
2178-
agg::rgba edgecolor(1,0,0,1);
2179-
2180-
//now fill the edge
2181-
agg::conv_stroke<agg::path_storage> stroke(path);
2182-
stroke.width(1.0);
2183-
rendererAA->color(edgecolor);
2184-
//self->theRasterizer->gamma(agg::gamma_power(gamma));
2185-
theRasterizer->add_path(stroke);
2186-
agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
2187-
2188-
*/
2199+
agg::rendering_buffer srcbuf
2200+
((agg::int8u*)buffer, image->get_width(),
2201+
image->get_height(), image->get_width());
2202+
agg::pixfmt_gray8 pixf_img(srcbuf);
2203+
2204+
agg::trans_affine mtx;
2205+
mtx *= agg::trans_affine_translation(0, -(int)image->get_height());
2206+
mtx *= agg::trans_affine_rotation(-angle * agg::pi / 180.0);
2207+
mtx *= agg::trans_affine_translation(x, y);
2208+
2209+
agg::path_storage rect;
2210+
rect.move_to(0, 0);
2211+
rect.line_to(image->get_width(), 0);
2212+
rect.line_to(image->get_width(), image->get_height());
2213+
rect.line_to(0, image->get_height());
2214+
rect.line_to(0, 0);
2215+
agg::conv_transform<agg::path_storage> rect2(rect, mtx);
2216+
2217+
agg::trans_affine inv_mtx(mtx);
2218+
inv_mtx.invert();
2219+
2220+
agg::image_filter_lut filter;
2221+
filter.calculate(agg::image_filter_spline36());
2222+
interpolator_type interpolator(inv_mtx);
2223+
agg::span_allocator<agg::gray8> gray_span_allocator;
2224+
image_span_gen_type image_span_generator(gray_span_allocator,
2225+
srcbuf, 0, interpolator, filter);
2226+
span_gen_type output_span_generator(&image_span_generator, gc.color);
2227+
renderer_type ri(*rendererBase, output_span_generator);
2228+
agg::rasterizer_scanline_aa<> rasterizer;
2229+
agg::scanline_p8 scanline;
2230+
rasterizer.add_path(rect2);
2231+
agg::render_scanlines(rasterizer, scanline, ri);
21892232

21902233
return Py::Object();
2191-
21922234
}
21932235

21942236

0 commit comments

Comments
 (0)