Fix can_focus / remove deprecated HBox/VBox
[libprolooks.git] / src / GaussianBlur.vala
blobecce59902e30cf0c83bd9779dcf8426b452a37a4
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);
37 cr.set_source_rgb (1, 1, 1);
38 double corner_radius = Math.fmin (w, h) / 3;
39 rounded_rect (cr, x, y, dx, dy, corner_radius, corner_radius);
40 //cr.rectangle (x, y, dx, dy);
41 cr.fill ();
42 Cairo.Pattern mask = cr.pop_group ();
44 Gdk.cairo_set_source_pixbuf (cr, pixbuf, x, y);
45 cr.mask (mask);
48 public static void draw_image_surface_with_mask (Cairo.Context cr,
49 Cairo.ImageSurface surface,
50 double x,
51 double y,
52 double w,
53 double h) {
54 double dx, dy;
56 dx = surface.get_width ();
57 dy = surface.get_height ();
59 x += Posix.rint ((w - dx) / 2);
60 y += Posix.rint ((h - dy) / 2);
62 cr.push_group_with_content (Cairo.Content.ALPHA);
63 cr.set_source_rgb (1, 1, 1);
64 double corner_radius = Math.fmin (w, h) / 3;
65 rounded_rect (cr, x, y, dx, dy, corner_radius, corner_radius);
66 //cr.rectangle (x, y, dx, dy);
67 cr.fill ();
68 Cairo.Pattern mask = cr.pop_group ();
70 cr.set_source_surface (surface, x, y);
71 cr.mask (mask);
75 /* G(x,y) = 1/(2 * PI * sigma^2) * exp(-(x^2 + y^2)/(2 * sigma^2))
77 private static Pixman.Fixed[] create_gaussian_blur_kernel (int radius,
78 double sigma,
79 int *length) {
80 double scale2 = 2.0 * sigma * sigma;
81 double scale1 = 1.0 / (Math.PI * scale2);
83 Pixman.int size = 2 * radius + 1;
84 Pixman.int n_params = size * size;
86 Pixman.Fixed[] params = new Pixman.Fixed[n_params + 2];
87 double[] tmp = new double[n_params];
88 double sum;
89 int x, y, i;
91 /* caluclate gaussian kernel in floating point format */
92 for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
93 for (y = -radius; y <= radius; ++y, ++i) {
94 double u = x * x;
95 double v = y * y;
97 tmp[i] = scale1 * Math.exp ( -(u + v) / scale2 );
99 sum += tmp[i];
103 /* normalize gaussian kernel and convert to fixed point format */
104 params[0] = size.to_fixed ();
105 params[1] = size.to_fixed ();
107 for (i = 0; i < n_params; ++i) {
108 Pixman.double quot = (tmp[i] / sum);
109 params[2 + i] = quot.to_fixed ();
112 if (length != null)
113 *length = n_params + 2;
115 return params;
118 public static Cairo.ImageSurface blur_image_surface (Cairo.ImageSurface surface,
119 int radius,
120 double sigma) {
121 int n_params = 0;
123 int width = surface.get_width ();
124 int height = surface.get_height ();
125 int stride = surface.get_stride ();
127 /* create pixman image for cairo image surface */
128 weak uchar[] surface_data = surface.get_data ();
129 Pixman.Image src = new Pixman.Image.for_bits (Pixman.Format.a8, width, height, surface_data, stride);
131 /* attach gaussian kernel to pixman image */
132 Pixman.Fixed[] params = create_gaussian_blur_kernel (radius, sigma, &n_params);
133 src.set_filter (Pixman.Filter.CONVOLUTION, params, n_params);
135 /* render blurred image to new pixman image */
136 uchar[] result_data = new uchar[stride * height];
137 Pixman.Image dst = new Pixman.Image.for_bits (Pixman.Format.a8, width, height, result_data, stride);
138 Pixman.image_composite (Pixman.Op.SRC, src, null, dst, 0, 0, 0, 0, 0, 0, (uint16) width, (uint16) height);
140 /* create new cairo image for blured pixman image */
141 Cairo.ImageSurface result = new Cairo.ImageSurface.for_data (result_data, Cairo.Format.A8, width, height, stride);
143 // FIXME: possible memory leak: freeing result_data;
144 return result;
147 public static Cairo.ImageSurface create_shadow_surface_for_pixbuf (Gdk.Pixbuf pixbuf,
148 double w,
149 double h,
150 double r = 3,
151 double alpha = 0.8,
152 double sigma = 3.0,
153 double offset = 2.0) {
155 /* create cairo context for image surface */
156 Cairo.ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.A8, (int) (w + r + r), (int) (h + r + r));
157 Cairo.Context cr = new Cairo.Context (surface);
159 /* pixbuf to mask pattern */
160 cr.push_group_with_content (Cairo.Content.ALPHA);
161 draw_pixbuf_with_mask (cr, pixbuf, r, r, w, h);
162 Cairo.Pattern pattern = cr.pop_group ();
164 /* fill image surface, considering mask pattern from pixbuf */
165 cr.set_source_rgba (1, 1, 1, alpha);
166 cr.mask (pattern);
168 /* render blurred image surface */
169 Cairo.ImageSurface blurred_surface = blur_image_surface (surface, (int) r, sigma);
171 return blurred_surface;
174 public static Cairo.ImageSurface create_shadow_surface (Cairo.ImageSurface orig,
175 double w,
176 double h,
177 double r = 3,
178 double alpha = 0.8,
179 double sigma = 3.0,
180 double offset = 2.0) {
182 /* create cairo context for image surface */
183 Cairo.ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.A8, (int) (w + r + r), (int) (h + r + r));
184 Cairo.Context cr = new Cairo.Context (surface);
186 /* surface to mask pattern */
187 cr.push_group_with_content (Cairo.Content.ALPHA);
188 draw_image_surface_with_mask (cr, orig, r, r, w, h);
189 Cairo.Pattern pattern = cr.pop_group ();
191 /* fill image surface, considering mask pattern from orig */
192 cr.set_source_rgba (1, 1, 1, alpha);
193 cr.mask (pattern);
195 /* render blurred image surface */
196 Cairo.ImageSurface blurred_surface = blur_image_surface (surface, (int) r, sigma);
198 return blurred_surface;
202 public static void draw_pixbuf_with_shadow (Cairo.Context cr,
203 Gdk.Pixbuf pixbuf,
204 double x,
205 double y,
206 double w,
207 double h,
208 double offset = 2,
209 double radius = 3) {
210 /* draw the shadow */
211 Cairo.Surface shadow = create_shadow_surface_for_pixbuf (pixbuf, w, h, radius);
213 cr.mask_surface (shadow, x + offset/2 - radius, y + offset/2 - radius);
215 /* draw the pixbuf */
216 draw_pixbuf_with_mask (cr, pixbuf, x - offset/2, y - offset/2, w, h);
219 public static void draw_image_surface_with_shadow (Cairo.Context cr,
220 Cairo.ImageSurface surface,
221 double x,
222 double y,
223 double w,
224 double h,
225 double offset = 2,
226 double radius = 3) {
227 /* draw the shadow */
228 Cairo.Surface shadow = create_shadow_surface (surface, w, h, radius);
230 cr.mask_surface (shadow, x + offset/2 - radius, y + offset/2 - radius);
232 /* draw the pixbuf */
233 draw_image_surface_with_mask (cr, surface, x - offset/2, y - offset/2, w, h);
235 } // namespace Prolooks