Anti-Grain Geometry Tutorial
agg_blur.h
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 <cstring>
31 #include <cmath>
32 #include "agg_array.h"
33 #include "agg_pixfmt_base.h"
34 #include "agg_pixfmt_transposer.h"
35 
36 namespace agg
37 {
38 
39  template<class T> struct stack_blur_tables
40  {
41  static int16u const g_stack_blur8_mul[255];
42  static int8u const g_stack_blur8_shr[255];
43  };
44 
45  //------------------------------------------------------------------------
46  template<class T>
47  int16u const stack_blur_tables<T>::g_stack_blur8_mul[255] =
48  {
49  512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
50  454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
51  482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
52  437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
53  497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
54  320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
55  446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
56  329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
57  505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
58  399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
59  324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
60  268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
61  451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
62  385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
63  332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
64  289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
65  };
66 
67  //------------------------------------------------------------------------
68  template<class T>
69  int8u const stack_blur_tables<T>::g_stack_blur8_shr[255] =
70  {
71  9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
72  17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
73  19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
74  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
75  21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
76  21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
77  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
78  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
79  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
80  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
81  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
82  23, 23, 23, 23, 23, 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, 24,
84  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
85  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
86  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
87  };
88 
89 
90 
91  //==============================================================stack_blur
92  template<class ColorT, class CalculatorT> class stack_blur
93  {
94  public:
95  typedef ColorT color_type;
96  typedef CalculatorT calculator_type;
97 
98  //--------------------------------------------------------------------
99  template<class Img> void blur_x(Img& img, unsigned radius)
100  {
101  if(radius < 1) return;
102 
103  unsigned x, y, xp, i;
104  unsigned stack_ptr;
105  unsigned stack_start;
106 
107  color_type pix;
108  color_type* stack_pix;
109  calculator_type sum;
110  calculator_type sum_in;
111  calculator_type sum_out;
112 
113  unsigned w = img.width();
114  unsigned h = img.height();
115  unsigned wm = w - 1;
116  unsigned div = radius * 2 + 1;
117 
118  unsigned div_sum = (radius + 1) * (radius + 1);
119  unsigned mul_sum = 0;
120  unsigned shr_sum = 0;
121  unsigned max_val = color_type::base_mask;
122 
123  if(max_val <= 255 && radius < 255)
124  {
127  }
128 
129  m_buf.allocate(w, 128);
130  m_stack.allocate(div, 32);
131 
132  for(y = 0; y < h; y++)
133  {
134  sum.clear();
135  sum_in.clear();
136  sum_out.clear();
137 
138  pix = img.pixel(0, y);
139  for(i = 0; i <= radius; i++)
140  {
141  m_stack[i] = pix;
142  sum.add(pix, i + 1);
143  sum_out.add(pix);
144  }
145  for(i = 1; i <= radius; i++)
146  {
147  pix = img.pixel((i > wm) ? wm : i, y);
148  m_stack[i + radius] = pix;
149  sum.add(pix, radius + 1 - i);
150  sum_in.add(pix);
151  }
152 
153  stack_ptr = radius;
154  for(x = 0; x < w; x++)
155  {
156  if(mul_sum) sum.calc_pix(m_buf[x], mul_sum, shr_sum);
157  else sum.calc_pix(m_buf[x], div_sum);
158 
159  sum.sub(sum_out);
160 
161  stack_start = stack_ptr + div - radius;
162  if(stack_start >= div) stack_start -= div;
163  stack_pix = &m_stack[stack_start];
164 
165  sum_out.sub(*stack_pix);
166 
167  xp = x + radius + 1;
168  if(xp > wm) xp = wm;
169  pix = img.pixel(xp, y);
170 
171  *stack_pix = pix;
172 
173  sum_in.add(pix);
174  sum.add(sum_in);
175 
176  ++stack_ptr;
177  if(stack_ptr >= div) stack_ptr = 0;
178  stack_pix = &m_stack[stack_ptr];
179 
180  sum_out.add(*stack_pix);
181  sum_in.sub(*stack_pix);
182  }
183  img.copy_color_hspan(0, y, w, &m_buf[0]);
184  }
185  }
186 
187  //--------------------------------------------------------------------
188  template<class Img> void blur_y(Img& img, unsigned radius)
189  {
190  pixfmt_transposer<Img> img2(img);
191  blur_x(img2, radius);
192  }
193 
194  //--------------------------------------------------------------------
195  template<class Img> void blur(Img& img, unsigned radius)
196  {
197  blur_x(img, radius);
198  pixfmt_transposer<Img> img2(img);
199  blur_x(img2, radius);
200  }
201 
202  private:
204  pod_vector<color_type> m_stack;
205  };
206 
207  //====================================================stack_blur_calc_rgba
208  template<class T=unsigned> struct stack_blur_calc_rgba
209  {
210  typedef T value_type;
211  value_type r,g,b,a;
212 
213  AGG_INLINE void clear()
214  {
215  r = g = b = a = 0;
216  }
217 
218  template<class ArgT> AGG_INLINE void add(const ArgT& v)
219  {
220  r += v.r;
221  g += v.g;
222  b += v.b;
223  a += v.a;
224  }
225 
226  template<class ArgT> AGG_INLINE void add(const ArgT& v, unsigned k)
227  {
228  r += v.r * k;
229  g += v.g * k;
230  b += v.b * k;
231  a += v.a * k;
232  }
233 
234  template<class ArgT> AGG_INLINE void sub(const ArgT& v)
235  {
236  r -= v.r;
237  g -= v.g;
238  b -= v.b;
239  a -= v.a;
240  }
241 
242  template<class ArgT> AGG_INLINE void calc_pix(ArgT& v, unsigned div)
243  {
244  typedef typename ArgT::value_type value_type;
245  v.r = value_type(r / div);
246  v.g = value_type(g / div);
247  v.b = value_type(b / div);
248  v.a = value_type(a / div);
249  }
250 
251  template<class ArgT>
252  AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr)
253  {
254  typedef typename ArgT::value_type value_type;
255  v.r = value_type((r * mul) >> shr);
256  v.g = value_type((g * mul) >> shr);
257  v.b = value_type((b * mul) >> shr);
258  v.a = value_type((a * mul) >> shr);
259  }
260  };
261 
262 
263  //=====================================================stack_blur_calc_rgb
264  template<class T=unsigned> struct stack_blur_calc_rgb
265  {
266  typedef T value_type;
267  value_type r,g,b;
268 
269  AGG_INLINE void clear()
270  {
271  r = g = b = 0;
272  }
273 
274  template<class ArgT> AGG_INLINE void add(const ArgT& v)
275  {
276  r += v.r;
277  g += v.g;
278  b += v.b;
279  }
280 
281  template<class ArgT> AGG_INLINE void add(const ArgT& v, unsigned k)
282  {
283  r += v.r * k;
284  g += v.g * k;
285  b += v.b * k;
286  }
287 
288  template<class ArgT> AGG_INLINE void sub(const ArgT& v)
289  {
290  r -= v.r;
291  g -= v.g;
292  b -= v.b;
293  }
294 
295  template<class ArgT> AGG_INLINE void calc_pix(ArgT& v, unsigned div)
296  {
297  typedef typename ArgT::value_type value_type;
298  v.r = value_type(r / div);
299  v.g = value_type(g / div);
300  v.b = value_type(b / div);
301  }
302 
303  template<class ArgT>
304  AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr)
305  {
306  typedef typename ArgT::value_type value_type;
307  v.r = value_type((r * mul) >> shr);
308  v.g = value_type((g * mul) >> shr);
309  v.b = value_type((b * mul) >> shr);
310  }
311  };
312 
313 
314  //====================================================stack_blur_calc_gray
315  template<class T=unsigned> struct stack_blur_calc_gray
316  {
317  typedef T value_type;
318  value_type v;
319 
320  AGG_INLINE void clear()
321  {
322  v = 0;
323  }
324 
325  template<class ArgT> AGG_INLINE void add(const ArgT& a)
326  {
327  v += a.v;
328  }
329 
330  template<class ArgT> AGG_INLINE void add(const ArgT& a, unsigned k)
331  {
332  v += a.v * k;
333  }
334 
335  template<class ArgT> AGG_INLINE void sub(const ArgT& a)
336  {
337  v -= a.v;
338  }
339 
340  template<class ArgT> AGG_INLINE void calc_pix(ArgT& a, unsigned div)
341  {
342  typedef typename ArgT::value_type value_type;
343  a.v = value_type(v / div);
344  }
345 
346  template<class ArgT>
347  AGG_INLINE void calc_pix(ArgT& a, unsigned mul, unsigned shr)
348  {
349  typedef typename ArgT::value_type value_type;
350  a.v = value_type((v * mul) >> shr);
351  }
352  };
353 
354 
355 
356  //========================================================stack_blur_gray8
357  template<class Img>
358  void stack_blur_gray8(Img& img, unsigned rx, unsigned ry)
359  {
360  unsigned x, y, xp, yp, i;
361  unsigned stack_ptr;
362  unsigned stack_start;
363 
364  const int8u* src_pix_ptr;
365  int8u* dst_pix_ptr;
366  unsigned pix;
367  unsigned stack_pix;
368  unsigned sum;
369  unsigned sum_in;
370  unsigned sum_out;
371 
372  unsigned w = img.width();
373  unsigned h = img.height();
374  unsigned wm = w - 1;
375  unsigned hm = h - 1;
376 
377  unsigned div;
378  unsigned mul_sum;
379  unsigned shr_sum;
380 
381  pod_vector<int8u> stack;
382 
383  if(rx > 0)
384  {
385  if(rx > 254) rx = 254;
386  div = rx * 2 + 1;
389  stack.allocate(div);
390 
391  for(y = 0; y < h; y++)
392  {
393  sum = sum_in = sum_out = 0;
394 
395  src_pix_ptr = img.pix_ptr(0, y);
396  pix = *src_pix_ptr;
397  for(i = 0; i <= rx; i++)
398  {
399  stack[i] = pix;
400  sum += pix * (i + 1);
401  sum_out += pix;
402  }
403  for(i = 1; i <= rx; i++)
404  {
405  if(i <= wm) src_pix_ptr += Img::pix_width;
406  pix = *src_pix_ptr;
407  stack[i + rx] = pix;
408  sum += pix * (rx + 1 - i);
409  sum_in += pix;
410  }
411 
412  stack_ptr = rx;
413  xp = rx;
414  if(xp > wm) xp = wm;
415  src_pix_ptr = img.pix_ptr(xp, y);
416  dst_pix_ptr = img.pix_ptr(0, y);
417  for(x = 0; x < w; x++)
418  {
419  *dst_pix_ptr = (sum * mul_sum) >> shr_sum;
420  dst_pix_ptr += Img::pix_width;
421 
422  sum -= sum_out;
423 
424  stack_start = stack_ptr + div - rx;
425  if(stack_start >= div) stack_start -= div;
426  sum_out -= stack[stack_start];
427 
428  if(xp < wm)
429  {
430  src_pix_ptr += Img::pix_width;
431  pix = *src_pix_ptr;
432  ++xp;
433  }
434 
435  stack[stack_start] = pix;
436 
437  sum_in += pix;
438  sum += sum_in;
439 
440  ++stack_ptr;
441  if(stack_ptr >= div) stack_ptr = 0;
442  stack_pix = stack[stack_ptr];
443 
444  sum_out += stack_pix;
445  sum_in -= stack_pix;
446  }
447  }
448  }
449 
450  if(ry > 0)
451  {
452  if(ry > 254) ry = 254;
453  div = ry * 2 + 1;
456  stack.allocate(div);
457 
458  int stride = img.stride();
459  for(x = 0; x < w; x++)
460  {
461  sum = sum_in = sum_out = 0;
462 
463  src_pix_ptr = img.pix_ptr(x, 0);
464  pix = *src_pix_ptr;
465  for(i = 0; i <= ry; i++)
466  {
467  stack[i] = pix;
468  sum += pix * (i + 1);
469  sum_out += pix;
470  }
471  for(i = 1; i <= ry; i++)
472  {
473  if(i <= hm) src_pix_ptr += stride;
474  pix = *src_pix_ptr;
475  stack[i + ry] = pix;
476  sum += pix * (ry + 1 - i);
477  sum_in += pix;
478  }
479 
480  stack_ptr = ry;
481  yp = ry;
482  if(yp > hm) yp = hm;
483  src_pix_ptr = img.pix_ptr(x, yp);
484  dst_pix_ptr = img.pix_ptr(x, 0);
485  for(y = 0; y < h; y++)
486  {
487  *dst_pix_ptr = (sum * mul_sum) >> shr_sum;
488  dst_pix_ptr += stride;
489 
490  sum -= sum_out;
491 
492  stack_start = stack_ptr + div - ry;
493  if(stack_start >= div) stack_start -= div;
494  sum_out -= stack[stack_start];
495 
496  if(yp < hm)
497  {
498  src_pix_ptr += stride;
499  pix = *src_pix_ptr;
500  ++yp;
501  }
502 
503  stack[stack_start] = pix;
504 
505  sum_in += pix;
506  sum += sum_in;
507 
508  ++stack_ptr;
509  if(stack_ptr >= div) stack_ptr = 0;
510  stack_pix = stack[stack_ptr];
511 
512  sum_out += stack_pix;
513  sum_in -= stack_pix;
514  }
515  }
516  }
517  }
518 
519 
520 
521  //========================================================stack_blur_rgb24
522  template<class Img>
523  void stack_blur_rgb24(Img& img, unsigned rx, unsigned ry)
524  {
525  typedef typename Img::color_type color_type;
526  typedef typename Img::order_type order_type;
527  enum order_e
528  {
529  R = order_type::R,
530  G = order_type::G,
531  B = order_type::B
532  };
533 
534  unsigned x, y, xp, yp, i;
535  unsigned stack_ptr;
536  unsigned stack_start;
537 
538  const int8u* src_pix_ptr;
539  int8u* dst_pix_ptr;
540  color_type* stack_pix_ptr;
541 
542  unsigned sum_r;
543  unsigned sum_g;
544  unsigned sum_b;
545  unsigned sum_in_r;
546  unsigned sum_in_g;
547  unsigned sum_in_b;
548  unsigned sum_out_r;
549  unsigned sum_out_g;
550  unsigned sum_out_b;
551 
552  unsigned w = img.width();
553  unsigned h = img.height();
554  unsigned wm = w - 1;
555  unsigned hm = h - 1;
556 
557  unsigned div;
558  unsigned mul_sum;
559  unsigned shr_sum;
560 
562 
563  if(rx > 0)
564  {
565  if(rx > 254) rx = 254;
566  div = rx * 2 + 1;
569  stack.allocate(div);
570 
571  for(y = 0; y < h; y++)
572  {
573  sum_r =
574  sum_g =
575  sum_b =
576  sum_in_r =
577  sum_in_g =
578  sum_in_b =
579  sum_out_r =
580  sum_out_g =
581  sum_out_b = 0;
582 
583  src_pix_ptr = img.pix_ptr(0, y);
584  for(i = 0; i <= rx; i++)
585  {
586  stack_pix_ptr = &stack[i];
587  stack_pix_ptr->r = src_pix_ptr[R];
588  stack_pix_ptr->g = src_pix_ptr[G];
589  stack_pix_ptr->b = src_pix_ptr[B];
590  sum_r += src_pix_ptr[R] * (i + 1);
591  sum_g += src_pix_ptr[G] * (i + 1);
592  sum_b += src_pix_ptr[B] * (i + 1);
593  sum_out_r += src_pix_ptr[R];
594  sum_out_g += src_pix_ptr[G];
595  sum_out_b += src_pix_ptr[B];
596  }
597  for(i = 1; i <= rx; i++)
598  {
599  if(i <= wm) src_pix_ptr += Img::pix_width;
600  stack_pix_ptr = &stack[i + rx];
601  stack_pix_ptr->r = src_pix_ptr[R];
602  stack_pix_ptr->g = src_pix_ptr[G];
603  stack_pix_ptr->b = src_pix_ptr[B];
604  sum_r += src_pix_ptr[R] * (rx + 1 - i);
605  sum_g += src_pix_ptr[G] * (rx + 1 - i);
606  sum_b += src_pix_ptr[B] * (rx + 1 - i);
607  sum_in_r += src_pix_ptr[R];
608  sum_in_g += src_pix_ptr[G];
609  sum_in_b += src_pix_ptr[B];
610  }
611 
612  stack_ptr = rx;
613  xp = rx;
614  if(xp > wm) xp = wm;
615  src_pix_ptr = img.pix_ptr(xp, y);
616  dst_pix_ptr = img.pix_ptr(0, y);
617  for(x = 0; x < w; x++)
618  {
619  dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
620  dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
621  dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
622  dst_pix_ptr += Img::pix_width;
623 
624  sum_r -= sum_out_r;
625  sum_g -= sum_out_g;
626  sum_b -= sum_out_b;
627 
628  stack_start = stack_ptr + div - rx;
629  if(stack_start >= div) stack_start -= div;
630  stack_pix_ptr = &stack[stack_start];
631 
632  sum_out_r -= stack_pix_ptr->r;
633  sum_out_g -= stack_pix_ptr->g;
634  sum_out_b -= stack_pix_ptr->b;
635 
636  if(xp < wm)
637  {
638  src_pix_ptr += Img::pix_width;
639  ++xp;
640  }
641 
642  stack_pix_ptr->r = src_pix_ptr[R];
643  stack_pix_ptr->g = src_pix_ptr[G];
644  stack_pix_ptr->b = src_pix_ptr[B];
645 
646  sum_in_r += src_pix_ptr[R];
647  sum_in_g += src_pix_ptr[G];
648  sum_in_b += src_pix_ptr[B];
649  sum_r += sum_in_r;
650  sum_g += sum_in_g;
651  sum_b += sum_in_b;
652 
653  ++stack_ptr;
654  if(stack_ptr >= div) stack_ptr = 0;
655  stack_pix_ptr = &stack[stack_ptr];
656 
657  sum_out_r += stack_pix_ptr->r;
658  sum_out_g += stack_pix_ptr->g;
659  sum_out_b += stack_pix_ptr->b;
660  sum_in_r -= stack_pix_ptr->r;
661  sum_in_g -= stack_pix_ptr->g;
662  sum_in_b -= stack_pix_ptr->b;
663  }
664  }
665  }
666 
667  if(ry > 0)
668  {
669  if(ry > 254) ry = 254;
670  div = ry * 2 + 1;
673  stack.allocate(div);
674 
675  int stride = img.stride();
676  for(x = 0; x < w; x++)
677  {
678  sum_r =
679  sum_g =
680  sum_b =
681  sum_in_r =
682  sum_in_g =
683  sum_in_b =
684  sum_out_r =
685  sum_out_g =
686  sum_out_b = 0;
687 
688  src_pix_ptr = img.pix_ptr(x, 0);
689  for(i = 0; i <= ry; i++)
690  {
691  stack_pix_ptr = &stack[i];
692  stack_pix_ptr->r = src_pix_ptr[R];
693  stack_pix_ptr->g = src_pix_ptr[G];
694  stack_pix_ptr->b = src_pix_ptr[B];
695  sum_r += src_pix_ptr[R] * (i + 1);
696  sum_g += src_pix_ptr[G] * (i + 1);
697  sum_b += src_pix_ptr[B] * (i + 1);
698  sum_out_r += src_pix_ptr[R];
699  sum_out_g += src_pix_ptr[G];
700  sum_out_b += src_pix_ptr[B];
701  }
702  for(i = 1; i <= ry; i++)
703  {
704  if(i <= hm) src_pix_ptr += stride;
705  stack_pix_ptr = &stack[i + ry];
706  stack_pix_ptr->r = src_pix_ptr[R];
707  stack_pix_ptr->g = src_pix_ptr[G];
708  stack_pix_ptr->b = src_pix_ptr[B];
709  sum_r += src_pix_ptr[R] * (ry + 1 - i);
710  sum_g += src_pix_ptr[G] * (ry + 1 - i);
711  sum_b += src_pix_ptr[B] * (ry + 1 - i);
712  sum_in_r += src_pix_ptr[R];
713  sum_in_g += src_pix_ptr[G];
714  sum_in_b += src_pix_ptr[B];
715  }
716 
717  stack_ptr = ry;
718  yp = ry;
719  if(yp > hm) yp = hm;
720  src_pix_ptr = img.pix_ptr(x, yp);
721  dst_pix_ptr = img.pix_ptr(x, 0);
722  for(y = 0; y < h; y++)
723  {
724  dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
725  dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
726  dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
727  dst_pix_ptr += stride;
728 
729  sum_r -= sum_out_r;
730  sum_g -= sum_out_g;
731  sum_b -= sum_out_b;
732 
733  stack_start = stack_ptr + div - ry;
734  if(stack_start >= div) stack_start -= div;
735 
736  stack_pix_ptr = &stack[stack_start];
737  sum_out_r -= stack_pix_ptr->r;
738  sum_out_g -= stack_pix_ptr->g;
739  sum_out_b -= stack_pix_ptr->b;
740 
741  if(yp < hm)
742  {
743  src_pix_ptr += stride;
744  ++yp;
745  }
746 
747  stack_pix_ptr->r = src_pix_ptr[R];
748  stack_pix_ptr->g = src_pix_ptr[G];
749  stack_pix_ptr->b = src_pix_ptr[B];
750 
751  sum_in_r += src_pix_ptr[R];
752  sum_in_g += src_pix_ptr[G];
753  sum_in_b += src_pix_ptr[B];
754  sum_r += sum_in_r;
755  sum_g += sum_in_g;
756  sum_b += sum_in_b;
757 
758  ++stack_ptr;
759  if(stack_ptr >= div) stack_ptr = 0;
760  stack_pix_ptr = &stack[stack_ptr];
761 
762  sum_out_r += stack_pix_ptr->r;
763  sum_out_g += stack_pix_ptr->g;
764  sum_out_b += stack_pix_ptr->b;
765  sum_in_r -= stack_pix_ptr->r;
766  sum_in_g -= stack_pix_ptr->g;
767  sum_in_b -= stack_pix_ptr->b;
768  }
769  }
770  }
771  }
772 
773 
774 
775  //=======================================================stack_blur_rgba32
776  template<class Img>
777  void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry)
778  {
779  typedef typename Img::color_type color_type;
780  typedef typename Img::order_type order_type;
781  enum order_e
782  {
783  R = order_type::R,
784  G = order_type::G,
785  B = order_type::B,
786  A = order_type::A
787  };
788 
789  unsigned x, y, xp, yp, i;
790  unsigned stack_ptr;
791  unsigned stack_start;
792 
793  const int8u* src_pix_ptr;
794  int8u* dst_pix_ptr;
795  color_type* stack_pix_ptr;
796 
797  unsigned sum_r;
798  unsigned sum_g;
799  unsigned sum_b;
800  unsigned sum_a;
801  unsigned sum_in_r;
802  unsigned sum_in_g;
803  unsigned sum_in_b;
804  unsigned sum_in_a;
805  unsigned sum_out_r;
806  unsigned sum_out_g;
807  unsigned sum_out_b;
808  unsigned sum_out_a;
809 
810  unsigned w = img.width();
811  unsigned h = img.height();
812  unsigned wm = w - 1;
813  unsigned hm = h - 1;
814 
815  unsigned div;
816  unsigned mul_sum;
817  unsigned shr_sum;
818 
820 
821  if(rx > 0)
822  {
823  if(rx > 254) rx = 254;
824  div = rx * 2 + 1;
827  stack.allocate(div);
828 
829  for(y = 0; y < h; y++)
830  {
831  sum_r =
832  sum_g =
833  sum_b =
834  sum_a =
835  sum_in_r =
836  sum_in_g =
837  sum_in_b =
838  sum_in_a =
839  sum_out_r =
840  sum_out_g =
841  sum_out_b =
842  sum_out_a = 0;
843 
844  src_pix_ptr = img.pix_ptr(0, y);
845  for(i = 0; i <= rx; i++)
846  {
847  stack_pix_ptr = &stack[i];
848  stack_pix_ptr->r = src_pix_ptr[R];
849  stack_pix_ptr->g = src_pix_ptr[G];
850  stack_pix_ptr->b = src_pix_ptr[B];
851  stack_pix_ptr->a = src_pix_ptr[A];
852  sum_r += src_pix_ptr[R] * (i + 1);
853  sum_g += src_pix_ptr[G] * (i + 1);
854  sum_b += src_pix_ptr[B] * (i + 1);
855  sum_a += src_pix_ptr[A] * (i + 1);
856  sum_out_r += src_pix_ptr[R];
857  sum_out_g += src_pix_ptr[G];
858  sum_out_b += src_pix_ptr[B];
859  sum_out_a += src_pix_ptr[A];
860  }
861  for(i = 1; i <= rx; i++)
862  {
863  if(i <= wm) src_pix_ptr += Img::pix_width;
864  stack_pix_ptr = &stack[i + rx];
865  stack_pix_ptr->r = src_pix_ptr[R];
866  stack_pix_ptr->g = src_pix_ptr[G];
867  stack_pix_ptr->b = src_pix_ptr[B];
868  stack_pix_ptr->a = src_pix_ptr[A];
869  sum_r += src_pix_ptr[R] * (rx + 1 - i);
870  sum_g += src_pix_ptr[G] * (rx + 1 - i);
871  sum_b += src_pix_ptr[B] * (rx + 1 - i);
872  sum_a += src_pix_ptr[A] * (rx + 1 - i);
873  sum_in_r += src_pix_ptr[R];
874  sum_in_g += src_pix_ptr[G];
875  sum_in_b += src_pix_ptr[B];
876  sum_in_a += src_pix_ptr[A];
877  }
878 
879  stack_ptr = rx;
880  xp = rx;
881  if(xp > wm) xp = wm;
882  src_pix_ptr = img.pix_ptr(xp, y);
883  dst_pix_ptr = img.pix_ptr(0, y);
884  for(x = 0; x < w; x++)
885  {
886  dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
887  dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
888  dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
889  dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
890  dst_pix_ptr += Img::pix_width;
891 
892  sum_r -= sum_out_r;
893  sum_g -= sum_out_g;
894  sum_b -= sum_out_b;
895  sum_a -= sum_out_a;
896 
897  stack_start = stack_ptr + div - rx;
898  if(stack_start >= div) stack_start -= div;
899  stack_pix_ptr = &stack[stack_start];
900 
901  sum_out_r -= stack_pix_ptr->r;
902  sum_out_g -= stack_pix_ptr->g;
903  sum_out_b -= stack_pix_ptr->b;
904  sum_out_a -= stack_pix_ptr->a;
905 
906  if(xp < wm)
907  {
908  src_pix_ptr += Img::pix_width;
909  ++xp;
910  }
911 
912  stack_pix_ptr->r = src_pix_ptr[R];
913  stack_pix_ptr->g = src_pix_ptr[G];
914  stack_pix_ptr->b = src_pix_ptr[B];
915  stack_pix_ptr->a = src_pix_ptr[A];
916 
917  sum_in_r += src_pix_ptr[R];
918  sum_in_g += src_pix_ptr[G];
919  sum_in_b += src_pix_ptr[B];
920  sum_in_a += src_pix_ptr[A];
921  sum_r += sum_in_r;
922  sum_g += sum_in_g;
923  sum_b += sum_in_b;
924  sum_a += sum_in_a;
925 
926  ++stack_ptr;
927  if(stack_ptr >= div) stack_ptr = 0;
928  stack_pix_ptr = &stack[stack_ptr];
929 
930  sum_out_r += stack_pix_ptr->r;
931  sum_out_g += stack_pix_ptr->g;
932  sum_out_b += stack_pix_ptr->b;
933  sum_out_a += stack_pix_ptr->a;
934  sum_in_r -= stack_pix_ptr->r;
935  sum_in_g -= stack_pix_ptr->g;
936  sum_in_b -= stack_pix_ptr->b;
937  sum_in_a -= stack_pix_ptr->a;
938  }
939  }
940  }
941 
942  if(ry > 0)
943  {
944  if(ry > 254) ry = 254;
945  div = ry * 2 + 1;
948  stack.allocate(div);
949 
950  int stride = img.stride();
951  for(x = 0; x < w; x++)
952  {
953  sum_r =
954  sum_g =
955  sum_b =
956  sum_a =
957  sum_in_r =
958  sum_in_g =
959  sum_in_b =
960  sum_in_a =
961  sum_out_r =
962  sum_out_g =
963  sum_out_b =
964  sum_out_a = 0;
965 
966  src_pix_ptr = img.pix_ptr(x, 0);
967  for(i = 0; i <= ry; i++)
968  {
969  stack_pix_ptr = &stack[i];
970  stack_pix_ptr->r = src_pix_ptr[R];
971  stack_pix_ptr->g = src_pix_ptr[G];
972  stack_pix_ptr->b = src_pix_ptr[B];
973  stack_pix_ptr->a = src_pix_ptr[A];
974  sum_r += src_pix_ptr[R] * (i + 1);
975  sum_g += src_pix_ptr[G] * (i + 1);
976  sum_b += src_pix_ptr[B] * (i + 1);
977  sum_a += src_pix_ptr[A] * (i + 1);
978  sum_out_r += src_pix_ptr[R];
979  sum_out_g += src_pix_ptr[G];
980  sum_out_b += src_pix_ptr[B];
981  sum_out_a += src_pix_ptr[A];
982  }
983  for(i = 1; i <= ry; i++)
984  {
985  if(i <= hm) src_pix_ptr += stride;
986  stack_pix_ptr = &stack[i + ry];
987  stack_pix_ptr->r = src_pix_ptr[R];
988  stack_pix_ptr->g = src_pix_ptr[G];
989  stack_pix_ptr->b = src_pix_ptr[B];
990  stack_pix_ptr->a = src_pix_ptr[A];
991  sum_r += src_pix_ptr[R] * (ry + 1 - i);
992  sum_g += src_pix_ptr[G] * (ry + 1 - i);
993  sum_b += src_pix_ptr[B] * (ry + 1 - i);
994  sum_a += src_pix_ptr[A] * (ry + 1 - i);
995  sum_in_r += src_pix_ptr[R];
996  sum_in_g += src_pix_ptr[G];
997  sum_in_b += src_pix_ptr[B];
998  sum_in_a += src_pix_ptr[A];
999  }
1000 
1001  stack_ptr = ry;
1002  yp = ry;
1003  if(yp > hm) yp = hm;
1004  src_pix_ptr = img.pix_ptr(x, yp);
1005  dst_pix_ptr = img.pix_ptr(x, 0);
1006  for(y = 0; y < h; y++)
1007  {
1008  dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
1009  dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
1010  dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
1011  dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
1012  dst_pix_ptr += stride;
1013 
1014  sum_r -= sum_out_r;
1015  sum_g -= sum_out_g;
1016  sum_b -= sum_out_b;
1017  sum_a -= sum_out_a;
1018 
1019  stack_start = stack_ptr + div - ry;
1020  if(stack_start >= div) stack_start -= div;
1021 
1022  stack_pix_ptr = &stack[stack_start];
1023  sum_out_r -= stack_pix_ptr->r;
1024  sum_out_g -= stack_pix_ptr->g;
1025  sum_out_b -= stack_pix_ptr->b;
1026  sum_out_a -= stack_pix_ptr->a;
1027 
1028  if(yp < hm)
1029  {
1030  src_pix_ptr += stride;
1031  ++yp;
1032  }
1033 
1034  stack_pix_ptr->r = src_pix_ptr[R];
1035  stack_pix_ptr->g = src_pix_ptr[G];
1036  stack_pix_ptr->b = src_pix_ptr[B];
1037  stack_pix_ptr->a = src_pix_ptr[A];
1038 
1039  sum_in_r += src_pix_ptr[R];
1040  sum_in_g += src_pix_ptr[G];
1041  sum_in_b += src_pix_ptr[B];
1042  sum_in_a += src_pix_ptr[A];
1043  sum_r += sum_in_r;
1044  sum_g += sum_in_g;
1045  sum_b += sum_in_b;
1046  sum_a += sum_in_a;
1047 
1048  ++stack_ptr;
1049  if(stack_ptr >= div) stack_ptr = 0;
1050  stack_pix_ptr = &stack[stack_ptr];
1051 
1052  sum_out_r += stack_pix_ptr->r;
1053  sum_out_g += stack_pix_ptr->g;
1054  sum_out_b += stack_pix_ptr->b;
1055  sum_out_a += stack_pix_ptr->a;
1056  sum_in_r -= stack_pix_ptr->r;
1057  sum_in_g -= stack_pix_ptr->g;
1058  sum_in_b -= stack_pix_ptr->b;
1059  sum_in_a -= stack_pix_ptr->a;
1060  }
1061  }
1062  }
1063  }
1064 
1065 
1066 
1067  //===========================================================recursive_blur
1068  template<class ColorT, class CalculatorT> class recursive_blur
1069  {
1070  public:
1071  typedef ColorT color_type;
1072  typedef CalculatorT calculator_type;
1073  typedef typename color_type::value_type value_type;
1074  typedef typename calculator_type::value_type calc_type;
1075 
1076  //--------------------------------------------------------------------
1077  template<class Img> void blur_x(Img& img, double radius)
1078  {
1079  if(radius < 0.62) return;
1080  if(img.width() < 3) return;
1081 
1082  calc_type s = calc_type(radius * 0.5);
1083  calc_type q = calc_type((s < 2.5) ?
1084  3.97156 - 4.14554 * std::sqrt(1 - 0.26891 * s) :
1085  0.98711 * s - 0.96330);
1086 
1087  calc_type q2 = calc_type(q * q);
1088  calc_type q3 = calc_type(q2 * q);
1089 
1090  calc_type b0 = calc_type(1.0 / (1.578250 +
1091  2.444130 * q +
1092  1.428100 * q2 +
1093  0.422205 * q3));
1094 
1095  calc_type b1 = calc_type( 2.44413 * q +
1096  2.85619 * q2 +
1097  1.26661 * q3);
1098 
1099  calc_type b2 = calc_type(-1.42810 * q2 +
1100  -1.26661 * q3);
1101 
1102  calc_type b3 = calc_type(0.422205 * q3);
1103 
1104  calc_type b = calc_type(1 - (b1 + b2 + b3) * b0);
1105 
1106  b1 *= b0;
1107  b2 *= b0;
1108  b3 *= b0;
1109 
1110  int w = img.width();
1111  int h = img.height();
1112  int wm = w-1;
1113  int x, y;
1114 
1115  m_sum1.allocate(w);
1116  m_sum2.allocate(w);
1117  m_buf.allocate(w);
1118 
1119  for(y = 0; y < h; y++)
1120  {
1121  calculator_type c;
1122  c.from_pix(img.pixel(0, y));
1123  m_sum1[0].calc(b, b1, b2, b3, c, c, c, c);
1124  c.from_pix(img.pixel(1, y));
1125  m_sum1[1].calc(b, b1, b2, b3, c, m_sum1[0], m_sum1[0], m_sum1[0]);
1126  c.from_pix(img.pixel(2, y));
1127  m_sum1[2].calc(b, b1, b2, b3, c, m_sum1[1], m_sum1[0], m_sum1[0]);
1128 
1129  for(x = 3; x < w; ++x)
1130  {
1131  c.from_pix(img.pixel(x, y));
1132  m_sum1[x].calc(b, b1, b2, b3, c, m_sum1[x-1], m_sum1[x-2], m_sum1[x-3]);
1133  }
1134 
1135  m_sum2[wm ].calc(b, b1, b2, b3, m_sum1[wm ], m_sum1[wm ], m_sum1[wm], m_sum1[wm]);
1136  m_sum2[wm-1].calc(b, b1, b2, b3, m_sum1[wm-1], m_sum2[wm ], m_sum2[wm], m_sum2[wm]);
1137  m_sum2[wm-2].calc(b, b1, b2, b3, m_sum1[wm-2], m_sum2[wm-1], m_sum2[wm], m_sum2[wm]);
1138  m_sum2[wm ].to_pix(m_buf[wm ]);
1139  m_sum2[wm-1].to_pix(m_buf[wm-1]);
1140  m_sum2[wm-2].to_pix(m_buf[wm-2]);
1141 
1142  for(x = wm-3; x >= 0; --x)
1143  {
1144  m_sum2[x].calc(b, b1, b2, b3, m_sum1[x], m_sum2[x+1], m_sum2[x+2], m_sum2[x+3]);
1145  m_sum2[x].to_pix(m_buf[x]);
1146  }
1147  img.copy_color_hspan(0, y, w, &m_buf[0]);
1148  }
1149  }
1150 
1151  //--------------------------------------------------------------------
1152  template<class Img> void blur_y(Img& img, double radius)
1153  {
1154  pixfmt_transposer<Img> img2(img);
1155  blur_x(img2, radius);
1156  }
1157 
1158  //--------------------------------------------------------------------
1159  template<class Img> void blur(Img& img, double radius)
1160  {
1161  blur_x(img, radius);
1162  pixfmt_transposer<Img> img2(img);
1163  blur_x(img2, radius);
1164  }
1165 
1166  private:
1170  };
1171 
1172 
1173  //=================================================recursive_blur_calc_rgba
1174  template<class T=double> struct recursive_blur_calc_rgba
1175  {
1176  typedef T value_type;
1178 
1179  value_type r,g,b,a;
1180 
1181  template<class ColorT>
1182  AGG_INLINE void from_pix(const ColorT& c)
1183  {
1184  r = c.r;
1185  g = c.g;
1186  b = c.b;
1187  a = c.a;
1188  }
1189 
1190  AGG_INLINE void calc(value_type b1,
1191  value_type b2,
1192  value_type b3,
1193  value_type b4,
1194  const self_type& c1,
1195  const self_type& c2,
1196  const self_type& c3,
1197  const self_type& c4)
1198  {
1199  r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r;
1200  g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g;
1201  b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b;
1202  a = b1*c1.a + b2*c2.a + b3*c3.a + b4*c4.a;
1203  }
1204 
1205  template<class ColorT>
1206  AGG_INLINE void to_pix(ColorT& c) const
1207  {
1208  typedef typename ColorT::value_type cv_type;
1209  c.r = cv_type(r);
1210  c.g = cv_type(g);
1211  c.b = cv_type(b);
1212  c.a = cv_type(a);
1213  }
1214  };
1215 
1216 
1217  //=================================================recursive_blur_calc_rgb
1218  template<class T=double> struct recursive_blur_calc_rgb
1219  {
1220  typedef T value_type;
1222 
1223  value_type r,g,b;
1224 
1225  template<class ColorT>
1226  AGG_INLINE void from_pix(const ColorT& c)
1227  {
1228  r = c.r;
1229  g = c.g;
1230  b = c.b;
1231  }
1232 
1233  AGG_INLINE void calc(value_type b1,
1234  value_type b2,
1235  value_type b3,
1236  value_type b4,
1237  const self_type& c1,
1238  const self_type& c2,
1239  const self_type& c3,
1240  const self_type& c4)
1241  {
1242  r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r;
1243  g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g;
1244  b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b;
1245  }
1246 
1247  template<class ColorT>
1248  AGG_INLINE void to_pix(ColorT& c) const
1249  {
1250  typedef typename ColorT::value_type cv_type;
1251  c.r = cv_type(r);
1252  c.g = cv_type(g);
1253  c.b = cv_type(b);
1254  }
1255  };
1256 
1257 
1258  //================================================recursive_blur_calc_gray
1259  template<class T=double> struct recursive_blur_calc_gray
1260  {
1261  typedef T value_type;
1263 
1264  value_type v;
1265 
1266  template<class ColorT>
1267  AGG_INLINE void from_pix(const ColorT& c)
1268  {
1269  v = c.v;
1270  }
1271 
1272  AGG_INLINE void calc(value_type b1,
1273  value_type b2,
1274  value_type b3,
1275  value_type b4,
1276  const self_type& c1,
1277  const self_type& c2,
1278  const self_type& c3,
1279  const self_type& c4)
1280  {
1281  v = b1*c1.v + b2*c2.v + b3*c3.v + b4*c4.v;
1282  }
1283 
1284  template<class ColorT>
1285  AGG_INLINE void to_pix(ColorT& c) const
1286  {
1287  typedef typename ColorT::value_type cv_type;
1288  c.v = cv_type(v);
1289  }
1290  };
1291 
1292  //================================================slight_blur
1293  // Special-purpose filter for applying a Gaussian blur with a radius small enough
1294  // that the blur only affects adjacent pixels. A Gaussian curve with a standard
1295  // deviation of r/2 is used, as per the HTML/CSS spec. At 3 standard deviations,
1296  // the contribution drops to less than 0.005, i.e. less than half a percent,
1297  // therefore the radius can be at least 1.33 before errors become significant.
1298  // This filter is useful for smoothing artifacts caused by detail rendered
1299  // at the pixel scale, e.g. single-pixel lines. Note that the filter should
1300  // only be used with premultiplied pixel formats (or those without alpha).
1301  // See the "line_thickness" example for a demonstration.
1302  template<class PixFmt>
1304  {
1305  public:
1306  typedef typename PixFmt::pixel_type pixel_type;
1307  typedef typename PixFmt::value_type value_type;
1308  typedef typename PixFmt::order_type order_type;
1309 
1310  slight_blur(double r = 1.33)
1311  {
1312  radius(r);
1313  }
1314 
1315  void radius(double r)
1316  {
1317  if (r > 0)
1318  {
1319  // Sample the gaussian curve at 0 and r/2 standard deviations.
1320  // At 3 standard deviations, the response is < 0.005.
1321  double pi = 3.14159;
1322  double n = 2 / r;
1323  m_g0 = 1 / std::sqrt(2 * pi);
1324  m_g1 = m_g0 * exp(-n * n);
1325 
1326  // Normalize.
1327  double sum = m_g0 + 2 * m_g1;
1328  m_g0 /= sum;
1329  m_g1 /= sum;
1330  }
1331  else
1332  {
1333  m_g0 = 1;
1334  m_g1 = 0;
1335  }
1336  }
1337 
1338  void blur(PixFmt& img, rect_i bounds)
1339  {
1340  // Make sure we stay within the image area.
1341  bounds.clip(rect_i(0, 0, img.width() - 1, img.height() - 1));
1342 
1343  int w = bounds.x2 - bounds.x1 + 1;
1344  int h = bounds.y2 - bounds.y1 + 1;
1345 
1346  if (w < 3 || h < 3) return;
1347 
1348  // Allocate 3 rows of buffer space.
1349  m_buf.allocate(w * 3);
1350 
1351  // Set up row pointers
1352  pixel_type * begin = &m_buf[0];
1353  pixel_type * r0 = begin;
1354  pixel_type * r1 = r0 + w;
1355  pixel_type * r2 = r1 + w;
1356  pixel_type * end = r2 + w;
1357 
1358  // Horizontally blur the first two input rows.
1359  calc_row(img, bounds.x1, bounds.y1, w, r0);
1360  std::memcpy(r1, r0, w * sizeof(pixel_type));
1361 
1362  for (int y = 0; ; )
1363  {
1364  // Get pointer to first pixel.
1365  pixel_type* p = img.pix_value_ptr(bounds.x1, bounds.y1 + y, bounds.x1 + w);
1366 
1367  // Horizontally blur the row below.
1368  if (y + 1 < h)
1369  {
1370  calc_row(img, bounds.x1, bounds.y1 + y + 1, w, r2);
1371  }
1372  else
1373  {
1374  std::memcpy(r2, r1, w * sizeof(pixel_type)); // duplicate bottom row
1375  }
1376 
1377  // Combine blurred rows into destination.
1378  for (int x = 0; x < w; ++x)
1379  {
1380  calc_pixel(*r0++, *r1++, *r2++, *p++);
1381  }
1382 
1383  if (++y >= h) break;
1384 
1385  // Wrap bottom row pointer around to top of buffer.
1386  if (r2 == end) r2 = begin;
1387  else if (r1 == end) r1 = begin;
1388  else if (r0 == end) r0 = begin;
1389  }
1390  }
1391 
1392  private:
1393  void calc_row(PixFmt& img, int x, int y, int w, pixel_type* row)
1394  {
1395  const int wm = w - 1;
1396 
1397  pixel_type* p = img.pix_value_ptr(x, y, w);
1398 
1399  pixel_type c[3];
1400  pixel_type* p0 = c;
1401  pixel_type* p1 = c + 1;
1402  pixel_type* p2 = c + 2;
1403  pixel_type* end = c + 3;
1404  *p0 = *p1 = *p;
1405 
1406  for (int x = 0; x < wm; ++x)
1407  {
1408  *p2 = *(p = p->next());
1409 
1410  calc_pixel(*p0++, *p1++, *p2++, *row++);
1411 
1412  if (p0 == end) p0 = c;
1413  else if (p1 == end) p1 = c;
1414  else if (p2 == end) p2 = c;
1415  }
1416 
1417  calc_pixel(*p0, *p1, *p1, *row);
1418  }
1419 
1420  void calc_pixel(
1421  pixel_type const & c1,
1422  pixel_type const & c2,
1423  pixel_type const & c3,
1424  pixel_type & x)
1425  {
1426  calc_pixel(c1, c2, c3, x, PixFmt::pixfmt_category());
1427  }
1428 
1429  void calc_pixel(
1430  pixel_type const & c1,
1431  pixel_type const & c2,
1432  pixel_type const & c3,
1433  pixel_type & x,
1435  {
1436  x.c[0] = calc_value(c1.c[0], c2.c[0], c3.c[0]);
1437  }
1438 
1439  void calc_pixel(
1440  pixel_type const & c1,
1441  pixel_type const & c2,
1442  pixel_type const & c3,
1443  pixel_type & x,
1445  {
1446  enum { R = order_type::R, G = order_type::G, B = order_type::B };
1447  x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]);
1448  x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]);
1449  x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]);
1450  }
1451 
1452  void calc_pixel(
1453  pixel_type const & c1,
1454  pixel_type const & c2,
1455  pixel_type const & c3,
1456  pixel_type & x,
1458  {
1459  enum { R = order_type::R, G = order_type::G, B = order_type::B, A = order_type::A };
1460  x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]);
1461  x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]);
1462  x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]);
1463  x.c[A] = calc_value(c1.c[A], c2.c[A], c3.c[A]);
1464  }
1465 
1466  value_type calc_value(value_type v1, value_type v2, value_type v3)
1467  {
1468  return value_type(m_g1 * v1 + m_g0 * v2 + m_g1 * v3);
1469  }
1470 
1471  double m_g0, m_g1;
1472  pod_vector<pixel_type> m_buf;
1473  };
1474 
1475  // Helper functions for applying blur to a surface without having to create an intermediate object.
1476 
1477  template<class PixFmt>
1478  void apply_slight_blur(PixFmt& img, const rect_i& bounds, double r = 1)
1479  {
1480  if (r > 0) slight_blur<PixFmt>(r).blur(img, bounds);
1481  }
1482 
1483  template<class PixFmt>
1484  void apply_slight_blur(PixFmt& img, double r = 1)
1485  {
1486  if (r > 0) slight_blur<PixFmt>(r).blur(img, rect_i(0, 0, img.width() - 1, img.height() - 1));
1487  }
1488 
1489  template<class PixFmt>
1490  void apply_slight_blur(renderer_base<PixFmt>& img, const rect_i& bounds, double r = 1)
1491  {
1492  if (r > 0) slight_blur<PixFmt>(r).blur(img.ren(), bounds);
1493  }
1494 
1495  template<class PixFmt>
1496  void apply_slight_blur(renderer_base<PixFmt>& img, double r = 1)
1497  {
1498  if (r > 0) slight_blur<PixFmt>(r).blur(img.ren(), img.clip_box());
1499  }
1500 }
1501 
1502 
1503 
1504 
1505 #endif
Definition: agg_arc.cpp:24