You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

319 line
9.1 KiB

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