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
22 public static void draw_pixbuf_with_mask (Cairo
.Context cr
,
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);
42 Cairo
.Pattern mask
= cr
.pop_group ();
44 Gdk
.cairo_set_source_pixbuf (cr
, pixbuf
, x
, y
);
48 public static void draw_image_surface_with_mask (Cairo
.Context cr
,
49 Cairo
.ImageSurface surface
,
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);
68 Cairo
.Pattern mask
= cr
.pop_group ();
70 cr
.set_source_surface (surface
, x
, y
);
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
,
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
];
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
) {
97 tmp
[i
] = scale1
* Math
.exp ( -(u
+ v
) / scale2
);
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 ();
113 *length
= n_params
+ 2;
118 public static Cairo
.ImageSurface
blur_image_surface (Cairo
.ImageSurface surface
,
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;
147 public static Cairo
.ImageSurface
create_shadow_surface_for_pixbuf (Gdk
.Pixbuf pixbuf
,
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
);
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
,
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
);
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
,
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
,
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