Coverage Report

Created: 2026-02-14 06:52

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