1 /*
2 * Exponential blur, based on algorithm by Jani Huhtanen.
3 *
4 * Copyright 2009 Canonical Ltd.
5 *
6 * Authors:
7 * Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
8 * Jason Smith <jason.smith@canonical.com>
9 *
10 * This program is free software: you can redistribute it and/or modify it
11 * under the terms of either or both of the following licenses:
12 *
13 * 1) the GNU Lesser General Public License version 3, as published by the
14 * Free Software Foundation; and/or
15 * 2) the GNU Lesser General Public License version 2.1, as published by
16 * the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranties of
20 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
21 * PURPOSE. See the applicable version of the GNU Lesser General Public
22 * License for more details.
23 *
24 * You should have received a copy of both the GNU Lesser General Public
25 * License version 3 and version 2.1 along with this program. If not, see
26 * <http://www.gnu.org/licenses/>
27 */
28
29 // FIXME: not working yet, unfinished
30
31 #include <math.h>
32
33 #include "exponential-blur.h"
34
35 static inline void
36 _blurinner (guchar* pixel,
37 gint *zR,
38 gint *zG,
39 gint *zB,
40 gint *zA,
41 gint alpha,
42 gint aprec,
43 gint zprec);
44
45 static inline void
46 _blurrow (guchar* pixels,
47 gint width,
48 gint height,
49 gint channels,
50 gint line,
51 gint alpha,
52 gint aprec,
53 gint zprec);
54
55 static inline void
56 _blurcol (guchar* pixels,
57 gint width,
58 gint height,
59 gint channels,
60 gint col,
61 gint alpha,
62 gint aprec,
63 gint zprec);
64
65 void
66 _expblur (guchar* pixels,
67 gint width,
68 gint height,
69 gint channels,
70 gint radius,
71 gint aprec,
72 gint zprec);
73
74 void
surface_exponential_blur(cairo_surface_t * surface,guint radius)75 surface_exponential_blur (cairo_surface_t* surface,
76 guint radius)
77 {
78 guchar* pixels;
79 guint width;
80 guint height;
81 cairo_format_t format;
82
83 // sanity checks are done in raico-blur.c
84
85 // before we mess with the surface execute any pending drawing
86 cairo_surface_flush (surface);
87
88 pixels = cairo_image_surface_get_data (surface);
89 width = cairo_image_surface_get_width (surface);
90 height = cairo_image_surface_get_height (surface);
91 format = cairo_image_surface_get_format (surface);
92
93 switch (format)
94 {
95 case CAIRO_FORMAT_ARGB32:
96 _expblur (pixels, width, height, 4, radius, 16, 7);
97 break;
98
99 case CAIRO_FORMAT_RGB24:
100 _expblur (pixels, width, height, 3, radius, 16, 7);
101 break;
102
103 case CAIRO_FORMAT_A8:
104 _expblur (pixels, width, height, 1, radius, 16, 7);
105 break;
106
107 default :
108 // do nothing
109 break;
110 }
111
112 // inform cairo we altered the surfaces contents
113 cairo_surface_mark_dirty (surface);
114 }
115
116 //
117 // pixels image-data
118 // width image-width
119 // height image-height
120 // channels image-channels
121 //
122 // in-place blur of image 'img' with kernel of approximate radius 'radius'
123 //
124 // blurs with two sided exponential impulse response
125 //
126 // aprec = precision of alpha parameter in fixed-point format 0.aprec
127 //
128 // zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
129 //
130 void
_expblur(guchar * pixels,gint width,gint height,gint channels,gint radius,gint aprec,gint zprec)131 _expblur (guchar* pixels,
132 gint width,
133 gint height,
134 gint channels,
135 gint radius,
136 gint aprec,
137 gint zprec)
138 {
139 gint alpha;
140 gint row = 0;
141 gint col = 0;
142
143 if (radius < 1)
144 return;
145
146 // calculate the alpha such that 90% of
147 // the kernel is within the radius.
148 // (Kernel extends to infinity)
149 alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
150
151 for (; row < height; row++)
152 _blurrow (pixels,
153 width,
154 height,
155 channels,
156 row,
157 alpha,
158 aprec,
159 zprec);
160
161 for(; col < width; col++)
162 _blurcol (pixels,
163 width,
164 height,
165 channels,
166 col,
167 alpha,
168 aprec,
169 zprec);
170
171 return;
172 }
173
174 static inline void
_blurinner(guchar * pixel,gint * zR,gint * zG,gint * zB,gint * zA,gint alpha,gint aprec,gint zprec)175 _blurinner (guchar* pixel,
176 gint *zR,
177 gint *zG,
178 gint *zB,
179 gint *zA,
180 gint alpha,
181 gint aprec,
182 gint zprec)
183 {
184 gint R;
185 gint G;
186 gint B;
187 guchar A;
188
189 R = *pixel;
190 G = *(pixel + 1);
191 B = *(pixel + 2);
192 A = *(pixel + 3);
193
194 *zR += (alpha * ((R << zprec) - *zR)) >> aprec;
195 *zG += (alpha * ((G << zprec) - *zG)) >> aprec;
196 *zB += (alpha * ((B << zprec) - *zB)) >> aprec;
197 *zA += (alpha * ((A << zprec) - *zA)) >> aprec;
198
199 *pixel = *zR >> zprec;
200 *(pixel + 1) = *zG >> zprec;
201 *(pixel + 2) = *zB >> zprec;
202 *(pixel + 3) = *zA >> zprec;
203 }
204
205 static inline void
_blurrow(guchar * pixels,gint width,gint height,gint channels,gint line,gint alpha,gint aprec,gint zprec)206 _blurrow (guchar* pixels,
207 gint width,
208 gint height,
209 gint channels,
210 gint line,
211 gint alpha,
212 gint aprec,
213 gint zprec)
214 {
215 gint zR;
216 gint zG;
217 gint zB;
218 gint zA;
219 gint index;
220 guchar* scanline;
221
222 scanline = &(pixels[line * width * channels]);
223
224 zR = *scanline << zprec;
225 zG = *(scanline + 1) << zprec;
226 zB = *(scanline + 2) << zprec;
227 zA = *(scanline + 3) << zprec;
228
229 for (index = 0; index < width; index ++)
230 _blurinner (&scanline[index * channels],
231 &zR,
232 &zG,
233 &zB,
234 &zA,
235 alpha,
236 aprec,
237 zprec);
238
239 for (index = width - 2; index >= 0; index--)
240 _blurinner (&scanline[index * channels],
241 &zR,
242 &zG,
243 &zB,
244 &zA,
245 alpha,
246 aprec,
247 zprec);
248 }
249
250 static inline void
_blurcol(guchar * pixels,gint width,gint height,gint channels,gint x,gint alpha,gint aprec,gint zprec)251 _blurcol (guchar* pixels,
252 gint width,
253 gint height,
254 gint channels,
255 gint x,
256 gint alpha,
257 gint aprec,
258 gint zprec)
259 {
260 gint zR;
261 gint zG;
262 gint zB;
263 gint zA;
264 gint index;
265 guchar* ptr;
266
267 ptr = pixels;
268
269 ptr += x * channels;
270
271 zR = *((guchar*) ptr ) << zprec;
272 zG = *((guchar*) ptr + 1) << zprec;
273 zB = *((guchar*) ptr + 2) << zprec;
274 zA = *((guchar*) ptr + 3) << zprec;
275
276 for (index = width; index < (height - 1) * width; index += width)
277 _blurinner ((guchar*) &ptr[index * channels],
278 &zR,
279 &zG,
280 &zB,
281 &zA,
282 alpha,
283 aprec,
284 zprec);
285
286 for (index = (height - 2) * width; index >= 0; index -= width)
287 _blurinner ((guchar*) &ptr[index * channels],
288 &zR,
289 &zG,
290 &zB,
291 &zA,
292 alpha,
293 aprec,
294 zprec);
295 }
296
297