[cairo] propsal for blur-API in cairo
Mirco Müller
macslow at bangang.de
Wed Jun 17 13:23:06 PDT 2009
Greetings cairo-lovers!
I've spent some time thinking of what an API-addition for blurring in
cairo should look like. I tried to stick to the pattern used by the API
used for gradients.
The main idea is to introduce an opaque blur-object similar to a
gradient-pattern. You can set type and quality of it. Along those lines
also setters and getters for the numerous values controlling each
blur-type.
typedef enum _cairo_blur_type_t
{
CAIRO_BLUR_TYPE_BOXED = 0, // exp, stack, gaussian etc.
CAIRO_BLUR_TYPE_VECTORIAL, // directional blur
CAIRO_BLUR_TYPE_RADIAL // self-explanatory
} cairo_blur_type_t;
typedef enum _cairo_blur_quality_t
{
CAIRO_BLUR_QUALITY_LOW = 0, // low quality, but fast
CAIRO_BLUR_QUALITY_MEDIUM, // speed/quality compromise
CAIRO_BLUR_QUALITY_HIGH // quality over speed
} cairo_blur_quality;
typedef struct _cairo_blur_private_t
{
cairo_blur_type_t type; // radial, vectorial boxed
cairo_blur_quality_t quality; // low, medium, high
double center[2]; // for radial blur
double direction[2]; // for vectorial blur
double strength; // for radial/vectorial blur
double vradius; // for boxed blur
double hradius; // for boxed blur
} cairo_blur_private_t;
typedef struct _cairo_blur_t
{
cairo_blur_private_t* priv;
} cairo_blur_t;
cairo_blur_t*
cairo_blur_create (cairo_blur_type_t type);
cairo_blur_type_t
cairo_blur_get_type (cairo_blur_t* blur);
cairo_blur_quality_t
cairo_blur_get_quality (cairo_blur_t* blur);
void
cairo_blur_set_quality (cairo_blur_t* blur,
cairo_blur_quality_t quality);
void
cairo_blur_get_center (cairo_blur_t* blur,
double* x,
double* y);
void
cairo_blur_set_center (cairo_blur_t* blur,
double x,
double y);
void
cairo_blur_get_direction (cairo_blur_t* blur,
double* x_offset,
double* y_offset);
void
cairo_blur_set_direction (cairo_blur_t* blur,
double x_offset,
double y_offset);
double
cairo_blur_get_strength (cairo_blur_t* blur);
void
cairo_blur_set_strength (cairo_blur_t* blur,
double strength);
void
cairo_blur_get_radius (cairo_blur_t* blur,
double* vradius,
double* hradius);
void
cairo_blur_set_radius (cairo_blur_t* blur,
double vradius,
double hradius);
void
cairo_blur_destroy (cairo_blur_t* blur);
Now for the debatable part. How should the blur be applied? There are
two ideas for this.
1.) Just have it applied to a surface. This is very simple and keeps
the overall API-addition lean. The drawback is that this is less
flexible.
void
cairo_surface_apply_blur (cairo_surface_t* surface,
cairo_blur_t* blur);
or
void
cairo_blur_apply (cairo_blur_t* blur
cairo_surface_t* surface);
2.) Have a new cairo_foo_blurred() variation added for every current
drawing operator. That makes blurring a lot more versatile for users of
the new API. People don't have to think so much about how to e.g. just
apply a blur to the current stroke or fill they are doing and not to
anything else.
void
cairo_mask_blurred (cairo_t* cr,
cairo_pattern_t* pattern,
cairo_blur_t* blur);
void
cairo_mask_surface_blurred (cairo_t* cr,
cairo_surface_t* surface,
double surface_x,
double surface_y,
cairo_blur_t* blur);
void
cairo_fill_blurred (cairo_t* cr,
cairo_blur_t* blur);
void
cairo_fill_preserve_blurred (cairo_t* cr,
cairo_blur_t* blur);
void
cairo_stroke_blurred (cairo_t* cr,
cairo_blur_t* blur);
void
cairo_stroke_preserve_blurred (cairo_t* cr,
cairo_blur_t* blur);
void
cairo_paint_blurred (cairo_t* cr,
cairo_blur_t* blur);
void
cairo_paint_with_alpha_blurred (cairo_t* cr,
double alpha,
cairo_blur_t* blur);
cairo_show_text_blurred (cairo_t* cr,
const char* utf8,
cairo_blur_t* blur);
void
cairo_show_glyphs_blurred (cairo_t* cr,
const cairo_glyph_t* glyphs,
int num_glyphs,
cairo_blur_t* blur);
void
cairo_show_text_glyphs_blurred (cairo_t* cr,
...
cairo_blur_t* blur);
Here an example of what it could look like to do a gaussian blur on
just one fill (white fill with black "drop-shadow"):
cairo_blur_t* blur;
// setup context and stuff
...
blur = cairo_blur_create (CAIRO_BLUR_TYPE_BOXED);
cairo_blur_set_quality (blur, CAIRO_BLUR_QUALITY_HIGH);
cairo_blur_set_radius (blur, 0.1, 0.1);
// draw some path
...
cairo_set_rgba (cr, 0.0, 0.0, 0.0, 1.0);
cairo_fill_blurred_preserve (cr, blur);
cairo_blur_destroy (blur);
cairo_set_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_fill (cr);
This is how applying a radial blur would "feel" to a stroke:
cairo_blur_t* blur;
// setup context and stuff
...
blur = cairo_blur_create (CAIRO_BLUR_TYPE_RADIAL);
cairo_blur_set_quality (blur, CAIRO_BLUR_QUALITY_MEDIUM);
cairo_blur_set_center (blur, 0.5, 0.5);
cairo_blur_set_strength (blur, 0.3);
// draw some path
...
cairo_stroke_blurred (cr, blur);
cairo_blur_destroy (blur);
Applying a vectorial blur to the "destination":
cairo_blur_t* blur;
// setup context and stuff
...
blur = cairo_blur_create (CAIRO_BLUR_TYPE_VECTORIAL);
cairo_blur_set_quality (blur, CAIRO_BLUR_QUALITY_LOW);
cairo_blur_set_direction (blur, 0.1, -0.2);
cairo_blur_set_strength (blur, 0.2);
cairo_push_group (cr);
// draw something
...
cairo_pop_group_to_source (cr);
cairo_paint_blurred (cr, blur);
cairo_blur_destroy (blur);
What do you think?
Best regards ...
Mirco "MacSlow" Müller
More information about the cairo
mailing list