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
);
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
);
44 Cairo
.Pattern mask
= cr
.pop_group ();
45 Gdk
.cairo_set_source_pixbuf (cr
, pixbuf
, x
, y
);
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
,
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
];
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
) {
71 tmp
[i
] = scale1
* Math
.exp ( -(u
+ v
) / scale2
);
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 ();
87 *length
= n_params
+ 2;
92 public static Cairo
.ImageSurface
blur_image_surface (Cairo
.ImageSurface surface
,
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;
121 public static Cairo
.ImageSurface
create_shadow_surface (Gdk
.Pixbuf pixbuf
,
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
);
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
,
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