color_utils.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include "lmem.h"
  4. #include "platform.h"
  5. #include <stdlib.h>
  6. #include <math.h>
  7. #include <string.h>
  8. #include "user_interface.h"
  9. #include "osapi.h"
  10. #include "color_utils.h"
  11. #define min(a,b) ((a) < (b) ? (a) : (b))
  12. #define max(a,b) ((a) > (b) ? (a) : (b))
  13. #define abs(a) ((a) > 0 ? (a) : (0-a))
  14. #define min3(a,b, c) min((a), min((b), (c)))
  15. #define max3(a,b, c) max((a), max((b), (c)))
  16. #define CANARY_VALUE 0x37383132
  17. // convert hsv to grb value
  18. uint32_t hsv2grb(uint16_t hue, uint8_t sat, uint8_t val)
  19. {
  20. uint16_t H_accent = (hue % 360) / 60;
  21. uint16_t bottom = ((255 - sat) * val)>>8;
  22. uint16_t top = val;
  23. uint8_t rising = ((top-bottom) *(hue%60 ) ) / 60 + bottom;
  24. uint8_t falling = ((top-bottom) *(60-hue%60) ) / 60 + bottom;
  25. uint8_t r;
  26. uint8_t g;
  27. uint8_t b;
  28. switch(H_accent) {
  29. case 0:
  30. r = top;
  31. g = rising;
  32. b = bottom;
  33. break;
  34. case 1:
  35. r = falling;
  36. g = top;
  37. b = bottom;
  38. break;
  39. case 2:
  40. r = bottom;
  41. g = top;
  42. b = rising;
  43. break;
  44. case 3:
  45. r = bottom;
  46. g = falling;
  47. b = top;
  48. break;
  49. case 4:
  50. r = rising;
  51. g = bottom;
  52. b = top;
  53. break;
  54. case 5:
  55. r = top;
  56. g = bottom;
  57. b = falling;
  58. break;
  59. }
  60. uint32_t result = (g << 16) | (r << 8) | b;
  61. return result;
  62. }
  63. // convert hsv to grbw value
  64. uint32_t hsv2grbw(uint16_t hue, uint8_t sat, uint8_t val) {
  65. uint32_t grb = hsv2grb(hue, sat, val);
  66. uint8_t g = ((grb & 0x00FF0000) >> 16);
  67. uint8_t r = ((grb & 0x0000FF00) >> 8);
  68. uint8_t b = (grb & 0x000000FF);
  69. // calculate white component
  70. uint8_t w = min3(g, r, b);
  71. g = g - w;
  72. r = r - w;
  73. b = b - w;
  74. uint32_t grbw = (g << 24) | (r << 16) | (b << 8) | w;
  75. return grbw;
  76. }
  77. // convert grb to hsv value
  78. uint32_t grb2hsv(uint8_t g, uint8_t r, uint8_t b) {
  79. uint8_t m = min3(r, g, b);
  80. uint8_t M = max3(r, g, b);
  81. uint8_t delta = M - m;
  82. int hue = 0;
  83. int saturation = 0;
  84. int value = 0;
  85. if(delta == 0) {
  86. /* Achromatic case (i.e. grayscale) */
  87. hue = -1; /* undefined */
  88. saturation = 0;
  89. } else {
  90. int h;
  91. if(r == M)
  92. h = ((g-b)*60) / delta;
  93. else if(g == M)
  94. h = ((b-r)*60) / delta + 120;
  95. else /*if(b == M)*/
  96. h = ((r-g)*60) / delta + 240;
  97. if(h < 0)
  98. h += 360;
  99. hue = h;
  100. /* The constatnt 8 is tuned to statistically cause as little
  101. * tolerated mismatches as possible in RGB -> HSV -> RGB conversion.
  102. * (See the unit test at the bottom of this file.)
  103. */
  104. saturation = (256*delta-8) / M;
  105. }
  106. value = M;
  107. uint32_t result = (hue << 16) | (saturation << 8) | value;
  108. return result;
  109. }
  110. /*
  111. * Put a value 0 to 360 in to get a color value.
  112. * The colours are a transition r -> g -> b -> back to r
  113. * Inspired by the Adafruit examples.
  114. */
  115. uint32_t color_wheel(uint16_t pos) {
  116. return hsv2grb(pos, 255, 255);
  117. }
  118. // convert hsv to grb value
  119. static int cu_hsv2grb(lua_State *L) {
  120. const int hue = luaL_checkint(L, 1);
  121. const int sat = luaL_checkint(L, 2);
  122. const int val = luaL_checkint(L, 3);
  123. luaL_argcheck(L, hue >= 0 && hue <= 360, 1, "should be a 0-360");
  124. luaL_argcheck(L, sat >= 0 && sat <= 255, 2, "should be 0-255");
  125. luaL_argcheck(L, val >= 0 && val <= 255, 3, "should be 0-255");
  126. // convert to grb
  127. uint32_t tmp_color = hsv2grb(hue, sat, val);
  128. // return
  129. lua_pushunsigned(L, (tmp_color & 0x00FF0000) >> 16);
  130. lua_pushunsigned(L, (tmp_color & 0x0000FF00) >> 8);
  131. lua_pushunsigned(L, (tmp_color & 0x000000FF));
  132. return 3;
  133. }
  134. // convert hsv to grbw value
  135. static int cu_hsv2grbw(lua_State *L) {
  136. const int hue = luaL_checkint(L, 1);
  137. const int sat = luaL_checkint(L, 2);
  138. const int val = luaL_checkint(L, 3);
  139. luaL_argcheck(L, hue >= 0 && hue <= 360, 1, "should be a 0-360");
  140. luaL_argcheck(L, sat >= 0 && sat <= 255, 2, "should be 0-255");
  141. luaL_argcheck(L, val >= 0 && val <= 255, 3, "should be 0-255");
  142. // convert to grbw
  143. uint32_t tmp_color = hsv2grbw(hue, sat, val);
  144. // return g, r, b, w
  145. lua_pushunsigned(L, (tmp_color & 0xFF000000) >> 24);
  146. lua_pushunsigned(L, (tmp_color & 0x00FF0000) >> 16);
  147. lua_pushunsigned(L, (tmp_color & 0x0000FF00) >> 8);
  148. lua_pushunsigned(L, (tmp_color & 0x000000FF));
  149. return 4;
  150. }
  151. // create a color wheel value
  152. static int cu_color_wheel(lua_State *L) {
  153. const int wheel_index = luaL_checkint(L, 1);
  154. luaL_argcheck(L, wheel_index >= 0 && wheel_index <= 360, 1, "should be a 0-360");
  155. uint32_t color = color_wheel(wheel_index);
  156. uint8_t r = (color & 0x00FF0000) >> 16;
  157. uint8_t g = (color & 0x0000FF00) >> 8;
  158. uint8_t b = (color & 0x000000FF) >> 0;
  159. // return
  160. lua_pushunsigned(L, g);
  161. lua_pushunsigned(L, r);
  162. lua_pushunsigned(L, b);
  163. return 3;
  164. }
  165. // convert grb values to hsv
  166. static int cu_grb2hsv(lua_State *L) {
  167. const int g = luaL_checkint(L, 1);
  168. const int r = luaL_checkint(L, 2);
  169. const int b = luaL_checkint(L, 3);
  170. luaL_argcheck(L, g != r || g != b, 1, "greyscale value cannot be converted to hsv");
  171. uint32_t hsv = grb2hsv(g, r, b);
  172. uint16_t h = (hsv & 0xFFFF0000) >> 16;
  173. uint8_t s = (hsv & 0x0000FF00) >> 8;
  174. uint8_t v = (hsv & 0x000000FF) >> 0;
  175. // return
  176. lua_pushunsigned(L, h);
  177. lua_pushunsigned(L, s);
  178. lua_pushunsigned(L, v);
  179. return 3;
  180. }
  181. LROT_BEGIN(color_utils, NULL, 0)
  182. LROT_FUNCENTRY( hsv2grb, cu_hsv2grb )
  183. LROT_FUNCENTRY( hsv2grbw, cu_hsv2grbw )
  184. LROT_FUNCENTRY( colorWheel, cu_color_wheel )
  185. LROT_FUNCENTRY( grb2hsv, cu_grb2hsv )
  186. LROT_END(color_utils, NULL, 0)
  187. NODEMCU_MODULE(COLOR_UTILS, "color_utils", color_utils, NULL);