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