agg_blur.h 51 KB

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