From 340c25623bfd3f601bc8b13825467e463135ca3c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 30 Oct 2015 12:43:02 -0400 Subject: [PATCH 1/2] Fix #347: Faster text rendering in Agg When the text isn't rotated, we can skip a lot of machinery by just doing a direct blending of text pixels onto the output buffer. --- doc/users/whats_new/faster-text-rendering.rst | 5 + src/_backend_agg.h | 95 ++++++++++++------- 2 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 doc/users/whats_new/faster-text-rendering.rst diff --git a/doc/users/whats_new/faster-text-rendering.rst b/doc/users/whats_new/faster-text-rendering.rst new file mode 100644 index 000000000000..d7807bb772f1 --- /dev/null +++ b/doc/users/whats_new/faster-text-rendering.rst @@ -0,0 +1,5 @@ +Faster text rendering +--------------------- + +Rendering text in the Agg backend is now less fuzzy and about 20% +faster to draw. diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 11abfcb98f5e..8676f5353737 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -734,41 +734,68 @@ inline void RendererAgg::draw_text_image(GCAgg &gc, ImageArray &image, int x, in typedef agg::renderer_scanline_aa renderer_type; - theRasterizer.reset_clipping(); - rendererBase.reset_clipping(true); - set_clipbox(gc.cliprect, theRasterizer); + if (angle != 0.0) { + agg::rendering_buffer srcbuf( + image.data(), (unsigned)image.dim(1), + (unsigned)image.dim(0), (unsigned)image.dim(1)); + agg::pixfmt_gray8 pixf_img(srcbuf); + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, theRasterizer); + + agg::trans_affine mtx; + mtx *= agg::trans_affine_translation(0, -image.dim(0)); + 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.dim(1), 0); + rect.line_to(image.dim(1), image.dim(0)); + rect.line_to(0, image.dim(0)); + rect.line_to(0, 0); + agg::conv_transform 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); + color_span_alloc_type sa; + image_accessor_type ia(pixf_img, agg::gray8(0)); + image_span_gen_type image_span_generator(ia, interpolator, filter); + span_gen_type output_span_generator(&image_span_generator, gc.color); + renderer_type ri(rendererBase, sa, output_span_generator); + + theRasterizer.add_path(rect2); + agg::render_scanlines(theRasterizer, slineP8, ri); + } else { + agg::rect_i fig, text; + + fig.init(0, 0, width, height); + text.init(x, y - image.dim(0), x + image.dim(1), y); + text.clip(fig); + + if (gc.cliprect.x1 != 0.0 || gc.cliprect.y1 != 0.0 || gc.cliprect.x2 != 0.0 || gc.cliprect.y2 != 0.0) { + agg::rect_i clip; + + clip.init(int(mpl_round(gc.cliprect.x1)), + int(mpl_round(gc.cliprect.y1)), + int(mpl_round(gc.cliprect.x2)), + int(mpl_round(gc.cliprect.y2))); + text.clip(clip); + } - agg::rendering_buffer srcbuf( - image.data(), (unsigned)image.dim(1), (unsigned)image.dim(0), (unsigned)image.dim(1)); - agg::pixfmt_gray8 pixf_img(srcbuf); - - agg::trans_affine mtx; - mtx *= agg::trans_affine_translation(0, -image.dim(0)); - 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.dim(1), 0); - rect.line_to(image.dim(1), image.dim(0)); - rect.line_to(0, image.dim(0)); - rect.line_to(0, 0); - agg::conv_transform 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); - color_span_alloc_type sa; - image_accessor_type ia(pixf_img, agg::gray8(0)); - image_span_gen_type image_span_generator(ia, interpolator, filter); - span_gen_type output_span_generator(&image_span_generator, gc.color); - renderer_type ri(rendererBase, sa, output_span_generator); - - theRasterizer.add_path(rect2); - agg::render_scanlines(theRasterizer, slineP8, ri); + for (int yi = text.y1; yi < text.y2; ++yi) { + for (int xi = text.x1; xi < text.x2; ++xi) { + typename ImageArray::value_type pixel = image( + yi - (y - image.dim(0)), xi - x); + pixFmt.blend_pixel(xi, yi, gc.color, pixel); + } + } + } } class span_conv_alpha From 83a10258f6bf7ff42a86f9fc523cbc378dde2ae9 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 2 Nov 2015 10:40:48 -0500 Subject: [PATCH 2/2] Use blend_color_solid as suggested by @jkseppan --- src/_backend_agg.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 8676f5353737..0249b3f4f13a 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -789,11 +789,8 @@ inline void RendererAgg::draw_text_image(GCAgg &gc, ImageArray &image, int x, in } for (int yi = text.y1; yi < text.y2; ++yi) { - for (int xi = text.x1; xi < text.x2; ++xi) { - typename ImageArray::value_type pixel = image( - yi - (y - image.dim(0)), xi - x); - pixFmt.blend_pixel(xi, yi, gc.color, pixel); - } + pixFmt.blend_solid_hspan(text.x1, yi, (text.x2 - text.x1), gc.color, + &image(yi - (y - image.dim(0)), text.x1 - x)); } } }