cairo blur image surface

This is used in the back-end for www.websequencediagrams.com.
// to build: // gcc -I/usr/include/cairo -lcairo -o blur blur.c #include#include #include #include "cairo.h" void cairo_image_surface_blur( cairo_surface_t* surface, double radius ) { // Steve Hanov, 2009 // Released into the public domain. // get width, height int width = cairo_image_surface_get_width( surface ); int height = cairo_image_surface_get_height( surface ); unsigned char* dst = (unsigned char*)malloc(width*height*4); unsigned* precalc = (unsigned*)malloc(width*height*sizeof(unsigned)); unsigned char* src = cairo_image_surface_get_data( surface ); double mul=1.f/((radius*2)*(radius*2)); int channel; // The number of times to perform the averaging. According to wikipedia, // three iterations is good enough to pass for a gaussian. const MAX_ITERATIONS = 3; int iteration; memcpy( dst, src, width*height*4 ); for ( iteration = 0; iteration < MAX_ITERATIONS; iteration++ ) { for( channel = 0; channel < 4; channel++ ) { int x,y; // precomputation step. unsigned char* pix = src; unsigned* pre = precalc; pix += channel; for (y=0;y 0) tot+=pre[-1]; if (y>0) tot+=pre[-width]; if (x>0 && y>0) tot-=pre[-width-1]; *pre++=tot; pix += 4; } } // blur step. pix = dst + (int)radius * width * 4 + (int)radius * 4 + channel; for (y=radius;y = width ? width - 1 : x + radius; int b = y + radius >= height ? height - 1 : y + radius; int tot = precalc[r+b*width] + precalc[l+t*width] - precalc[l+b*width] - precalc[r+t*width]; *pix=(unsigned char)(tot*mul); pix += 4; } pix += (int)radius * 2 * 4; } } memcpy( src, dst, width*height*4 ); } free( dst ); free( precalc ); } int main(int argc, char* argv[]) { cairo_surface_t* surface; cairo_t* ctx; cairo_text_extents_t text_extents; cairo_font_extents_t font_extents; double FontSize = 100; double radius = 7; double width, height; if ( argc != 3 ) { printf("Syntax: %s " "n", argv[0]); return -1; } // Get text size. surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, 10, 10 ); ctx = cairo_create( surface ); cairo_set_font_size( ctx, FontSize ); cairo_font_extents( ctx, &font_extents ); cairo_text_extents( ctx, argv[2], &text_extents ); height = font_extents.ascent + font_extents.descent + radius * 2; width = text_extents.x_advance + radius * 2; cairo_destroy( ctx ); cairo_surface_destroy( surface ); // Draw text. surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height ); ctx = cairo_create( surface ); cairo_set_font_size( ctx, FontSize ); cairo_move_to( ctx, 0 + radius, font_extents.ascent + radius ); cairo_show_text( ctx, argv[2] ); cairo_fill( ctx ); cairo_image_surface_blur( surface, 5 ); cairo_move_to( ctx, 0, font_extents.ascent ); cairo_show_text( ctx, argv[2] ); cairo_fill( ctx ); cairo_destroy( ctx ); cairo_surface_write_to_png( surface, argv[1] ); cairo_surface_destroy( surface ); return 0; }

Comments