GaussianBlur: First partly functional demo
[libprolooks.git] / prolooks / GaussianBlur.vala
blobe9eae64e441dc3f153df5c5d0fd0f0ae1abe653f
1 /* Pixman based blur effect
2 * Copyright (C) 2008 Mathias Hasselmann
3 * Copyright (C) 2010 Hans Baier
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 namespace Prolooks {
22 public static void draw_pixbuf_with_mask (Cairo.Context cr,
23 Gdk.Pixbuf pixbuf,
24 double x,
25 double y,
26 double w,
27 double h) {
28 double dx, dy;
30 dx = pixbuf.get_width ();
31 dy = pixbuf.get_height ();
33 x += Posix.rint ((w - dx) / 2);
34 y += Posix.rint ((h - dy) / 2);
36 cr.push_group_with_content (Cairo.Content.ALPHA);
38 cr.set_source_rgb (1, 1, 1);
40 double corner_radius = Math.fmin (w, h) / 3;
41 rounded_rect (cr, x, y, dx, dy, corner_radius, corner_radius);
42 cr.fill ();
44 Cairo.Pattern mask = cr.pop_group ();
45 Gdk.cairo_set_source_pixbuf (cr, pixbuf, x, y);
46 cr.mask (mask);
49 /* G(x,y) = 1/(2 * PI * sigma^2) * exp(-(x^2 + y^2)/(2 * sigma^2))
51 private static Pixman.Fixed[] create_gaussian_blur_kernel (int radius,
52 double sigma,
53 int *length) {
54 double scale2 = 2.0 * sigma * sigma;
55 double scale1 = 1.0 / (Math.PI * scale2);
57 Pixman.int size = 2 * radius + 1;
58 Pixman.int n_params = size * size;
60 Pixman.Fixed[] params = new Pixman.Fixed[n_params + 2];
61 double[] tmp = new double[n_params];
62 double sum;
63 int x, y, i;
65 /* caluclate gaussian kernel in floating point format */
66 for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
67 for (y = -radius; y <= radius; ++y, ++i) {
68 double u = x * x;
69 double v = y * y;
71 tmp[i] = scale1 * Math.exp ( -(u + v) / scale2 );
73 sum += tmp[i];
77 /* normalize gaussian kernel and convert to fixed point format */
78 params[0] = size.to_fixed ();
79 params[1] = size.to_fixed ();
81 for (i = 0; i < n_params; ++i) {
82 Pixman.double quot = (tmp[i] / sum);
83 params[2 + i] = quot.to_fixed ();
86 if (length != null)
87 *length = n_params + 2;
89 return params;
92 public static Cairo.ImageSurface blur_image_surface (Cairo.ImageSurface surface,
93 int radius,
94 double sigma) {
95 int n_params = 0;
97 int width = surface.get_width ();
98 int height = surface.get_height ();
99 int stride = surface.get_stride ();
101 /* create pixman image for cairo image surface */
102 weak uchar[] surface_data = surface.get_data ();
103 Pixman.Image src = new Pixman.Image.for_bits (Pixman.Format.a8, width, height, surface_data, stride);
105 /* attach gaussian kernel to pixman image */
106 Pixman.Fixed[] params = create_gaussian_blur_kernel (radius, sigma, &n_params);
107 src.set_filter (Pixman.Filter.CONVOLUTION, params, n_params);
109 /* render blurred image to new pixman image */
110 uchar[] p = new uchar[stride * height];
111 Pixman.Image dst = new Pixman.Image.for_bits (Pixman.Format.a8, width, height, p, stride);
112 Pixman.image_composite (Pixman.Op.SRC, src, null, dst, 0, 0, 0, 0, 0, 0, (uint16) width, (uint16) height);
114 /* create new cairo image for blured pixman image */
115 Cairo.ImageSurface result = new Cairo.ImageSurface.for_data (p, Cairo.Format.A8, width, height, stride);
117 // FIXME: possible memory leak: freeing p;
118 return result;
121 public static Cairo.ImageSurface create_shadow_surface (Gdk.Pixbuf pixbuf,
122 double w,
123 double h,
124 double r = 3,
125 double alpha = 0.8,
126 double sigma = 3.0,
127 double offset = 2.0) {
129 /* create cairo context for image surface */
130 Cairo.ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.A8, (int) (w + r + r), (int) (h + r + r));
131 Cairo.Context cr = new Cairo.Context (surface);
133 /* pixbuf to mask pattern */
134 cr.push_group_with_content (Cairo.Content.ALPHA);
135 draw_pixbuf_with_mask (cr, pixbuf, r, r, w, h);
136 Cairo.Pattern pattern = cr.pop_group ();
138 /* fill image surface, considering mask pattern from pixbuf */
139 cr.set_source_rgba (1, 1, 1, alpha);
140 cr.mask (pattern);
142 /* render blurred surface image surface */
143 Cairo.ImageSurface blurred_surface = blur_image_surface (surface, (int) r, sigma);
145 return blurred_surface;
148 public static void draw_pixbuf_with_shadow (Cairo.Context cr,
149 Gdk.Pixbuf pixbuf,
150 double x,
151 double y,
152 double w,
153 double h,
154 double offset = 2,
155 double radius = 3) {
156 /* draw the shadow */
157 Cairo.Surface shadow = create_shadow_surface (pixbuf, w, h, radius);
159 cr.mask_surface (shadow, x + offset/2 - radius, y + offset/2 - radius);
161 /* draw the pixbuf */
162 draw_pixbuf_with_mask (cr, pixbuf, x - offset/2, y - offset/2, w, h);
165 } // namespace Prolooks