xref: /haiku/headers/libs/agg/agg_blur.h (revision e39da397f5ff79f2db9f9a3ddf1852b6710578af)
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. Insted,
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 agg
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         //--------------------------------------------------------------------
blur_x(Img & img,unsigned radius)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         //--------------------------------------------------------------------
blur_y(Img & img,unsigned radius)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         //--------------------------------------------------------------------
blur(Img & img,unsigned radius)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 
clearstack_blur_calc_rgba210         AGG_INLINE void clear()
211         {
212             r = g = b = a = 0;
213         }
214 
addstack_blur_calc_rgba215         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 
addstack_blur_calc_rgba223         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 
substack_blur_calc_rgba231         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 
calc_pixstack_blur_calc_rgba239         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>
calc_pixstack_blur_calc_rgba249         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 
clearstack_blur_calc_rgb266         AGG_INLINE void clear()
267         {
268             r = g = b = 0;
269         }
270 
addstack_blur_calc_rgb271         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 
addstack_blur_calc_rgb278         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 
substack_blur_calc_rgb285         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 
calc_pixstack_blur_calc_rgb292         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>
calc_pixstack_blur_calc_rgb301         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 
clearstack_blur_calc_gray317         AGG_INLINE void clear()
318         {
319             v = 0;
320         }
321 
addstack_blur_calc_gray322         template<class ArgT> AGG_INLINE void add(const ArgT& a)
323         {
324             v += a.v;
325         }
326 
addstack_blur_calc_gray327         template<class ArgT> AGG_INLINE void add(const ArgT& a, unsigned k)
328         {
329             v += a.v * k;
330         }
331 
substack_blur_calc_gray332         template<class ArgT> AGG_INLINE void sub(const ArgT& a)
333         {
334             v -= a.v;
335         }
336 
calc_pixstack_blur_calc_gray337         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>
calc_pixstack_blur_calc_gray344         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>
stack_blur_gray8(Img & img,unsigned rx,unsigned ry)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>
stack_blur_rgb24(Img & img,unsigned rx,unsigned ry)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>
stack_blur_rgba32(Img & img,unsigned rx,unsigned ry)774     void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry)
775     {
776         typedef typename Img::color_type color_type;
777         typedef typename Img::order_type order_type;
778         enum order_e
779         {
780             R = order_type::R,
781             G = order_type::G,
782             B = order_type::B,
783             A = order_type::A
784         };
785 
786         unsigned x, y, xp, yp, i;
787         unsigned stack_ptr;
788         unsigned stack_start;
789 
790         const int8u* src_pix_ptr;
791               int8u* dst_pix_ptr;
792         color_type*  stack_pix_ptr;
793 
794         unsigned sum_r;
795         unsigned sum_g;
796         unsigned sum_b;
797         unsigned sum_a;
798         unsigned sum_in_r;
799         unsigned sum_in_g;
800         unsigned sum_in_b;
801         unsigned sum_in_a;
802         unsigned sum_out_r;
803         unsigned sum_out_g;
804         unsigned sum_out_b;
805         unsigned sum_out_a;
806 
807         unsigned w   = img.width();
808         unsigned h   = img.height();
809         unsigned wm  = w - 1;
810         unsigned hm  = h - 1;
811 
812         unsigned div;
813         unsigned mul_sum;
814         unsigned shr_sum;
815 
816         pod_vector<color_type> stack;
817 
818         if(rx > 0)
819         {
820             if(rx > 254) rx = 254;
821             div = rx * 2 + 1;
822             mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[rx];
823             shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[rx];
824             stack.allocate(div);
825 
826             for(y = 0; y < h; y++)
827             {
828                 sum_r =
829                 sum_g =
830                 sum_b =
831                 sum_a =
832                 sum_in_r =
833                 sum_in_g =
834                 sum_in_b =
835                 sum_in_a =
836                 sum_out_r =
837                 sum_out_g =
838                 sum_out_b =
839                 sum_out_a = 0;
840 
841                 src_pix_ptr = img.pix_ptr(0, y);
842                 for(i = 0; i <= rx; i++)
843                 {
844                     stack_pix_ptr    = &stack[i];
845                     stack_pix_ptr->r = src_pix_ptr[R];
846                     stack_pix_ptr->g = src_pix_ptr[G];
847                     stack_pix_ptr->b = src_pix_ptr[B];
848                     stack_pix_ptr->a = src_pix_ptr[A];
849                     sum_r           += src_pix_ptr[R] * (i + 1);
850                     sum_g           += src_pix_ptr[G] * (i + 1);
851                     sum_b           += src_pix_ptr[B] * (i + 1);
852                     sum_a           += src_pix_ptr[A] * (i + 1);
853                     sum_out_r       += src_pix_ptr[R];
854                     sum_out_g       += src_pix_ptr[G];
855                     sum_out_b       += src_pix_ptr[B];
856                     sum_out_a       += src_pix_ptr[A];
857                 }
858                 for(i = 1; i <= rx; i++)
859                 {
860                     if(i <= wm) src_pix_ptr += Img::pix_width;
861                     stack_pix_ptr = &stack[i + rx];
862                     stack_pix_ptr->r = src_pix_ptr[R];
863                     stack_pix_ptr->g = src_pix_ptr[G];
864                     stack_pix_ptr->b = src_pix_ptr[B];
865                     stack_pix_ptr->a = src_pix_ptr[A];
866                     sum_r           += src_pix_ptr[R] * (rx + 1 - i);
867                     sum_g           += src_pix_ptr[G] * (rx + 1 - i);
868                     sum_b           += src_pix_ptr[B] * (rx + 1 - i);
869                     sum_a           += src_pix_ptr[A] * (rx + 1 - i);
870                     sum_in_r        += src_pix_ptr[R];
871                     sum_in_g        += src_pix_ptr[G];
872                     sum_in_b        += src_pix_ptr[B];
873                     sum_in_a        += src_pix_ptr[A];
874                 }
875 
876                 stack_ptr = rx;
877                 xp = rx;
878                 if(xp > wm) xp = wm;
879                 src_pix_ptr = img.pix_ptr(xp, y);
880                 dst_pix_ptr = img.pix_ptr(0, y);
881                 for(x = 0; x < w; x++)
882                 {
883                     dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
884                     dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
885                     dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
886                     dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
887                     dst_pix_ptr += Img::pix_width;
888 
889                     sum_r -= sum_out_r;
890                     sum_g -= sum_out_g;
891                     sum_b -= sum_out_b;
892                     sum_a -= sum_out_a;
893 
894                     stack_start = stack_ptr + div - rx;
895                     if(stack_start >= div) stack_start -= div;
896                     stack_pix_ptr = &stack[stack_start];
897 
898                     sum_out_r -= stack_pix_ptr->r;
899                     sum_out_g -= stack_pix_ptr->g;
900                     sum_out_b -= stack_pix_ptr->b;
901                     sum_out_a -= stack_pix_ptr->a;
902 
903                     if(xp < wm)
904                     {
905                         src_pix_ptr += Img::pix_width;
906                         ++xp;
907                     }
908 
909                     stack_pix_ptr->r = src_pix_ptr[R];
910                     stack_pix_ptr->g = src_pix_ptr[G];
911                     stack_pix_ptr->b = src_pix_ptr[B];
912                     stack_pix_ptr->a = src_pix_ptr[A];
913 
914                     sum_in_r += src_pix_ptr[R];
915                     sum_in_g += src_pix_ptr[G];
916                     sum_in_b += src_pix_ptr[B];
917                     sum_in_a += src_pix_ptr[A];
918                     sum_r    += sum_in_r;
919                     sum_g    += sum_in_g;
920                     sum_b    += sum_in_b;
921                     sum_a    += sum_in_a;
922 
923                     ++stack_ptr;
924                     if(stack_ptr >= div) stack_ptr = 0;
925                     stack_pix_ptr = &stack[stack_ptr];
926 
927                     sum_out_r += stack_pix_ptr->r;
928                     sum_out_g += stack_pix_ptr->g;
929                     sum_out_b += stack_pix_ptr->b;
930                     sum_out_a += stack_pix_ptr->a;
931                     sum_in_r  -= stack_pix_ptr->r;
932                     sum_in_g  -= stack_pix_ptr->g;
933                     sum_in_b  -= stack_pix_ptr->b;
934                     sum_in_a  -= stack_pix_ptr->a;
935                 }
936             }
937         }
938 
939         if(ry > 0)
940         {
941             if(ry > 254) ry = 254;
942             div = ry * 2 + 1;
943             mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[ry];
944             shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[ry];
945             stack.allocate(div);
946 
947             int stride = img.stride();
948             for(x = 0; x < w; x++)
949             {
950                 sum_r =
951                 sum_g =
952                 sum_b =
953                 sum_a =
954                 sum_in_r =
955                 sum_in_g =
956                 sum_in_b =
957                 sum_in_a =
958                 sum_out_r =
959                 sum_out_g =
960                 sum_out_b =
961                 sum_out_a = 0;
962 
963                 src_pix_ptr = img.pix_ptr(x, 0);
964                 for(i = 0; i <= ry; i++)
965                 {
966                     stack_pix_ptr    = &stack[i];
967                     stack_pix_ptr->r = src_pix_ptr[R];
968                     stack_pix_ptr->g = src_pix_ptr[G];
969                     stack_pix_ptr->b = src_pix_ptr[B];
970                     stack_pix_ptr->a = src_pix_ptr[A];
971                     sum_r           += src_pix_ptr[R] * (i + 1);
972                     sum_g           += src_pix_ptr[G] * (i + 1);
973                     sum_b           += src_pix_ptr[B] * (i + 1);
974                     sum_a           += src_pix_ptr[A] * (i + 1);
975                     sum_out_r       += src_pix_ptr[R];
976                     sum_out_g       += src_pix_ptr[G];
977                     sum_out_b       += src_pix_ptr[B];
978                     sum_out_a       += src_pix_ptr[A];
979                 }
980                 for(i = 1; i <= ry; i++)
981                 {
982                     if(i <= hm) src_pix_ptr += stride;
983                     stack_pix_ptr = &stack[i + ry];
984                     stack_pix_ptr->r = src_pix_ptr[R];
985                     stack_pix_ptr->g = src_pix_ptr[G];
986                     stack_pix_ptr->b = src_pix_ptr[B];
987                     stack_pix_ptr->a = src_pix_ptr[A];
988                     sum_r           += src_pix_ptr[R] * (ry + 1 - i);
989                     sum_g           += src_pix_ptr[G] * (ry + 1 - i);
990                     sum_b           += src_pix_ptr[B] * (ry + 1 - i);
991                     sum_a           += src_pix_ptr[A] * (ry + 1 - i);
992                     sum_in_r        += src_pix_ptr[R];
993                     sum_in_g        += src_pix_ptr[G];
994                     sum_in_b        += src_pix_ptr[B];
995                     sum_in_a        += src_pix_ptr[A];
996                 }
997 
998                 stack_ptr = ry;
999                 yp = ry;
1000                 if(yp > hm) yp = hm;
1001                 src_pix_ptr = img.pix_ptr(x, yp);
1002                 dst_pix_ptr = img.pix_ptr(x, 0);
1003                 for(y = 0; y < h; y++)
1004                 {
1005                     dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
1006                     dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
1007                     dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
1008                     dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
1009                     dst_pix_ptr += stride;
1010 
1011                     sum_r -= sum_out_r;
1012                     sum_g -= sum_out_g;
1013                     sum_b -= sum_out_b;
1014                     sum_a -= sum_out_a;
1015 
1016                     stack_start = stack_ptr + div - ry;
1017                     if(stack_start >= div) stack_start -= div;
1018 
1019                     stack_pix_ptr = &stack[stack_start];
1020                     sum_out_r -= stack_pix_ptr->r;
1021                     sum_out_g -= stack_pix_ptr->g;
1022                     sum_out_b -= stack_pix_ptr->b;
1023                     sum_out_a -= stack_pix_ptr->a;
1024 
1025                     if(yp < hm)
1026                     {
1027                         src_pix_ptr += stride;
1028                         ++yp;
1029                     }
1030 
1031                     stack_pix_ptr->r = src_pix_ptr[R];
1032                     stack_pix_ptr->g = src_pix_ptr[G];
1033                     stack_pix_ptr->b = src_pix_ptr[B];
1034                     stack_pix_ptr->a = src_pix_ptr[A];
1035 
1036                     sum_in_r += src_pix_ptr[R];
1037                     sum_in_g += src_pix_ptr[G];
1038                     sum_in_b += src_pix_ptr[B];
1039                     sum_in_a += src_pix_ptr[A];
1040                     sum_r    += sum_in_r;
1041                     sum_g    += sum_in_g;
1042                     sum_b    += sum_in_b;
1043                     sum_a    += sum_in_a;
1044 
1045                     ++stack_ptr;
1046                     if(stack_ptr >= div) stack_ptr = 0;
1047                     stack_pix_ptr = &stack[stack_ptr];
1048 
1049                     sum_out_r += stack_pix_ptr->r;
1050                     sum_out_g += stack_pix_ptr->g;
1051                     sum_out_b += stack_pix_ptr->b;
1052                     sum_out_a += stack_pix_ptr->a;
1053                     sum_in_r  -= stack_pix_ptr->r;
1054                     sum_in_g  -= stack_pix_ptr->g;
1055                     sum_in_b  -= stack_pix_ptr->b;
1056                     sum_in_a  -= stack_pix_ptr->a;
1057                 }
1058             }
1059         }
1060     }
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         //--------------------------------------------------------------------
blur_x(Img & img,double radius)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         //--------------------------------------------------------------------
blur_y(Img & img,double radius)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         //--------------------------------------------------------------------
blur(Img & img,double radius)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         agg::pod_vector<calculator_type> m_sum1;
1165         agg::pod_vector<calculator_type> m_sum2;
1166         agg::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>
from_pixrecursive_blur_calc_rgba1179         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 
calcrecursive_blur_calc_rgba1187         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>
to_pixrecursive_blur_calc_rgba1203         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>
from_pixrecursive_blur_calc_rgb1223         AGG_INLINE void from_pix(const ColorT& c)
1224         {
1225             r = c.r;
1226             g = c.g;
1227             b = c.b;
1228         }
1229 
calcrecursive_blur_calc_rgb1230         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>
to_pixrecursive_blur_calc_rgb1245         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>
from_pixrecursive_blur_calc_gray1264         AGG_INLINE void from_pix(const ColorT& c)
1265         {
1266             v = c.v;
1267         }
1268 
calcrecursive_blur_calc_gray1269         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>
to_pixrecursive_blur_calc_gray1282         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
1295