/src/MapServer/src/renderers/agg/include/agg_blur.h
Line | Count | Source |
1 | | //---------------------------------------------------------------------------- |
2 | | // Anti-Grain Geometry - Version 2.4 |
3 | | // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) |
4 | | // |
5 | | // Permission to copy, use, modify, sell and distribute this software |
6 | | // is granted provided this copyright notice appears in all copies. |
7 | | // This software is provided "as is" without express or implied |
8 | | // warranty, and with no claim as to its suitability for any purpose. |
9 | | // |
10 | | //---------------------------------------------------------------------------- |
11 | | // Contact: mcseem@antigrain.com |
12 | | // mcseemagg@yahoo.com |
13 | | // http://www.antigrain.com |
14 | | //---------------------------------------------------------------------------- |
15 | | // |
16 | | // The Stack Blur Algorithm was invented by Mario Klingemann, |
17 | | // mario@quasimondo.com and described here: |
18 | | // http://incubator.quasimondo.com/processing/fast_blur_deluxe.php |
19 | | // (search phrase "Stackblur: Fast But Goodlooking"). |
20 | | // The major improvement is that there's no more division table |
21 | | // that was very expensive to create for large blur radii. Instead, |
22 | | // for 8-bit per channel and radius not exceeding 254 the division is |
23 | | // replaced by multiplication and shift. |
24 | | // |
25 | | //---------------------------------------------------------------------------- |
26 | | |
27 | | #ifndef AGG_BLUR_INCLUDED |
28 | | #define AGG_BLUR_INCLUDED |
29 | | |
30 | | #include "agg_array.h" |
31 | | #include "agg_pixfmt_transposer.h" |
32 | | |
33 | | namespace mapserver |
34 | | { |
35 | | |
36 | | template<class T> struct stack_blur_tables |
37 | | { |
38 | | static int16u const g_stack_blur8_mul[255]; |
39 | | static int8u const g_stack_blur8_shr[255]; |
40 | | }; |
41 | | |
42 | | //------------------------------------------------------------------------ |
43 | | template<class T> |
44 | | int16u const stack_blur_tables<T>::g_stack_blur8_mul[255] = |
45 | | { |
46 | | 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, |
47 | | 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, |
48 | | 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, |
49 | | 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, |
50 | | 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, |
51 | | 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, |
52 | | 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, |
53 | | 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, |
54 | | 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, |
55 | | 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, |
56 | | 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, |
57 | | 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, |
58 | | 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, |
59 | | 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, |
60 | | 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, |
61 | | 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 |
62 | | }; |
63 | | |
64 | | //------------------------------------------------------------------------ |
65 | | template<class T> |
66 | | int8u const stack_blur_tables<T>::g_stack_blur8_shr[255] = |
67 | | { |
68 | | 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, |
69 | | 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, |
70 | | 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, |
71 | | 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, |
72 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, |
73 | | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, |
74 | | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, |
75 | | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, |
76 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, |
77 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, |
78 | | 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, |
79 | | 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, |
80 | | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, |
81 | | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, |
82 | | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, |
83 | | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 |
84 | | }; |
85 | | |
86 | | |
87 | | |
88 | | //==============================================================stack_blur |
89 | | template<class ColorT, class CalculatorT> class stack_blur |
90 | | { |
91 | | public: |
92 | | typedef ColorT color_type; |
93 | | typedef CalculatorT calculator_type; |
94 | | |
95 | | //-------------------------------------------------------------------- |
96 | | template<class Img> void blur_x(Img& img, unsigned radius) |
97 | | { |
98 | | if(radius < 1) return; |
99 | | |
100 | | unsigned x, y, xp, i; |
101 | | unsigned stack_ptr; |
102 | | unsigned stack_start; |
103 | | |
104 | | color_type pix; |
105 | | color_type* stack_pix; |
106 | | calculator_type sum; |
107 | | calculator_type sum_in; |
108 | | calculator_type sum_out; |
109 | | |
110 | | unsigned w = img.width(); |
111 | | unsigned h = img.height(); |
112 | | unsigned wm = w - 1; |
113 | | unsigned div = radius * 2 + 1; |
114 | | |
115 | | unsigned div_sum = (radius + 1) * (radius + 1); |
116 | | unsigned mul_sum = 0; |
117 | | unsigned shr_sum = 0; |
118 | | unsigned max_val = color_type::base_mask; |
119 | | |
120 | | if(max_val <= 255 && radius < 255) |
121 | | { |
122 | | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[radius]; |
123 | | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[radius]; |
124 | | } |
125 | | |
126 | | m_buf.allocate(w, 128); |
127 | | m_stack.allocate(div, 32); |
128 | | |
129 | | for(y = 0; y < h; y++) |
130 | | { |
131 | | sum.clear(); |
132 | | sum_in.clear(); |
133 | | sum_out.clear(); |
134 | | |
135 | | pix = img.pixel(0, y); |
136 | | for(i = 0; i <= radius; i++) |
137 | | { |
138 | | m_stack[i] = pix; |
139 | | sum.add(pix, i + 1); |
140 | | sum_out.add(pix); |
141 | | } |
142 | | for(i = 1; i <= radius; i++) |
143 | | { |
144 | | pix = img.pixel((i > wm) ? wm : i, y); |
145 | | m_stack[i + radius] = pix; |
146 | | sum.add(pix, radius + 1 - i); |
147 | | sum_in.add(pix); |
148 | | } |
149 | | |
150 | | stack_ptr = radius; |
151 | | for(x = 0; x < w; x++) |
152 | | { |
153 | | if(mul_sum) sum.calc_pix(m_buf[x], mul_sum, shr_sum); |
154 | | else sum.calc_pix(m_buf[x], div_sum); |
155 | | |
156 | | sum.sub(sum_out); |
157 | | |
158 | | stack_start = stack_ptr + div - radius; |
159 | | if(stack_start >= div) stack_start -= div; |
160 | | stack_pix = &m_stack[stack_start]; |
161 | | |
162 | | sum_out.sub(*stack_pix); |
163 | | |
164 | | xp = x + radius + 1; |
165 | | if(xp > wm) xp = wm; |
166 | | pix = img.pixel(xp, y); |
167 | | |
168 | | *stack_pix = pix; |
169 | | |
170 | | sum_in.add(pix); |
171 | | sum.add(sum_in); |
172 | | |
173 | | ++stack_ptr; |
174 | | if(stack_ptr >= div) stack_ptr = 0; |
175 | | stack_pix = &m_stack[stack_ptr]; |
176 | | |
177 | | sum_out.add(*stack_pix); |
178 | | sum_in.sub(*stack_pix); |
179 | | } |
180 | | img.copy_color_hspan(0, y, w, &m_buf[0]); |
181 | | } |
182 | | } |
183 | | |
184 | | //-------------------------------------------------------------------- |
185 | | template<class Img> void blur_y(Img& img, unsigned radius) |
186 | | { |
187 | | pixfmt_transposer<Img> img2(img); |
188 | | blur_x(img2, radius); |
189 | | } |
190 | | |
191 | | //-------------------------------------------------------------------- |
192 | | template<class Img> void blur(Img& img, unsigned radius) |
193 | | { |
194 | | blur_x(img, radius); |
195 | | pixfmt_transposer<Img> img2(img); |
196 | | blur_x(img2, radius); |
197 | | } |
198 | | |
199 | | private: |
200 | | pod_vector<color_type> m_buf; |
201 | | pod_vector<color_type> m_stack; |
202 | | }; |
203 | | |
204 | | //====================================================stack_blur_calc_rgba |
205 | | template<class T=unsigned> struct stack_blur_calc_rgba |
206 | | { |
207 | | typedef T value_type; |
208 | | value_type r,g,b,a; |
209 | | |
210 | | AGG_INLINE void clear() |
211 | | { |
212 | | r = g = b = a = 0; |
213 | | } |
214 | | |
215 | | template<class ArgT> AGG_INLINE void add(const ArgT& v) |
216 | | { |
217 | | r += v.r; |
218 | | g += v.g; |
219 | | b += v.b; |
220 | | a += v.a; |
221 | | } |
222 | | |
223 | | template<class ArgT> AGG_INLINE void add(const ArgT& v, unsigned k) |
224 | | { |
225 | | r += v.r * k; |
226 | | g += v.g * k; |
227 | | b += v.b * k; |
228 | | a += v.a * k; |
229 | | } |
230 | | |
231 | | template<class ArgT> AGG_INLINE void sub(const ArgT& v) |
232 | | { |
233 | | r -= v.r; |
234 | | g -= v.g; |
235 | | b -= v.b; |
236 | | a -= v.a; |
237 | | } |
238 | | |
239 | | template<class ArgT> AGG_INLINE void calc_pix(ArgT& v, unsigned div) |
240 | | { |
241 | | typedef typename ArgT::value_type value_type; |
242 | | v.r = value_type(r / div); |
243 | | v.g = value_type(g / div); |
244 | | v.b = value_type(b / div); |
245 | | v.a = value_type(a / div); |
246 | | } |
247 | | |
248 | | template<class ArgT> |
249 | | AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) |
250 | | { |
251 | | typedef typename ArgT::value_type value_type; |
252 | | v.r = value_type((r * mul) >> shr); |
253 | | v.g = value_type((g * mul) >> shr); |
254 | | v.b = value_type((b * mul) >> shr); |
255 | | v.a = value_type((a * mul) >> shr); |
256 | | } |
257 | | }; |
258 | | |
259 | | |
260 | | //=====================================================stack_blur_calc_rgb |
261 | | template<class T=unsigned> struct stack_blur_calc_rgb |
262 | | { |
263 | | typedef T value_type; |
264 | | value_type r,g,b; |
265 | | |
266 | | AGG_INLINE void clear() |
267 | | { |
268 | | r = g = b = 0; |
269 | | } |
270 | | |
271 | | template<class ArgT> AGG_INLINE void add(const ArgT& v) |
272 | | { |
273 | | r += v.r; |
274 | | g += v.g; |
275 | | b += v.b; |
276 | | } |
277 | | |
278 | | template<class ArgT> AGG_INLINE void add(const ArgT& v, unsigned k) |
279 | | { |
280 | | r += v.r * k; |
281 | | g += v.g * k; |
282 | | b += v.b * k; |
283 | | } |
284 | | |
285 | | template<class ArgT> AGG_INLINE void sub(const ArgT& v) |
286 | | { |
287 | | r -= v.r; |
288 | | g -= v.g; |
289 | | b -= v.b; |
290 | | } |
291 | | |
292 | | template<class ArgT> AGG_INLINE void calc_pix(ArgT& v, unsigned div) |
293 | | { |
294 | | typedef typename ArgT::value_type value_type; |
295 | | v.r = value_type(r / div); |
296 | | v.g = value_type(g / div); |
297 | | v.b = value_type(b / div); |
298 | | } |
299 | | |
300 | | template<class ArgT> |
301 | | AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) |
302 | | { |
303 | | typedef typename ArgT::value_type value_type; |
304 | | v.r = value_type((r * mul) >> shr); |
305 | | v.g = value_type((g * mul) >> shr); |
306 | | v.b = value_type((b * mul) >> shr); |
307 | | } |
308 | | }; |
309 | | |
310 | | |
311 | | //====================================================stack_blur_calc_gray |
312 | | template<class T=unsigned> struct stack_blur_calc_gray |
313 | | { |
314 | | typedef T value_type; |
315 | | value_type v; |
316 | | |
317 | | AGG_INLINE void clear() |
318 | | { |
319 | | v = 0; |
320 | | } |
321 | | |
322 | | template<class ArgT> AGG_INLINE void add(const ArgT& a) |
323 | | { |
324 | | v += a.v; |
325 | | } |
326 | | |
327 | | template<class ArgT> AGG_INLINE void add(const ArgT& a, unsigned k) |
328 | | { |
329 | | v += a.v * k; |
330 | | } |
331 | | |
332 | | template<class ArgT> AGG_INLINE void sub(const ArgT& a) |
333 | | { |
334 | | v -= a.v; |
335 | | } |
336 | | |
337 | | template<class ArgT> AGG_INLINE void calc_pix(ArgT& a, unsigned div) |
338 | | { |
339 | | typedef typename ArgT::value_type value_type; |
340 | | a.v = value_type(v / div); |
341 | | } |
342 | | |
343 | | template<class ArgT> |
344 | | AGG_INLINE void calc_pix(ArgT& a, unsigned mul, unsigned shr) |
345 | | { |
346 | | typedef typename ArgT::value_type value_type; |
347 | | a.v = value_type((v * mul) >> shr); |
348 | | } |
349 | | }; |
350 | | |
351 | | |
352 | | |
353 | | //========================================================stack_blur_gray8 |
354 | | template<class Img> |
355 | | void stack_blur_gray8(Img& img, unsigned rx, unsigned ry) |
356 | | { |
357 | | unsigned x, y, xp, yp, i; |
358 | | unsigned stack_ptr; |
359 | | unsigned stack_start; |
360 | | |
361 | | const int8u* src_pix_ptr; |
362 | | int8u* dst_pix_ptr; |
363 | | unsigned pix; |
364 | | unsigned stack_pix; |
365 | | unsigned sum; |
366 | | unsigned sum_in; |
367 | | unsigned sum_out; |
368 | | |
369 | | unsigned w = img.width(); |
370 | | unsigned h = img.height(); |
371 | | unsigned wm = w - 1; |
372 | | unsigned hm = h - 1; |
373 | | |
374 | | unsigned div; |
375 | | unsigned mul_sum; |
376 | | unsigned shr_sum; |
377 | | |
378 | | pod_vector<int8u> stack; |
379 | | |
380 | | if(rx > 0) |
381 | | { |
382 | | if(rx > 254) rx = 254; |
383 | | div = rx * 2 + 1; |
384 | | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[rx]; |
385 | | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[rx]; |
386 | | stack.allocate(div); |
387 | | |
388 | | for(y = 0; y < h; y++) |
389 | | { |
390 | | sum = sum_in = sum_out = 0; |
391 | | |
392 | | src_pix_ptr = img.pix_ptr(0, y); |
393 | | pix = *src_pix_ptr; |
394 | | for(i = 0; i <= rx; i++) |
395 | | { |
396 | | stack[i] = pix; |
397 | | sum += pix * (i + 1); |
398 | | sum_out += pix; |
399 | | } |
400 | | for(i = 1; i <= rx; i++) |
401 | | { |
402 | | if(i <= wm) src_pix_ptr += Img::pix_step; |
403 | | pix = *src_pix_ptr; |
404 | | stack[i + rx] = pix; |
405 | | sum += pix * (rx + 1 - i); |
406 | | sum_in += pix; |
407 | | } |
408 | | |
409 | | stack_ptr = rx; |
410 | | xp = rx; |
411 | | if(xp > wm) xp = wm; |
412 | | src_pix_ptr = img.pix_ptr(xp, y); |
413 | | dst_pix_ptr = img.pix_ptr(0, y); |
414 | | for(x = 0; x < w; x++) |
415 | | { |
416 | | *dst_pix_ptr = (sum * mul_sum) >> shr_sum; |
417 | | dst_pix_ptr += Img::pix_step; |
418 | | |
419 | | sum -= sum_out; |
420 | | |
421 | | stack_start = stack_ptr + div - rx; |
422 | | if(stack_start >= div) stack_start -= div; |
423 | | sum_out -= stack[stack_start]; |
424 | | |
425 | | if(xp < wm) |
426 | | { |
427 | | src_pix_ptr += Img::pix_step; |
428 | | pix = *src_pix_ptr; |
429 | | ++xp; |
430 | | } |
431 | | |
432 | | stack[stack_start] = pix; |
433 | | |
434 | | sum_in += pix; |
435 | | sum += sum_in; |
436 | | |
437 | | ++stack_ptr; |
438 | | if(stack_ptr >= div) stack_ptr = 0; |
439 | | stack_pix = stack[stack_ptr]; |
440 | | |
441 | | sum_out += stack_pix; |
442 | | sum_in -= stack_pix; |
443 | | } |
444 | | } |
445 | | } |
446 | | |
447 | | if(ry > 0) |
448 | | { |
449 | | if(ry > 254) ry = 254; |
450 | | div = ry * 2 + 1; |
451 | | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[ry]; |
452 | | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[ry]; |
453 | | stack.allocate(div); |
454 | | |
455 | | int stride = img.stride(); |
456 | | for(x = 0; x < w; x++) |
457 | | { |
458 | | sum = sum_in = sum_out = 0; |
459 | | |
460 | | src_pix_ptr = img.pix_ptr(x, 0); |
461 | | pix = *src_pix_ptr; |
462 | | for(i = 0; i <= ry; i++) |
463 | | { |
464 | | stack[i] = pix; |
465 | | sum += pix * (i + 1); |
466 | | sum_out += pix; |
467 | | } |
468 | | for(i = 1; i <= ry; i++) |
469 | | { |
470 | | if(i <= hm) src_pix_ptr += stride; |
471 | | pix = *src_pix_ptr; |
472 | | stack[i + ry] = pix; |
473 | | sum += pix * (ry + 1 - i); |
474 | | sum_in += pix; |
475 | | } |
476 | | |
477 | | stack_ptr = ry; |
478 | | yp = ry; |
479 | | if(yp > hm) yp = hm; |
480 | | src_pix_ptr = img.pix_ptr(x, yp); |
481 | | dst_pix_ptr = img.pix_ptr(x, 0); |
482 | | for(y = 0; y < h; y++) |
483 | | { |
484 | | *dst_pix_ptr = (sum * mul_sum) >> shr_sum; |
485 | | dst_pix_ptr += stride; |
486 | | |
487 | | sum -= sum_out; |
488 | | |
489 | | stack_start = stack_ptr + div - ry; |
490 | | if(stack_start >= div) stack_start -= div; |
491 | | sum_out -= stack[stack_start]; |
492 | | |
493 | | if(yp < hm) |
494 | | { |
495 | | src_pix_ptr += stride; |
496 | | pix = *src_pix_ptr; |
497 | | ++yp; |
498 | | } |
499 | | |
500 | | stack[stack_start] = pix; |
501 | | |
502 | | sum_in += pix; |
503 | | sum += sum_in; |
504 | | |
505 | | ++stack_ptr; |
506 | | if(stack_ptr >= div) stack_ptr = 0; |
507 | | stack_pix = stack[stack_ptr]; |
508 | | |
509 | | sum_out += stack_pix; |
510 | | sum_in -= stack_pix; |
511 | | } |
512 | | } |
513 | | } |
514 | | } |
515 | | |
516 | | |
517 | | |
518 | | //========================================================stack_blur_rgb24 |
519 | | template<class Img> |
520 | | void stack_blur_rgb24(Img& img, unsigned rx, unsigned ry) |
521 | | { |
522 | | typedef typename Img::color_type color_type; |
523 | | typedef typename Img::order_type order_type; |
524 | | enum order_e |
525 | | { |
526 | | R = order_type::R, |
527 | | G = order_type::G, |
528 | | B = order_type::B |
529 | | }; |
530 | | |
531 | | unsigned x, y, xp, yp, i; |
532 | | unsigned stack_ptr; |
533 | | unsigned stack_start; |
534 | | |
535 | | const int8u* src_pix_ptr; |
536 | | int8u* dst_pix_ptr; |
537 | | color_type* stack_pix_ptr; |
538 | | |
539 | | unsigned sum_r; |
540 | | unsigned sum_g; |
541 | | unsigned sum_b; |
542 | | unsigned sum_in_r; |
543 | | unsigned sum_in_g; |
544 | | unsigned sum_in_b; |
545 | | unsigned sum_out_r; |
546 | | unsigned sum_out_g; |
547 | | unsigned sum_out_b; |
548 | | |
549 | | unsigned w = img.width(); |
550 | | unsigned h = img.height(); |
551 | | unsigned wm = w - 1; |
552 | | unsigned hm = h - 1; |
553 | | |
554 | | unsigned div; |
555 | | unsigned mul_sum; |
556 | | unsigned shr_sum; |
557 | | |
558 | | pod_vector<color_type> stack; |
559 | | |
560 | | if(rx > 0) |
561 | | { |
562 | | if(rx > 254) rx = 254; |
563 | | div = rx * 2 + 1; |
564 | | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[rx]; |
565 | | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[rx]; |
566 | | stack.allocate(div); |
567 | | |
568 | | for(y = 0; y < h; y++) |
569 | | { |
570 | | sum_r = |
571 | | sum_g = |
572 | | sum_b = |
573 | | sum_in_r = |
574 | | sum_in_g = |
575 | | sum_in_b = |
576 | | sum_out_r = |
577 | | sum_out_g = |
578 | | sum_out_b = 0; |
579 | | |
580 | | src_pix_ptr = img.pix_ptr(0, y); |
581 | | for(i = 0; i <= rx; i++) |
582 | | { |
583 | | stack_pix_ptr = &stack[i]; |
584 | | stack_pix_ptr->r = src_pix_ptr[R]; |
585 | | stack_pix_ptr->g = src_pix_ptr[G]; |
586 | | stack_pix_ptr->b = src_pix_ptr[B]; |
587 | | sum_r += src_pix_ptr[R] * (i + 1); |
588 | | sum_g += src_pix_ptr[G] * (i + 1); |
589 | | sum_b += src_pix_ptr[B] * (i + 1); |
590 | | sum_out_r += src_pix_ptr[R]; |
591 | | sum_out_g += src_pix_ptr[G]; |
592 | | sum_out_b += src_pix_ptr[B]; |
593 | | } |
594 | | for(i = 1; i <= rx; i++) |
595 | | { |
596 | | if(i <= wm) src_pix_ptr += Img::pix_width; |
597 | | stack_pix_ptr = &stack[i + rx]; |
598 | | stack_pix_ptr->r = src_pix_ptr[R]; |
599 | | stack_pix_ptr->g = src_pix_ptr[G]; |
600 | | stack_pix_ptr->b = src_pix_ptr[B]; |
601 | | sum_r += src_pix_ptr[R] * (rx + 1 - i); |
602 | | sum_g += src_pix_ptr[G] * (rx + 1 - i); |
603 | | sum_b += src_pix_ptr[B] * (rx + 1 - i); |
604 | | sum_in_r += src_pix_ptr[R]; |
605 | | sum_in_g += src_pix_ptr[G]; |
606 | | sum_in_b += src_pix_ptr[B]; |
607 | | } |
608 | | |
609 | | stack_ptr = rx; |
610 | | xp = rx; |
611 | | if(xp > wm) xp = wm; |
612 | | src_pix_ptr = img.pix_ptr(xp, y); |
613 | | dst_pix_ptr = img.pix_ptr(0, y); |
614 | | for(x = 0; x < w; x++) |
615 | | { |
616 | | dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; |
617 | | dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; |
618 | | dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; |
619 | | dst_pix_ptr += Img::pix_width; |
620 | | |
621 | | sum_r -= sum_out_r; |
622 | | sum_g -= sum_out_g; |
623 | | sum_b -= sum_out_b; |
624 | | |
625 | | stack_start = stack_ptr + div - rx; |
626 | | if(stack_start >= div) stack_start -= div; |
627 | | stack_pix_ptr = &stack[stack_start]; |
628 | | |
629 | | sum_out_r -= stack_pix_ptr->r; |
630 | | sum_out_g -= stack_pix_ptr->g; |
631 | | sum_out_b -= stack_pix_ptr->b; |
632 | | |
633 | | if(xp < wm) |
634 | | { |
635 | | src_pix_ptr += Img::pix_width; |
636 | | ++xp; |
637 | | } |
638 | | |
639 | | stack_pix_ptr->r = src_pix_ptr[R]; |
640 | | stack_pix_ptr->g = src_pix_ptr[G]; |
641 | | stack_pix_ptr->b = src_pix_ptr[B]; |
642 | | |
643 | | sum_in_r += src_pix_ptr[R]; |
644 | | sum_in_g += src_pix_ptr[G]; |
645 | | sum_in_b += src_pix_ptr[B]; |
646 | | sum_r += sum_in_r; |
647 | | sum_g += sum_in_g; |
648 | | sum_b += sum_in_b; |
649 | | |
650 | | ++stack_ptr; |
651 | | if(stack_ptr >= div) stack_ptr = 0; |
652 | | stack_pix_ptr = &stack[stack_ptr]; |
653 | | |
654 | | sum_out_r += stack_pix_ptr->r; |
655 | | sum_out_g += stack_pix_ptr->g; |
656 | | sum_out_b += stack_pix_ptr->b; |
657 | | sum_in_r -= stack_pix_ptr->r; |
658 | | sum_in_g -= stack_pix_ptr->g; |
659 | | sum_in_b -= stack_pix_ptr->b; |
660 | | } |
661 | | } |
662 | | } |
663 | | |
664 | | if(ry > 0) |
665 | | { |
666 | | if(ry > 254) ry = 254; |
667 | | div = ry * 2 + 1; |
668 | | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[ry]; |
669 | | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[ry]; |
670 | | stack.allocate(div); |
671 | | |
672 | | int stride = img.stride(); |
673 | | for(x = 0; x < w; x++) |
674 | | { |
675 | | sum_r = |
676 | | sum_g = |
677 | | sum_b = |
678 | | sum_in_r = |
679 | | sum_in_g = |
680 | | sum_in_b = |
681 | | sum_out_r = |
682 | | sum_out_g = |
683 | | sum_out_b = 0; |
684 | | |
685 | | src_pix_ptr = img.pix_ptr(x, 0); |
686 | | for(i = 0; i <= ry; i++) |
687 | | { |
688 | | stack_pix_ptr = &stack[i]; |
689 | | stack_pix_ptr->r = src_pix_ptr[R]; |
690 | | stack_pix_ptr->g = src_pix_ptr[G]; |
691 | | stack_pix_ptr->b = src_pix_ptr[B]; |
692 | | sum_r += src_pix_ptr[R] * (i + 1); |
693 | | sum_g += src_pix_ptr[G] * (i + 1); |
694 | | sum_b += src_pix_ptr[B] * (i + 1); |
695 | | sum_out_r += src_pix_ptr[R]; |
696 | | sum_out_g += src_pix_ptr[G]; |
697 | | sum_out_b += src_pix_ptr[B]; |
698 | | } |
699 | | for(i = 1; i <= ry; i++) |
700 | | { |
701 | | if(i <= hm) src_pix_ptr += stride; |
702 | | stack_pix_ptr = &stack[i + ry]; |
703 | | stack_pix_ptr->r = src_pix_ptr[R]; |
704 | | stack_pix_ptr->g = src_pix_ptr[G]; |
705 | | stack_pix_ptr->b = src_pix_ptr[B]; |
706 | | sum_r += src_pix_ptr[R] * (ry + 1 - i); |
707 | | sum_g += src_pix_ptr[G] * (ry + 1 - i); |
708 | | sum_b += src_pix_ptr[B] * (ry + 1 - i); |
709 | | sum_in_r += src_pix_ptr[R]; |
710 | | sum_in_g += src_pix_ptr[G]; |
711 | | sum_in_b += src_pix_ptr[B]; |
712 | | } |
713 | | |
714 | | stack_ptr = ry; |
715 | | yp = ry; |
716 | | if(yp > hm) yp = hm; |
717 | | src_pix_ptr = img.pix_ptr(x, yp); |
718 | | dst_pix_ptr = img.pix_ptr(x, 0); |
719 | | for(y = 0; y < h; y++) |
720 | | { |
721 | | dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; |
722 | | dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; |
723 | | dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; |
724 | | dst_pix_ptr += stride; |
725 | | |
726 | | sum_r -= sum_out_r; |
727 | | sum_g -= sum_out_g; |
728 | | sum_b -= sum_out_b; |
729 | | |
730 | | stack_start = stack_ptr + div - ry; |
731 | | if(stack_start >= div) stack_start -= div; |
732 | | |
733 | | stack_pix_ptr = &stack[stack_start]; |
734 | | sum_out_r -= stack_pix_ptr->r; |
735 | | sum_out_g -= stack_pix_ptr->g; |
736 | | sum_out_b -= stack_pix_ptr->b; |
737 | | |
738 | | if(yp < hm) |
739 | | { |
740 | | src_pix_ptr += stride; |
741 | | ++yp; |
742 | | } |
743 | | |
744 | | stack_pix_ptr->r = src_pix_ptr[R]; |
745 | | stack_pix_ptr->g = src_pix_ptr[G]; |
746 | | stack_pix_ptr->b = src_pix_ptr[B]; |
747 | | |
748 | | sum_in_r += src_pix_ptr[R]; |
749 | | sum_in_g += src_pix_ptr[G]; |
750 | | sum_in_b += src_pix_ptr[B]; |
751 | | sum_r += sum_in_r; |
752 | | sum_g += sum_in_g; |
753 | | sum_b += sum_in_b; |
754 | | |
755 | | ++stack_ptr; |
756 | | if(stack_ptr >= div) stack_ptr = 0; |
757 | | stack_pix_ptr = &stack[stack_ptr]; |
758 | | |
759 | | sum_out_r += stack_pix_ptr->r; |
760 | | sum_out_g += stack_pix_ptr->g; |
761 | | sum_out_b += stack_pix_ptr->b; |
762 | | sum_in_r -= stack_pix_ptr->r; |
763 | | sum_in_g -= stack_pix_ptr->g; |
764 | | sum_in_b -= stack_pix_ptr->b; |
765 | | } |
766 | | } |
767 | | } |
768 | | } |
769 | | |
770 | | |
771 | | |
772 | | //=======================================================stack_blur_rgba32 |
773 | | template<class Img> |
774 | | void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry) |
775 | 0 | { |
776 | 0 | typedef typename Img::color_type color_type; |
777 | 0 | typedef typename Img::order_type order_type; |
778 | 0 | enum order_e |
779 | 0 | { |
780 | 0 | R = order_type::R, |
781 | 0 | G = order_type::G, |
782 | 0 | B = order_type::B, |
783 | 0 | A = order_type::A |
784 | 0 | }; |
785 | |
|
786 | 0 | unsigned x, y, xp, yp, i; |
787 | 0 | unsigned stack_ptr; |
788 | 0 | unsigned stack_start; |
789 | |
|
790 | 0 | const int8u* src_pix_ptr; |
791 | 0 | int8u* dst_pix_ptr; |
792 | 0 | color_type* stack_pix_ptr; |
793 | |
|
794 | 0 | unsigned sum_r; |
795 | 0 | unsigned sum_g; |
796 | 0 | unsigned sum_b; |
797 | 0 | unsigned sum_a; |
798 | 0 | unsigned sum_in_r; |
799 | 0 | unsigned sum_in_g; |
800 | 0 | unsigned sum_in_b; |
801 | 0 | unsigned sum_in_a; |
802 | 0 | unsigned sum_out_r; |
803 | 0 | unsigned sum_out_g; |
804 | 0 | unsigned sum_out_b; |
805 | 0 | unsigned sum_out_a; |
806 | |
|
807 | 0 | unsigned w = img.width(); |
808 | 0 | unsigned h = img.height(); |
809 | 0 | unsigned wm = w - 1; |
810 | 0 | unsigned hm = h - 1; |
811 | |
|
812 | 0 | unsigned div; |
813 | 0 | unsigned mul_sum; |
814 | 0 | unsigned shr_sum; |
815 | |
|
816 | 0 | pod_vector<color_type> stack; |
817 | |
|
818 | 0 | if(rx > 0) |
819 | 0 | { |
820 | 0 | if(rx > 254) rx = 254; |
821 | 0 | div = rx * 2 + 1; |
822 | 0 | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[rx]; |
823 | 0 | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[rx]; |
824 | 0 | stack.allocate(div); |
825 | |
|
826 | 0 | for(y = 0; y < h; y++) |
827 | 0 | { |
828 | 0 | sum_r = |
829 | 0 | sum_g = |
830 | 0 | sum_b = |
831 | 0 | sum_a = |
832 | 0 | sum_in_r = |
833 | 0 | sum_in_g = |
834 | 0 | sum_in_b = |
835 | 0 | sum_in_a = |
836 | 0 | sum_out_r = |
837 | 0 | sum_out_g = |
838 | 0 | sum_out_b = |
839 | 0 | sum_out_a = 0; |
840 | |
|
841 | 0 | src_pix_ptr = img.pix_ptr(0, y); |
842 | 0 | for(i = 0; i <= rx; i++) |
843 | 0 | { |
844 | 0 | stack_pix_ptr = &stack[i]; |
845 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
846 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
847 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
848 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
849 | 0 | sum_r += src_pix_ptr[R] * (i + 1); |
850 | 0 | sum_g += src_pix_ptr[G] * (i + 1); |
851 | 0 | sum_b += src_pix_ptr[B] * (i + 1); |
852 | 0 | sum_a += src_pix_ptr[A] * (i + 1); |
853 | 0 | sum_out_r += src_pix_ptr[R]; |
854 | 0 | sum_out_g += src_pix_ptr[G]; |
855 | 0 | sum_out_b += src_pix_ptr[B]; |
856 | 0 | sum_out_a += src_pix_ptr[A]; |
857 | 0 | } |
858 | 0 | for(i = 1; i <= rx; i++) |
859 | 0 | { |
860 | 0 | if(i <= wm) src_pix_ptr += Img::pix_width; |
861 | 0 | stack_pix_ptr = &stack[i + rx]; |
862 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
863 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
864 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
865 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
866 | 0 | sum_r += src_pix_ptr[R] * (rx + 1 - i); |
867 | 0 | sum_g += src_pix_ptr[G] * (rx + 1 - i); |
868 | 0 | sum_b += src_pix_ptr[B] * (rx + 1 - i); |
869 | 0 | sum_a += src_pix_ptr[A] * (rx + 1 - i); |
870 | 0 | sum_in_r += src_pix_ptr[R]; |
871 | 0 | sum_in_g += src_pix_ptr[G]; |
872 | 0 | sum_in_b += src_pix_ptr[B]; |
873 | 0 | sum_in_a += src_pix_ptr[A]; |
874 | 0 | } |
875 | |
|
876 | 0 | stack_ptr = rx; |
877 | 0 | xp = rx; |
878 | 0 | if(xp > wm) xp = wm; |
879 | 0 | src_pix_ptr = img.pix_ptr(xp, y); |
880 | 0 | dst_pix_ptr = img.pix_ptr(0, y); |
881 | 0 | for(x = 0; x < w; x++) |
882 | 0 | { |
883 | 0 | dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; |
884 | 0 | dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; |
885 | 0 | dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; |
886 | 0 | dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; |
887 | 0 | dst_pix_ptr += Img::pix_width; |
888 | |
|
889 | 0 | sum_r -= sum_out_r; |
890 | 0 | sum_g -= sum_out_g; |
891 | 0 | sum_b -= sum_out_b; |
892 | 0 | sum_a -= sum_out_a; |
893 | | |
894 | 0 | stack_start = stack_ptr + div - rx; |
895 | 0 | if(stack_start >= div) stack_start -= div; |
896 | 0 | stack_pix_ptr = &stack[stack_start]; |
897 | |
|
898 | 0 | sum_out_r -= stack_pix_ptr->r; |
899 | 0 | sum_out_g -= stack_pix_ptr->g; |
900 | 0 | sum_out_b -= stack_pix_ptr->b; |
901 | 0 | sum_out_a -= stack_pix_ptr->a; |
902 | |
|
903 | 0 | if(xp < wm) |
904 | 0 | { |
905 | 0 | src_pix_ptr += Img::pix_width; |
906 | 0 | ++xp; |
907 | 0 | } |
908 | | |
909 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
910 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
911 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
912 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
913 | | |
914 | 0 | sum_in_r += src_pix_ptr[R]; |
915 | 0 | sum_in_g += src_pix_ptr[G]; |
916 | 0 | sum_in_b += src_pix_ptr[B]; |
917 | 0 | sum_in_a += src_pix_ptr[A]; |
918 | 0 | sum_r += sum_in_r; |
919 | 0 | sum_g += sum_in_g; |
920 | 0 | sum_b += sum_in_b; |
921 | 0 | sum_a += sum_in_a; |
922 | | |
923 | 0 | ++stack_ptr; |
924 | 0 | if(stack_ptr >= div) stack_ptr = 0; |
925 | 0 | stack_pix_ptr = &stack[stack_ptr]; |
926 | |
|
927 | 0 | sum_out_r += stack_pix_ptr->r; |
928 | 0 | sum_out_g += stack_pix_ptr->g; |
929 | 0 | sum_out_b += stack_pix_ptr->b; |
930 | 0 | sum_out_a += stack_pix_ptr->a; |
931 | 0 | sum_in_r -= stack_pix_ptr->r; |
932 | 0 | sum_in_g -= stack_pix_ptr->g; |
933 | 0 | sum_in_b -= stack_pix_ptr->b; |
934 | 0 | sum_in_a -= stack_pix_ptr->a; |
935 | 0 | } |
936 | 0 | } |
937 | 0 | } |
938 | |
|
939 | 0 | if(ry > 0) |
940 | 0 | { |
941 | 0 | if(ry > 254) ry = 254; |
942 | 0 | div = ry * 2 + 1; |
943 | 0 | mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[ry]; |
944 | 0 | shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[ry]; |
945 | 0 | stack.allocate(div); |
946 | |
|
947 | 0 | int stride = img.stride(); |
948 | 0 | for(x = 0; x < w; x++) |
949 | 0 | { |
950 | 0 | sum_r = |
951 | 0 | sum_g = |
952 | 0 | sum_b = |
953 | 0 | sum_a = |
954 | 0 | sum_in_r = |
955 | 0 | sum_in_g = |
956 | 0 | sum_in_b = |
957 | 0 | sum_in_a = |
958 | 0 | sum_out_r = |
959 | 0 | sum_out_g = |
960 | 0 | sum_out_b = |
961 | 0 | sum_out_a = 0; |
962 | |
|
963 | 0 | src_pix_ptr = img.pix_ptr(x, 0); |
964 | 0 | for(i = 0; i <= ry; i++) |
965 | 0 | { |
966 | 0 | stack_pix_ptr = &stack[i]; |
967 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
968 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
969 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
970 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
971 | 0 | sum_r += src_pix_ptr[R] * (i + 1); |
972 | 0 | sum_g += src_pix_ptr[G] * (i + 1); |
973 | 0 | sum_b += src_pix_ptr[B] * (i + 1); |
974 | 0 | sum_a += src_pix_ptr[A] * (i + 1); |
975 | 0 | sum_out_r += src_pix_ptr[R]; |
976 | 0 | sum_out_g += src_pix_ptr[G]; |
977 | 0 | sum_out_b += src_pix_ptr[B]; |
978 | 0 | sum_out_a += src_pix_ptr[A]; |
979 | 0 | } |
980 | 0 | for(i = 1; i <= ry; i++) |
981 | 0 | { |
982 | 0 | if(i <= hm) src_pix_ptr += stride; |
983 | 0 | stack_pix_ptr = &stack[i + ry]; |
984 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
985 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
986 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
987 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
988 | 0 | sum_r += src_pix_ptr[R] * (ry + 1 - i); |
989 | 0 | sum_g += src_pix_ptr[G] * (ry + 1 - i); |
990 | 0 | sum_b += src_pix_ptr[B] * (ry + 1 - i); |
991 | 0 | sum_a += src_pix_ptr[A] * (ry + 1 - i); |
992 | 0 | sum_in_r += src_pix_ptr[R]; |
993 | 0 | sum_in_g += src_pix_ptr[G]; |
994 | 0 | sum_in_b += src_pix_ptr[B]; |
995 | 0 | sum_in_a += src_pix_ptr[A]; |
996 | 0 | } |
997 | |
|
998 | 0 | stack_ptr = ry; |
999 | 0 | yp = ry; |
1000 | 0 | if(yp > hm) yp = hm; |
1001 | 0 | src_pix_ptr = img.pix_ptr(x, yp); |
1002 | 0 | dst_pix_ptr = img.pix_ptr(x, 0); |
1003 | 0 | for(y = 0; y < h; y++) |
1004 | 0 | { |
1005 | 0 | dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; |
1006 | 0 | dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; |
1007 | 0 | dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; |
1008 | 0 | dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; |
1009 | 0 | dst_pix_ptr += stride; |
1010 | |
|
1011 | 0 | sum_r -= sum_out_r; |
1012 | 0 | sum_g -= sum_out_g; |
1013 | 0 | sum_b -= sum_out_b; |
1014 | 0 | sum_a -= sum_out_a; |
1015 | | |
1016 | 0 | stack_start = stack_ptr + div - ry; |
1017 | 0 | if(stack_start >= div) stack_start -= div; |
1018 | |
|
1019 | 0 | stack_pix_ptr = &stack[stack_start]; |
1020 | 0 | sum_out_r -= stack_pix_ptr->r; |
1021 | 0 | sum_out_g -= stack_pix_ptr->g; |
1022 | 0 | sum_out_b -= stack_pix_ptr->b; |
1023 | 0 | sum_out_a -= stack_pix_ptr->a; |
1024 | |
|
1025 | 0 | if(yp < hm) |
1026 | 0 | { |
1027 | 0 | src_pix_ptr += stride; |
1028 | 0 | ++yp; |
1029 | 0 | } |
1030 | | |
1031 | 0 | stack_pix_ptr->r = src_pix_ptr[R]; |
1032 | 0 | stack_pix_ptr->g = src_pix_ptr[G]; |
1033 | 0 | stack_pix_ptr->b = src_pix_ptr[B]; |
1034 | 0 | stack_pix_ptr->a = src_pix_ptr[A]; |
1035 | | |
1036 | 0 | sum_in_r += src_pix_ptr[R]; |
1037 | 0 | sum_in_g += src_pix_ptr[G]; |
1038 | 0 | sum_in_b += src_pix_ptr[B]; |
1039 | 0 | sum_in_a += src_pix_ptr[A]; |
1040 | 0 | sum_r += sum_in_r; |
1041 | 0 | sum_g += sum_in_g; |
1042 | 0 | sum_b += sum_in_b; |
1043 | 0 | sum_a += sum_in_a; |
1044 | | |
1045 | 0 | ++stack_ptr; |
1046 | 0 | if(stack_ptr >= div) stack_ptr = 0; |
1047 | 0 | stack_pix_ptr = &stack[stack_ptr]; |
1048 | |
|
1049 | 0 | sum_out_r += stack_pix_ptr->r; |
1050 | 0 | sum_out_g += stack_pix_ptr->g; |
1051 | 0 | sum_out_b += stack_pix_ptr->b; |
1052 | 0 | sum_out_a += stack_pix_ptr->a; |
1053 | 0 | sum_in_r -= stack_pix_ptr->r; |
1054 | 0 | sum_in_g -= stack_pix_ptr->g; |
1055 | 0 | sum_in_b -= stack_pix_ptr->b; |
1056 | 0 | sum_in_a -= stack_pix_ptr->a; |
1057 | 0 | } |
1058 | 0 | } |
1059 | 0 | } |
1060 | 0 | } |
1061 | | |
1062 | | |
1063 | | |
1064 | | //===========================================================recursive_blur |
1065 | | template<class ColorT, class CalculatorT> class recursive_blur |
1066 | | { |
1067 | | public: |
1068 | | typedef ColorT color_type; |
1069 | | typedef CalculatorT calculator_type; |
1070 | | typedef typename color_type::value_type value_type; |
1071 | | typedef typename calculator_type::value_type calc_type; |
1072 | | |
1073 | | //-------------------------------------------------------------------- |
1074 | | template<class Img> void blur_x(Img& img, double radius) |
1075 | | { |
1076 | | if(radius < 0.62) return; |
1077 | | if(img.width() < 3) return; |
1078 | | |
1079 | | calc_type s = calc_type(radius * 0.5); |
1080 | | calc_type q = calc_type((s < 2.5) ? |
1081 | | 3.97156 - 4.14554 * sqrt(1 - 0.26891 * s) : |
1082 | | 0.98711 * s - 0.96330); |
1083 | | |
1084 | | calc_type q2 = calc_type(q * q); |
1085 | | calc_type q3 = calc_type(q2 * q); |
1086 | | |
1087 | | calc_type b0 = calc_type(1.0 / (1.578250 + |
1088 | | 2.444130 * q + |
1089 | | 1.428100 * q2 + |
1090 | | 0.422205 * q3)); |
1091 | | |
1092 | | calc_type b1 = calc_type( 2.44413 * q + |
1093 | | 2.85619 * q2 + |
1094 | | 1.26661 * q3); |
1095 | | |
1096 | | calc_type b2 = calc_type(-1.42810 * q2 + |
1097 | | -1.26661 * q3); |
1098 | | |
1099 | | calc_type b3 = calc_type(0.422205 * q3); |
1100 | | |
1101 | | calc_type b = calc_type(1 - (b1 + b2 + b3) * b0); |
1102 | | |
1103 | | b1 *= b0; |
1104 | | b2 *= b0; |
1105 | | b3 *= b0; |
1106 | | |
1107 | | int w = img.width(); |
1108 | | int h = img.height(); |
1109 | | int wm = w-1; |
1110 | | int x, y; |
1111 | | |
1112 | | m_sum1.allocate(w); |
1113 | | m_sum2.allocate(w); |
1114 | | m_buf.allocate(w); |
1115 | | |
1116 | | for(y = 0; y < h; y++) |
1117 | | { |
1118 | | calculator_type c; |
1119 | | c.from_pix(img.pixel(0, y)); |
1120 | | m_sum1[0].calc(b, b1, b2, b3, c, c, c, c); |
1121 | | c.from_pix(img.pixel(1, y)); |
1122 | | m_sum1[1].calc(b, b1, b2, b3, c, m_sum1[0], m_sum1[0], m_sum1[0]); |
1123 | | c.from_pix(img.pixel(2, y)); |
1124 | | m_sum1[2].calc(b, b1, b2, b3, c, m_sum1[1], m_sum1[0], m_sum1[0]); |
1125 | | |
1126 | | for(x = 3; x < w; ++x) |
1127 | | { |
1128 | | c.from_pix(img.pixel(x, y)); |
1129 | | m_sum1[x].calc(b, b1, b2, b3, c, m_sum1[x-1], m_sum1[x-2], m_sum1[x-3]); |
1130 | | } |
1131 | | |
1132 | | m_sum2[wm ].calc(b, b1, b2, b3, m_sum1[wm ], m_sum1[wm ], m_sum1[wm], m_sum1[wm]); |
1133 | | m_sum2[wm-1].calc(b, b1, b2, b3, m_sum1[wm-1], m_sum2[wm ], m_sum2[wm], m_sum2[wm]); |
1134 | | m_sum2[wm-2].calc(b, b1, b2, b3, m_sum1[wm-2], m_sum2[wm-1], m_sum2[wm], m_sum2[wm]); |
1135 | | m_sum2[wm ].to_pix(m_buf[wm ]); |
1136 | | m_sum2[wm-1].to_pix(m_buf[wm-1]); |
1137 | | m_sum2[wm-2].to_pix(m_buf[wm-2]); |
1138 | | |
1139 | | for(x = wm-3; x >= 0; --x) |
1140 | | { |
1141 | | m_sum2[x].calc(b, b1, b2, b3, m_sum1[x], m_sum2[x+1], m_sum2[x+2], m_sum2[x+3]); |
1142 | | m_sum2[x].to_pix(m_buf[x]); |
1143 | | } |
1144 | | img.copy_color_hspan(0, y, w, &m_buf[0]); |
1145 | | } |
1146 | | } |
1147 | | |
1148 | | //-------------------------------------------------------------------- |
1149 | | template<class Img> void blur_y(Img& img, double radius) |
1150 | | { |
1151 | | pixfmt_transposer<Img> img2(img); |
1152 | | blur_x(img2, radius); |
1153 | | } |
1154 | | |
1155 | | //-------------------------------------------------------------------- |
1156 | | template<class Img> void blur(Img& img, double radius) |
1157 | | { |
1158 | | blur_x(img, radius); |
1159 | | pixfmt_transposer<Img> img2(img); |
1160 | | blur_x(img2, radius); |
1161 | | } |
1162 | | |
1163 | | private: |
1164 | | mapserver::pod_vector<calculator_type> m_sum1; |
1165 | | mapserver::pod_vector<calculator_type> m_sum2; |
1166 | | mapserver::pod_vector<color_type> m_buf; |
1167 | | }; |
1168 | | |
1169 | | |
1170 | | //=================================================recursive_blur_calc_rgba |
1171 | | template<class T=double> struct recursive_blur_calc_rgba |
1172 | | { |
1173 | | typedef T value_type; |
1174 | | typedef recursive_blur_calc_rgba<T> self_type; |
1175 | | |
1176 | | value_type r,g,b,a; |
1177 | | |
1178 | | template<class ColorT> |
1179 | | AGG_INLINE void from_pix(const ColorT& c) |
1180 | | { |
1181 | | r = c.r; |
1182 | | g = c.g; |
1183 | | b = c.b; |
1184 | | a = c.a; |
1185 | | } |
1186 | | |
1187 | | AGG_INLINE void calc(value_type b1, |
1188 | | value_type b2, |
1189 | | value_type b3, |
1190 | | value_type b4, |
1191 | | const self_type& c1, |
1192 | | const self_type& c2, |
1193 | | const self_type& c3, |
1194 | | const self_type& c4) |
1195 | | { |
1196 | | r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; |
1197 | | g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; |
1198 | | b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; |
1199 | | a = b1*c1.a + b2*c2.a + b3*c3.a + b4*c4.a; |
1200 | | } |
1201 | | |
1202 | | template<class ColorT> |
1203 | | AGG_INLINE void to_pix(ColorT& c) const |
1204 | | { |
1205 | | typedef typename ColorT::value_type cv_type; |
1206 | | c.r = (cv_type)uround(r); |
1207 | | c.g = (cv_type)uround(g); |
1208 | | c.b = (cv_type)uround(b); |
1209 | | c.a = (cv_type)uround(a); |
1210 | | } |
1211 | | }; |
1212 | | |
1213 | | |
1214 | | //=================================================recursive_blur_calc_rgb |
1215 | | template<class T=double> struct recursive_blur_calc_rgb |
1216 | | { |
1217 | | typedef T value_type; |
1218 | | typedef recursive_blur_calc_rgb<T> self_type; |
1219 | | |
1220 | | value_type r,g,b; |
1221 | | |
1222 | | template<class ColorT> |
1223 | | AGG_INLINE void from_pix(const ColorT& c) |
1224 | | { |
1225 | | r = c.r; |
1226 | | g = c.g; |
1227 | | b = c.b; |
1228 | | } |
1229 | | |
1230 | | AGG_INLINE void calc(value_type b1, |
1231 | | value_type b2, |
1232 | | value_type b3, |
1233 | | value_type b4, |
1234 | | const self_type& c1, |
1235 | | const self_type& c2, |
1236 | | const self_type& c3, |
1237 | | const self_type& c4) |
1238 | | { |
1239 | | r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; |
1240 | | g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; |
1241 | | b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; |
1242 | | } |
1243 | | |
1244 | | template<class ColorT> |
1245 | | AGG_INLINE void to_pix(ColorT& c) const |
1246 | | { |
1247 | | typedef typename ColorT::value_type cv_type; |
1248 | | c.r = (cv_type)uround(r); |
1249 | | c.g = (cv_type)uround(g); |
1250 | | c.b = (cv_type)uround(b); |
1251 | | } |
1252 | | }; |
1253 | | |
1254 | | |
1255 | | //================================================recursive_blur_calc_gray |
1256 | | template<class T=double> struct recursive_blur_calc_gray |
1257 | | { |
1258 | | typedef T value_type; |
1259 | | typedef recursive_blur_calc_gray<T> self_type; |
1260 | | |
1261 | | value_type v; |
1262 | | |
1263 | | template<class ColorT> |
1264 | | AGG_INLINE void from_pix(const ColorT& c) |
1265 | | { |
1266 | | v = c.v; |
1267 | | } |
1268 | | |
1269 | | AGG_INLINE void calc(value_type b1, |
1270 | | value_type b2, |
1271 | | value_type b3, |
1272 | | value_type b4, |
1273 | | const self_type& c1, |
1274 | | const self_type& c2, |
1275 | | const self_type& c3, |
1276 | | const self_type& c4) |
1277 | | { |
1278 | | v = b1*c1.v + b2*c2.v + b3*c3.v + b4*c4.v; |
1279 | | } |
1280 | | |
1281 | | template<class ColorT> |
1282 | | AGG_INLINE void to_pix(ColorT& c) const |
1283 | | { |
1284 | | typedef typename ColorT::value_type cv_type; |
1285 | | c.v = (cv_type)uround(v); |
1286 | | } |
1287 | | }; |
1288 | | |
1289 | | } |
1290 | | |
1291 | | |
1292 | | |
1293 | | |
1294 | | #endif |