Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

floodfill.c 8.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * libpipi Proper image processing implementation library
  3. * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
  4. * 2008 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * All Rights Reserved
  6. *
  7. * $Id$
  8. *
  9. * This library is free software. It comes without any warranty, to
  10. * the extent permitted by applicable law. You can redistribute it
  11. * and/or modify it under the terms of the Do What The Fuck You Want
  12. * To Public License, Version 2, as published by Sam Hocevar. See
  13. * http://sam.zoy.org/wtfpl/COPYING for more details.
  14. */
  15. /*
  16. * floodfill.c: flood fill (4 neighbours) functions
  17. */
  18. #include "config.h"
  19. #include "common.h"
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <math.h>
  24. #include "pipi.h"
  25. #include "pipi_internals.h"
  26. #define STACKSIZE (1<<20)
  27. static void pipi_flood_fill_stack_scanline_u32(pipi_pixels_t *dstp,
  28. int x, int y,
  29. uint32_t new, uint32_t old);
  30. static void pipi_flood_fill_stack_scanline_float(pipi_pixels_t *dstp,
  31. int x, int y,
  32. float nr, float ng, float nb,
  33. float or, float og, float ob);
  34. static int pop (int *x,int *y, int h);
  35. static int push(int x, int y, int h);
  36. static void clear_stack(int h);
  37. static int stack[STACKSIZE];
  38. static int stack_pointer;
  39. static float get_max_color_diff(float r1, float g1, float b1,
  40. float r2, float g2, float b2);
  41. static int validate_pixel_f(float r1, float g1, float b1,
  42. float r2, float g2, float b2);
  43. /*
  44. Stack based flood fill.
  45. Instead of using system stack (calling recursively functions,
  46. which can lead to big problems as this stack is a fixed and small sized one),
  47. we create our own one.
  48. Additionnaly, we use a scanline trick to speed up the whole thing.
  49. This method is more or less the one described at
  50. http://student.kuleuven.be/~m0216922/CG/floodfill.html
  51. */
  52. /* Public function */
  53. int pipi_flood_fill(pipi_image_t *src,
  54. int px, int py,
  55. float r, float g, float b)
  56. {
  57. pipi_image_t *dst = src;
  58. pipi_pixels_t *dstp;
  59. int w, h;
  60. if(!src) return -1;
  61. w = src->w;
  62. h = src->h;
  63. if((px >= src->w) || (py >= src->h) ||
  64. (px < 0) || (py < 0)) return -1;
  65. if(src->last_modified == PIPI_PIXELS_RGBA32) {
  66. uint32_t *dstdata;
  67. unsigned char nr, ng, nb;
  68. /* Get ARGB32 pointer */
  69. dstp = pipi_getpixels(dst, PIPI_PIXELS_RGBA32);
  70. dstdata = (uint32_t *)dstp->pixels;
  71. nr = r*255.0f;
  72. ng = g*255.0f;
  73. nb = b*255.0f;
  74. dstp->w = w;
  75. dstp->h = h;
  76. pipi_flood_fill_stack_scanline_u32(dstp, px, py, (nr<<16)|(ng<<8)|(nb), dstdata[px+py*w]);
  77. } else {
  78. int gray = (dst->last_modified == PIPI_PIXELS_Y_F);
  79. float *dstdata;
  80. float or, og, ob;
  81. dstp = gray ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
  82. : pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
  83. dstdata = (float *)dstp->pixels;
  84. or = dstdata[(px+py*w)*4];
  85. og = dstdata[(px+py*w)*4 + 1];
  86. ob = dstdata[(px+py*w)*4 + 2];
  87. dstp->w = w;
  88. dstp->h = h;
  89. pipi_flood_fill_stack_scanline_float(dstp, px, py, r, g, b, or, og, ob);
  90. }
  91. return 0;
  92. }
  93. /* ARGB32 */
  94. void pipi_flood_fill_stack_scanline_u32(pipi_pixels_t *dstp,
  95. int x, int y,
  96. uint32_t new, uint32_t old)
  97. {
  98. if(new==old) return;
  99. clear_stack(dstp->h);
  100. int yt;
  101. int left, right;
  102. uint32_t *dstdata = (uint32_t *)dstp->pixels;
  103. if(!push(x, y, dstp->h)) return;
  104. while(pop(&x, &y, dstp->h))
  105. {
  106. yt = y;
  107. while(yt >= 0 && (dstdata[x+yt*dstp->w] == old)) {
  108. yt--;
  109. }
  110. yt++;
  111. left = right = 0;
  112. while(yt < dstp->h && (dstdata[x+yt*dstp->w] == old))
  113. {
  114. uint32_t *cur_line = &dstdata[(yt*dstp->w)];
  115. int xp1 = (x+1);
  116. int xm1 = (x-1);
  117. cur_line[x] = new;
  118. if(!left && x > 0 && (cur_line[xm1] == old))
  119. {
  120. if(!push(x - 1, yt, dstp->h)) return;
  121. left = 1;
  122. }
  123. else if(left && x > 0 && (cur_line[xm1] != old))
  124. {
  125. left = 0;
  126. }
  127. if(!right && x < dstp->w - 1 && (cur_line[xp1] == old))
  128. {
  129. if(!push(x + 1, yt, dstp->h)) return;
  130. right = 1;
  131. }
  132. else if(right && x < dstp->w - 1 && (cur_line[xp1] != old))
  133. {
  134. right = 0;
  135. }
  136. yt++;
  137. }
  138. }
  139. }
  140. /* Float version. Much slower, but supports HDR and (soon antialiasing) */
  141. static void pipi_flood_fill_stack_scanline_float(pipi_pixels_t *dstp,
  142. int x, int y,
  143. float nr, float ng, float nb,
  144. float or, float og, float ob)
  145. {
  146. if((nr==or) && (ng==og) && (nb==ob)) return;
  147. clear_stack(dstp->h);
  148. int yt;
  149. int left, right;
  150. float *dstdata = (float *)dstp->pixels;
  151. if(!push(x, y, dstp->h)) return;
  152. while(pop(&x, &y, dstp->h))
  153. {
  154. yt = y;
  155. while(yt >= 0 && validate_pixel_f(dstdata[(x+yt*dstp->w)*4] ,
  156. dstdata[(x+yt*dstp->w)*4 + 1] ,
  157. dstdata[(x+yt*dstp->w)*4 + 2] ,
  158. or, og, ob)) {
  159. yt--;
  160. }
  161. yt++;
  162. left = right = 0;
  163. while(yt < dstp->h && validate_pixel_f(dstdata[(x+yt*dstp->w)*4] ,
  164. dstdata[(x+yt*dstp->w)*4 + 1] ,
  165. dstdata[(x+yt*dstp->w)*4 + 2] ,
  166. or, og, ob))
  167. {
  168. float *cur_line = &dstdata[(yt*dstp->w)*4];
  169. int xp1 = (x+1)*4;
  170. int xm1 = (x-1)*4;
  171. cur_line[x*4] = nr;
  172. cur_line[x*4 + 1] = ng;
  173. cur_line[x*4 + 2] = nb;
  174. if(!left && x > 0 && validate_pixel_f(cur_line[xm1],
  175. cur_line[xm1 + 1],
  176. cur_line[xm1 + 2],
  177. or, og, ob))
  178. {
  179. if(!push(x - 1, yt, dstp->h)) return;
  180. left = 1;
  181. }
  182. else if(left && x > 0 && !validate_pixel_f(cur_line[xm1] ,
  183. cur_line[xm1 + 1] ,
  184. cur_line[xm1 + 2] ,
  185. or, og, ob))
  186. {
  187. left = 0;
  188. }
  189. if(!right && x < dstp->w - 1 && validate_pixel_f(cur_line[xp1] ,
  190. cur_line[xp1 + 1] ,
  191. cur_line[xp1 + 2] ,
  192. or, og, ob))
  193. {
  194. if(!push(x + 1, yt, dstp->h)) return;
  195. right = 1;
  196. }
  197. else if(right && x < dstp->w - 1 && !validate_pixel_f(cur_line[xp1] ,
  198. cur_line[xp1 + 1] ,
  199. cur_line[xp1 + 2],
  200. or, og, ob))
  201. {
  202. right = 0;
  203. }
  204. yt++;
  205. }
  206. }
  207. }
  208. /* Following functions are local */
  209. static int pop(int *x, int *y, int h)
  210. {
  211. if(stack_pointer > 0)
  212. {
  213. int p = stack[stack_pointer];
  214. *x = p / h;
  215. *y = p % h;
  216. stack_pointer--;
  217. return 1;
  218. }
  219. else
  220. {
  221. return 0;
  222. }
  223. }
  224. static int push(int x, int y, int h)
  225. {
  226. if(stack_pointer < STACKSIZE - 1)
  227. {
  228. stack_pointer++;
  229. stack[stack_pointer] = h * x + y;
  230. return 1;
  231. }
  232. else
  233. {
  234. return 0;
  235. }
  236. }
  237. static void clear_stack(int h)
  238. {
  239. int x, y;
  240. while(pop(&x, &y, h));
  241. }
  242. #define MAX(a, b) (b>a?b:a)
  243. /* FIXME : Paves the way to antialiasing, but could be only 3 tests */
  244. static float get_max_color_diff(float r1, float g1, float b1,
  245. float r2, float g2, float b2)
  246. {
  247. float r = abs(r2-r1);
  248. float g = abs(g2-g1);
  249. float b = abs(b2-b1);
  250. return MAX(MAX(r, g), b);
  251. }
  252. static int validate_pixel_f(float r1, float g1, float b1,
  253. float r2, float g2, float b2)
  254. {
  255. if(get_max_color_diff(r1, g1, b1,
  256. r2, g2, b2)
  257. == 0) return 1;
  258. else
  259. return 0;
  260. }