1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
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.
25 //----------------------------------------------------------------------------
27 #ifndef AGG_BLUR_INCLUDED
28 #define AGG_BLUR_INCLUDED
30 #include "agg_array.h"
31 #include "agg_pixfmt_transposer.h"
36 template<class T
> struct stack_blur_tables
38 static int16u
const g_stack_blur8_mul
[255];
39 static int8u
const g_stack_blur8_shr
[255];
42 //------------------------------------------------------------------------
44 int16u
const stack_blur_tables
<T
>::g_stack_blur8_mul
[255] =
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
64 //------------------------------------------------------------------------
66 int8u
const stack_blur_tables
<T
>::g_stack_blur8_shr
[255] =
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
88 //==============================================================stack_blur
89 template<class ColorT
, class CalculatorT
> class stack_blur
92 typedef ColorT color_type
;
93 typedef CalculatorT calculator_type
;
95 //--------------------------------------------------------------------
96 template<class Img
> void blur_x(Img
& img
, unsigned radius
)
98 if(radius
< 1) return;
100 unsigned x
, y
, xp
, i
;
102 unsigned stack_start
;
105 color_type
* stack_pix
;
107 calculator_type sum_in
;
108 calculator_type sum_out
;
110 unsigned w
= img
.width();
111 unsigned h
= img
.height();
113 unsigned div
= radius
* 2 + 1;
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
;
120 if(max_val
<= 255 && radius
< 255)
122 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[radius
];
123 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[radius
];
126 m_buf
.allocate(w
, 128);
127 m_stack
.allocate(div
, 32);
129 for(y
= 0; y
< h
; y
++)
135 pix
= img
.pixel(0, y
);
136 for(i
= 0; i
<= radius
; i
++)
142 for(i
= 1; i
<= radius
; i
++)
144 pix
= img
.pixel((i
> wm
) ? wm
: i
, y
);
145 m_stack
[i
+ radius
] = pix
;
146 sum
.add(pix
, radius
+ 1 - i
);
151 for(x
= 0; x
< w
; x
++)
153 if(mul_sum
) sum
.calc_pix(m_buf
[x
], mul_sum
, shr_sum
);
154 else sum
.calc_pix(m_buf
[x
], div_sum
);
158 stack_start
= stack_ptr
+ div
- radius
;
159 if(stack_start
>= div
) stack_start
-= div
;
160 stack_pix
= &m_stack
[stack_start
];
162 sum_out
.sub(*stack_pix
);
166 pix
= img
.pixel(xp
, y
);
174 if(stack_ptr
>= div
) stack_ptr
= 0;
175 stack_pix
= &m_stack
[stack_ptr
];
177 sum_out
.add(*stack_pix
);
178 sum_in
.sub(*stack_pix
);
180 img
.copy_color_hspan(0, y
, w
, &m_buf
[0]);
184 //--------------------------------------------------------------------
185 template<class Img
> void blur_y(Img
& img
, unsigned radius
)
187 pixfmt_transposer
<Img
> img2(img
);
188 blur_x(img2
, radius
);
191 //--------------------------------------------------------------------
192 template<class Img
> void blur(Img
& img
, unsigned radius
)
195 pixfmt_transposer
<Img
> img2(img
);
196 blur_x(img2
, radius
);
200 pod_vector
<color_type
> m_buf
;
201 pod_vector
<color_type
> m_stack
;
204 //====================================================stack_blur_calc_rgba
205 template<class T
=unsigned> struct stack_blur_calc_rgba
207 typedef T value_type
;
210 AGG_INLINE
void clear()
215 template<class ArgT
> AGG_INLINE
void add(const ArgT
& v
)
223 template<class ArgT
> AGG_INLINE
void add(const ArgT
& v
, unsigned k
)
231 template<class ArgT
> AGG_INLINE
void sub(const ArgT
& v
)
239 template<class ArgT
> AGG_INLINE
void calc_pix(ArgT
& v
, unsigned div
)
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
);
249 AGG_INLINE
void calc_pix(ArgT
& v
, unsigned mul
, unsigned shr
)
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
);
260 //=====================================================stack_blur_calc_rgb
261 template<class T
=unsigned> struct stack_blur_calc_rgb
263 typedef T value_type
;
266 AGG_INLINE
void clear()
271 template<class ArgT
> AGG_INLINE
void add(const ArgT
& v
)
278 template<class ArgT
> AGG_INLINE
void add(const ArgT
& v
, unsigned k
)
285 template<class ArgT
> AGG_INLINE
void sub(const ArgT
& v
)
292 template<class ArgT
> AGG_INLINE
void calc_pix(ArgT
& v
, unsigned div
)
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
);
301 AGG_INLINE
void calc_pix(ArgT
& v
, unsigned mul
, unsigned shr
)
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
);
311 //====================================================stack_blur_calc_gray
312 template<class T
=unsigned> struct stack_blur_calc_gray
314 typedef T value_type
;
317 AGG_INLINE
void clear()
322 template<class ArgT
> AGG_INLINE
void add(const ArgT
& a
)
327 template<class ArgT
> AGG_INLINE
void add(const ArgT
& a
, unsigned k
)
332 template<class ArgT
> AGG_INLINE
void sub(const ArgT
& a
)
337 template<class ArgT
> AGG_INLINE
void calc_pix(ArgT
& a
, unsigned div
)
339 typedef typename
ArgT::value_type value_type
;
340 a
.v
= value_type(v
/ div
);
344 AGG_INLINE
void calc_pix(ArgT
& a
, unsigned mul
, unsigned shr
)
346 typedef typename
ArgT::value_type value_type
;
347 a
.v
= value_type((v
* mul
) >> shr
);
353 //========================================================stack_blur_gray8
355 void stack_blur_gray8(Img
& img
, unsigned rx
, unsigned ry
)
357 unsigned x
, y
, xp
, yp
, i
;
359 unsigned stack_start
;
361 const int8u
* src_pix_ptr
;
369 unsigned w
= img
.width();
370 unsigned h
= img
.height();
378 pod_vector
<int8u
> stack
;
382 if(rx
> 254) rx
= 254;
384 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[rx
];
385 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[rx
];
388 for(y
= 0; y
< h
; y
++)
390 sum
= sum_in
= sum_out
= 0;
392 src_pix_ptr
= img
.pix_ptr(0, y
);
394 for(i
= 0; i
<= rx
; i
++)
397 sum
+= pix
* (i
+ 1);
400 for(i
= 1; i
<= rx
; i
++)
402 if(i
<= wm
) src_pix_ptr
+= Img::pix_step
;
405 sum
+= pix
* (rx
+ 1 - i
);
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
++)
416 *dst_pix_ptr
= (sum
* mul_sum
) >> shr_sum
;
417 dst_pix_ptr
+= Img::pix_step
;
421 stack_start
= stack_ptr
+ div
- rx
;
422 if(stack_start
>= div
) stack_start
-= div
;
423 sum_out
-= stack
[stack_start
];
427 src_pix_ptr
+= Img::pix_step
;
432 stack
[stack_start
] = pix
;
438 if(stack_ptr
>= div
) stack_ptr
= 0;
439 stack_pix
= stack
[stack_ptr
];
441 sum_out
+= stack_pix
;
449 if(ry
> 254) ry
= 254;
451 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[ry
];
452 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[ry
];
455 int stride
= img
.stride();
456 for(x
= 0; x
< w
; x
++)
458 sum
= sum_in
= sum_out
= 0;
460 src_pix_ptr
= img
.pix_ptr(x
, 0);
462 for(i
= 0; i
<= ry
; i
++)
465 sum
+= pix
* (i
+ 1);
468 for(i
= 1; i
<= ry
; i
++)
470 if(i
<= hm
) src_pix_ptr
+= stride
;
473 sum
+= pix
* (ry
+ 1 - i
);
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
++)
484 *dst_pix_ptr
= (sum
* mul_sum
) >> shr_sum
;
485 dst_pix_ptr
+= stride
;
489 stack_start
= stack_ptr
+ div
- ry
;
490 if(stack_start
>= div
) stack_start
-= div
;
491 sum_out
-= stack
[stack_start
];
495 src_pix_ptr
+= stride
;
500 stack
[stack_start
] = pix
;
506 if(stack_ptr
>= div
) stack_ptr
= 0;
507 stack_pix
= stack
[stack_ptr
];
509 sum_out
+= stack_pix
;
518 //========================================================stack_blur_rgb24
520 void stack_blur_rgb24(Img
& img
, unsigned rx
, unsigned ry
)
522 typedef typename
Img::color_type color_type
;
523 typedef typename
Img::order_type order_type
;
531 unsigned x
, y
, xp
, yp
, i
;
533 unsigned stack_start
;
535 const int8u
* src_pix_ptr
;
537 color_type
* stack_pix_ptr
;
549 unsigned w
= img
.width();
550 unsigned h
= img
.height();
558 pod_vector
<color_type
> stack
;
562 if(rx
> 254) rx
= 254;
564 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[rx
];
565 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[rx
];
568 for(y
= 0; y
< h
; y
++)
580 src_pix_ptr
= img
.pix_ptr(0, y
);
581 for(i
= 0; i
<= rx
; i
++)
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
];
594 for(i
= 1; i
<= rx
; i
++)
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
];
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
++)
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
;
625 stack_start
= stack_ptr
+ div
- rx
;
626 if(stack_start
>= div
) stack_start
-= div
;
627 stack_pix_ptr
= &stack
[stack_start
];
629 sum_out_r
-= stack_pix_ptr
->r
;
630 sum_out_g
-= stack_pix_ptr
->g
;
631 sum_out_b
-= stack_pix_ptr
->b
;
635 src_pix_ptr
+= Img::pix_width
;
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
];
643 sum_in_r
+= src_pix_ptr
[R
];
644 sum_in_g
+= src_pix_ptr
[G
];
645 sum_in_b
+= src_pix_ptr
[B
];
651 if(stack_ptr
>= div
) stack_ptr
= 0;
652 stack_pix_ptr
= &stack
[stack_ptr
];
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
;
666 if(ry
> 254) ry
= 254;
668 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[ry
];
669 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[ry
];
672 int stride
= img
.stride();
673 for(x
= 0; x
< w
; x
++)
685 src_pix_ptr
= img
.pix_ptr(x
, 0);
686 for(i
= 0; i
<= ry
; i
++)
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
];
699 for(i
= 1; i
<= ry
; i
++)
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
];
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
++)
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
;
730 stack_start
= stack_ptr
+ div
- ry
;
731 if(stack_start
>= div
) stack_start
-= div
;
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
;
740 src_pix_ptr
+= stride
;
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
];
748 sum_in_r
+= src_pix_ptr
[R
];
749 sum_in_g
+= src_pix_ptr
[G
];
750 sum_in_b
+= src_pix_ptr
[B
];
756 if(stack_ptr
>= div
) stack_ptr
= 0;
757 stack_pix_ptr
= &stack
[stack_ptr
];
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
;
772 //=======================================================stack_blur_rgba32
774 void stack_blur_rgba32(Img
& img
, unsigned rx
, unsigned ry
)
776 typedef typename
Img::color_type color_type
;
777 typedef typename
Img::order_type order_type
;
786 unsigned x
, y
, xp
, yp
, i
;
788 unsigned stack_start
;
790 const int8u
* src_pix_ptr
;
792 color_type
* stack_pix_ptr
;
807 unsigned w
= img
.width();
808 unsigned h
= img
.height();
816 pod_vector
<color_type
> stack
;
820 if(rx
> 254) rx
= 254;
822 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[rx
];
823 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[rx
];
826 for(y
= 0; y
< h
; y
++)
841 src_pix_ptr
= img
.pix_ptr(0, y
);
842 for(i
= 0; i
<= rx
; i
++)
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
];
858 for(i
= 1; i
<= rx
; i
++)
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
];
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
++)
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
;
894 stack_start
= stack_ptr
+ div
- rx
;
895 if(stack_start
>= div
) stack_start
-= div
;
896 stack_pix_ptr
= &stack
[stack_start
];
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
;
905 src_pix_ptr
+= Img::pix_width
;
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
];
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
];
924 if(stack_ptr
>= div
) stack_ptr
= 0;
925 stack_pix_ptr
= &stack
[stack_ptr
];
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
;
941 if(ry
> 254) ry
= 254;
943 mul_sum
= stack_blur_tables
<int>::g_stack_blur8_mul
[ry
];
944 shr_sum
= stack_blur_tables
<int>::g_stack_blur8_shr
[ry
];
947 int stride
= img
.stride();
948 for(x
= 0; x
< w
; x
++)
963 src_pix_ptr
= img
.pix_ptr(x
, 0);
964 for(i
= 0; i
<= ry
; i
++)
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
];
980 for(i
= 1; i
<= ry
; i
++)
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
];
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
++)
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
;
1016 stack_start
= stack_ptr
+ div
- ry
;
1017 if(stack_start
>= div
) stack_start
-= div
;
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
;
1027 src_pix_ptr
+= stride
;
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
];
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
];
1046 if(stack_ptr
>= div
) stack_ptr
= 0;
1047 stack_pix_ptr
= &stack
[stack_ptr
];
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
;
1064 //===========================================================recursive_blur
1065 template<class ColorT
, class CalculatorT
> class recursive_blur
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
;
1073 //--------------------------------------------------------------------
1074 template<class Img
> void blur_x(Img
& img
, double radius
)
1076 if(radius
< 0.62) return;
1077 if(img
.width() < 3) return;
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);
1084 calc_type q2
= calc_type(q
* q
);
1085 calc_type q3
= calc_type(q2
* q
);
1087 calc_type b0
= calc_type(1.0 / (1.578250 +
1092 calc_type b1
= calc_type( 2.44413 * q
+
1096 calc_type b2
= calc_type(-1.42810 * q2
+
1099 calc_type b3
= calc_type(0.422205 * q3
);
1101 calc_type b
= calc_type(1 - (b1
+ b2
+ b3
) * b0
);
1107 int w
= img
.width();
1108 int h
= img
.height();
1116 for(y
= 0; y
< h
; y
++)
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]);
1126 for(x
= 3; x
< w
; ++x
)
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]);
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]);
1139 for(x
= wm
-3; x
>= 0; --x
)
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
]);
1144 img
.copy_color_hspan(0, y
, w
, &m_buf
[0]);
1148 //--------------------------------------------------------------------
1149 template<class Img
> void blur_y(Img
& img
, double radius
)
1151 pixfmt_transposer
<Img
> img2(img
);
1152 blur_x(img2
, radius
);
1155 //--------------------------------------------------------------------
1156 template<class Img
> void blur(Img
& img
, double radius
)
1158 blur_x(img
, radius
);
1159 pixfmt_transposer
<Img
> img2(img
);
1160 blur_x(img2
, radius
);
1164 agg::pod_vector
<calculator_type
> m_sum1
;
1165 agg::pod_vector
<calculator_type
> m_sum2
;
1166 agg::pod_vector
<color_type
> m_buf
;
1170 //=================================================recursive_blur_calc_rgba
1171 template<class T
=double> struct recursive_blur_calc_rgba
1173 typedef T value_type
;
1174 typedef recursive_blur_calc_rgba
<T
> self_type
;
1178 template<class ColorT
>
1179 AGG_INLINE
void from_pix(const ColorT
& c
)
1187 AGG_INLINE
void calc(value_type b1
,
1191 const self_type
& c1
,
1192 const self_type
& c2
,
1193 const self_type
& c3
,
1194 const self_type
& c4
)
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
;
1202 template<class ColorT
>
1203 AGG_INLINE
void to_pix(ColorT
& c
) const
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
);
1214 //=================================================recursive_blur_calc_rgb
1215 template<class T
=double> struct recursive_blur_calc_rgb
1217 typedef T value_type
;
1218 typedef recursive_blur_calc_rgb
<T
> self_type
;
1222 template<class ColorT
>
1223 AGG_INLINE
void from_pix(const ColorT
& c
)
1230 AGG_INLINE
void calc(value_type b1
,
1234 const self_type
& c1
,
1235 const self_type
& c2
,
1236 const self_type
& c3
,
1237 const self_type
& c4
)
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
;
1244 template<class ColorT
>
1245 AGG_INLINE
void to_pix(ColorT
& c
) const
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
);
1255 //================================================recursive_blur_calc_gray
1256 template<class T
=double> struct recursive_blur_calc_gray
1258 typedef T value_type
;
1259 typedef recursive_blur_calc_gray
<T
> self_type
;
1263 template<class ColorT
>
1264 AGG_INLINE
void from_pix(const ColorT
& c
)
1269 AGG_INLINE
void calc(value_type b1
,
1273 const self_type
& c1
,
1274 const self_type
& c2
,
1275 const self_type
& c3
,
1276 const self_type
& c4
)
1278 v
= b1
*c1
.v
+ b2
*c2
.v
+ b3
*c3
.v
+ b4
*c4
.v
;
1281 template<class ColorT
>
1282 AGG_INLINE
void to_pix(ColorT
& c
) const
1284 typedef typename
ColorT::value_type cv_type
;
1285 c
.v
= (cv_type
)uround(v
);