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
33namespace 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        //--------------------------------------------------------------------
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    {
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        //--------------------------------------------------------------------
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        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>
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
1295