color matrix filter in cairo and pixman

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E1635BD24@sisaex01sj>
Hi, All

Continuing previous of gaussian and convolution matrix,  I also add color matrix filter in cairo and pixman.  I thought pixman is the most efficient place to add such filtering

ColorMatrix filter should be fairly common in SVG, and right now canvas2D uses javascript for color filtering.  With this function implemented in cairo/pixman, we can do a better job in canvas 2D  In addition, implementing in pixman should be at least as fast as what is currently implemented in webkit.  If has clip, cairo/pixman is faster because it skips those pixels that are clipped out.  We will also implement such filters in GL backend.

You can download cairo from git clone https://code.google.com/p/cairogles/ and then "git checkout release-filter", also clone my pixman from git clone https://code.google.com/p/pixman-samsung/ and checkoiut "colormatrix" branch.  Attached are sample test code, source image and test result images for your testing.  Please review and comment.

Thanks in advance

Henry

________________________________________
From: Henry (Yu) Song - SISA
Sent: Tuesday, June 26, 2012 9:13 AM
To: [email protected]
Subject: gaussian filter and custom convolution filter

There has been several threads on how to design cairo APIs for blur and other filtering effects in the past, but no prototype implementation of ideas.

Since filtering effects are increasing becoming important and common in 2D graphics, such as SVG, CSS and 2D Canvas, I took the opportunity to propose few new APIs for filtering and implemented a prototype for them.  There are two new filterings in the proposal/prototype

1. Implemented CARO_FILTER_GAUSSIAN for image backend.   In addition to set filter type to CAIRO_FILTER_GAUSSIAN, I added few cairo APIs to allow set/get gaussian radius and sigma

2. Add a new cairo filter type - CAIRO_FILTER_CONVOLUTION.  This is intended to allow apps to specify their own convolution matrix. a new API (cairo_pattern_set_convolution_matrix()) is provided for this purpose.  An implementation for such custom filtering is also implemented for image backend.

I am aware that people have proposed chain-like APIs such that filtering effects can be chained together.  I thought to achieve such effect we can use multiple filter effects.

The actual implementation can be downloaded from git clone https://code.google.com/p/cairogles/ and then "git checkout release-filter".  Sample code, image and result image are also attached for your testing.  The underlying implementation for cairo gaussian filter and convolution filters uses pixman convolution filter.  The pixman convolution implementation is not optimized for gaussian, - would like to see/work on optimization for it.

Please review,  comments are extremely welcome.

Thanks a lot.

Henry

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
cairo_filter.c (text/x-csrc, 4.3 KB)
#include <cairo.h>
#include <math.h>

#define WIDTH 230
#define HEIGHT 253

void clear_cairo(cairo_t *cr, double width, double height)
{
    // background = white
    cairo_set_source_rgba(cr, 1, 1, 1, 1);
    cairo_rectangle(cr, 0.0, 0.0, width, height);
    cairo_fill(cr);
}


void render(cairo_t *cr, cairo_surface_t *img_surface)
{
    cairo_save(cr);
    clear_cairo(cr, WIDTH, HEIGHT);

    // paint with no effect, use default effect	
    cairo_translate (cr, 5, 5);
    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (img_surface);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    // paint with gaussian effect, use default radius 2
    cairo_pattern_set_filter (pattern, CAIRO_FILTER_GAUSSIAN);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);
    //cairo_paint (cr);

    // paint gaussian effect, use radius 4	
    cairo_pattern_set_radius_for_gaussian_filter (pattern, 4);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    cairo_pattern_destroy (pattern);
    
    // custom convolution effect
    pattern = cairo_pattern_create_for_surface (img_surface);
    // first custom effect
    cairo_pattern_set_filter (pattern, CAIRO_FILTER_CONVOLUTION);
    double matrix1[9] = { -1, -1, -1,
			  -1,  7, -1,
			  -1, -1, -1, };
    cairo_pattern_set_convolution_matrix (pattern, matrix1, 3, 3);
    cairo_translate (cr, -150, 81);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    // second custom effect
    double matrix2[25] = { 1,  1,    1,  1,  1,
			   1, -2,   -2, -2,  1,
			   1, -2, 0.01, -2,  1,
			   1, -2,   -2, -2,  1,
			   1,  1,    1,  1,  1, };
    cairo_pattern_set_convolution_matrix (pattern, matrix2, 5, 5);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    // third custom effect	
    double matrix3[9] = {  1,   -1,  1,
			  -1, -0.1, -1,
			   1,   -1,  1, };
    cairo_pattern_set_convolution_matrix (pattern, matrix3, 3, 3);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);
    
    cairo_pattern_destroy (pattern);

    // color effect
    pattern = cairo_pattern_create_for_surface (img_surface);
    // first color effect - gray
    cairo_pattern_set_filter (pattern, CAIRO_FILTER_COLOR);
    double color_matrix1[20] = { 0.5, 0.5, 0.5,  0,  0,
				 0.5, 0.5, 0.5,  0,  0,
				 0.5, 0.5, 0.5,  0,  0,
			  	   0,   0,   0,  1,  0};
    cairo_pattern_set_color_matrix (pattern, color_matrix1);
    cairo_translate (cr, -150, 81);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    // second color effect - inverted
    double color_matrix2[20] = { -1,   0,  0,  0,  1,
				  0,  -1,  0,  0,  1,
				  0,   0, -1,  0,  1,
				  0,   0,  0,  1,  0 };
    cairo_pattern_set_color_matrix (pattern, color_matrix2);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);

    // third color effect - red tint
    double color_matrix3[20] = {  1,   0,  0,  0,  0,
				  0,   0,  0,  0,  0,
				  0,   0,  0,  0,  0,
				  0,   0,  0,  1,  0 };
    cairo_pattern_set_color_matrix (pattern, color_matrix3);
    cairo_translate (cr, 75, 0);
    cairo_set_source (cr, pattern);
    //cairo_paint (cr);
    cairo_rectangle (cr, 0, 0, 70, 76);
    cairo_fill (cr);
    
    cairo_pattern_destroy (pattern);

    cairo_surface_write_to_png (cairo_get_target (cr), "./result.png");

    cairo_restore (cr);
}

int main(int argc, char **argv)
{
    cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
    cairo_t *cr = cairo_create(surface);
    
    cairo_surface_t *img_surface = cairo_image_surface_create_from_png("image008.png");

    render(cr, img_surface);
    
    cairo_destroy (cr);
    cairo_surface_destroy (surface);
    cairo_surface_destroy (img_surface);
    return 0;
}
image008.png (image/png, 9.8 KB) - not displayed
result.png (image/png, 47.6 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.