image_quantize.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*************************************************************************/
  2. /* image_quantize.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "image.h"
  31. #include "print_string.h"
  32. #include <stdio.h>
  33. #ifdef TOOLS_ENABLED
  34. #include "os/os.h"
  35. #include "set.h"
  36. #include "sort.h"
  37. //#define QUANTIZE_SPEED_OVER_QUALITY
  38. Image::MCBlock::MCBlock() {
  39. }
  40. Image::MCBlock::MCBlock(BColorPos *p_colors, int p_color_count) {
  41. colors = p_colors;
  42. color_count = p_color_count;
  43. min_color.color = BColor(255, 255, 255, 255);
  44. max_color.color = BColor(0, 0, 0, 0);
  45. shrink();
  46. }
  47. int Image::MCBlock::get_longest_axis_index() const {
  48. int max_dist = -1;
  49. int max_index = 0;
  50. for (int i = 0; i < 4; i++) {
  51. int d = max_color.color.col[i] - min_color.color.col[i];
  52. if (d > max_dist) {
  53. max_index = i;
  54. max_dist = d;
  55. }
  56. }
  57. return max_index;
  58. }
  59. int Image::MCBlock::get_longest_axis_length() const {
  60. int max_dist = -1;
  61. for (int i = 0; i < 4; i++) {
  62. int d = max_color.color.col[i] - min_color.color.col[i];
  63. if (d > max_dist) {
  64. max_dist = d;
  65. }
  66. }
  67. return max_dist;
  68. }
  69. bool Image::MCBlock::operator<(const MCBlock &p_block) const {
  70. int alen = get_longest_axis_length();
  71. int blen = p_block.get_longest_axis_length();
  72. if (alen == blen) {
  73. return colors < p_block.colors;
  74. } else
  75. return alen < blen;
  76. }
  77. void Image::MCBlock::shrink() {
  78. min_color = colors[0];
  79. max_color = colors[0];
  80. for (int i = 1; i < color_count; i++) {
  81. for (int j = 0; j < 4; j++) {
  82. min_color.color.col[j] = MIN(min_color.color.col[j], colors[i].color.col[j]);
  83. max_color.color.col[j] = MAX(max_color.color.col[j], colors[i].color.col[j]);
  84. }
  85. }
  86. }
  87. void Image::quantize() {
  88. bool has_alpha = detect_alpha() != ALPHA_NONE;
  89. bool quantize_fast = OS::get_singleton()->has_environment("QUANTIZE_FAST");
  90. convert(FORMAT_RGBA);
  91. ERR_FAIL_COND(format != FORMAT_RGBA);
  92. DVector<uint8_t> indexed_data;
  93. {
  94. int color_count = data.size() / 4;
  95. ERR_FAIL_COND(color_count == 0);
  96. Set<MCBlock> block_queue;
  97. DVector<BColorPos> data_colors;
  98. data_colors.resize(color_count);
  99. DVector<BColorPos>::Write dcw = data_colors.write();
  100. DVector<uint8_t>::Read dr = data.read();
  101. const BColor *drptr = (const BColor *)&dr[0];
  102. BColorPos *bcptr = &dcw[0];
  103. {
  104. for (int i = 0; i < color_count; i++) {
  105. //uint32_t data_ofs=i<<2;
  106. bcptr[i].color = drptr[i]; //BColor(drptr[data_ofs+0],drptr[data_ofs+1],drptr[data_ofs+2],drptr[data_ofs+3]);
  107. bcptr[i].index = i;
  108. }
  109. }
  110. //printf("color count: %i\n",color_count);
  111. /*
  112. for(int i=0;i<color_count;i++) {
  113. BColor bc = ((BColor*)&wb[0])[i];
  114. printf("%i - %i,%i,%i,%i\n",i,bc.r,bc.g,bc.b,bc.a);
  115. }*/
  116. MCBlock initial_block((BColorPos *)&dcw[0], color_count);
  117. block_queue.insert(initial_block);
  118. while (block_queue.size() < 256 && block_queue.back()->get().color_count > 1) {
  119. MCBlock longest = block_queue.back()->get();
  120. //printf("longest: %i (%i)\n",longest.get_longest_axis_index(),longest.get_longest_axis_length());
  121. block_queue.erase(block_queue.back());
  122. BColorPos *first = longest.colors;
  123. BColorPos *median = longest.colors + (longest.color_count + 1) / 2;
  124. BColorPos *end = longest.colors + longest.color_count;
  125. #if 0
  126. int lai =longest.get_longest_axis_index();
  127. switch(lai) {
  128. #if 0
  129. case 0: { SortArray<BColorPos,BColorPos::SortR> sort; sort.sort(first,end-first); } break;
  130. case 1: { SortArray<BColorPos,BColorPos::SortG> sort; sort.sort(first,end-first); } break;
  131. case 2: { SortArray<BColorPos,BColorPos::SortB> sort; sort.sort(first,end-first); } break;
  132. case 3: { SortArray<BColorPos,BColorPos::SortA> sort; sort.sort(first,end-first); } break;
  133. #else
  134. case 0: { SortArray<BColorPos,BColorPos::SortR> sort; sort.nth_element(0,end-first,median-first,first); } break;
  135. case 1: { SortArray<BColorPos,BColorPos::SortG> sort; sort.nth_element(0,end-first,median-first,first); } break;
  136. case 2: { SortArray<BColorPos,BColorPos::SortB> sort; sort.nth_element(0,end-first,median-first,first); } break;
  137. case 3: { SortArray<BColorPos,BColorPos::SortA> sort; sort.nth_element(0,end-first,median-first,first); } break;
  138. #endif
  139. }
  140. //avoid same color from being split in 2
  141. //search forward and flip
  142. BColorPos *median_end=median;
  143. BColorPos *p=median_end+1;
  144. while(p!=end) {
  145. if (median_end->color==p->color) {
  146. SWAP(*(median_end+1),*p);
  147. median_end++;
  148. }
  149. p++;
  150. }
  151. //search backward and flip
  152. BColorPos *median_begin=median;
  153. p=median_begin-1;
  154. while(p!=(first-1)) {
  155. if (median_begin->color==p->color) {
  156. SWAP(*(median_begin-1),*p);
  157. median_begin--;
  158. }
  159. p--;
  160. }
  161. if (first < median_begin) {
  162. median=median_begin;
  163. } else if (median_end < end-1) {
  164. median=median_end+1;
  165. } else {
  166. break; //shouldn't have arrived here, since it means all pixels are equal, but wathever
  167. }
  168. MCBlock left(first,median-first);
  169. MCBlock right(median,end-median);
  170. block_queue.insert(left);
  171. block_queue.insert(right);
  172. #else
  173. switch (longest.get_longest_axis_index()) {
  174. case 0: {
  175. SortArray<BColorPos, BColorPos::SortR> sort;
  176. sort.nth_element(0, end - first, median - first, first);
  177. } break;
  178. case 1: {
  179. SortArray<BColorPos, BColorPos::SortG> sort;
  180. sort.nth_element(0, end - first, median - first, first);
  181. } break;
  182. case 2: {
  183. SortArray<BColorPos, BColorPos::SortB> sort;
  184. sort.nth_element(0, end - first, median - first, first);
  185. } break;
  186. case 3: {
  187. SortArray<BColorPos, BColorPos::SortA> sort;
  188. sort.nth_element(0, end - first, median - first, first);
  189. } break;
  190. }
  191. MCBlock left(first, median - first);
  192. MCBlock right(median, end - median);
  193. block_queue.insert(left);
  194. block_queue.insert(right);
  195. #endif
  196. }
  197. while (block_queue.size() > 256) {
  198. block_queue.erase(block_queue.front()); // erase least significant
  199. }
  200. int res_colors = 0;
  201. int comp_size = (has_alpha ? 4 : 3);
  202. indexed_data.resize(color_count + 256 * comp_size);
  203. DVector<uint8_t>::Write iw = indexed_data.write();
  204. uint8_t *iwptr = &iw[0];
  205. BColor pallete[256];
  206. // print_line("applying quantization - res colors "+itos(block_queue.size()));
  207. while (block_queue.size()) {
  208. const MCBlock &b = block_queue.back()->get();
  209. uint64_t sum[4] = { 0, 0, 0, 0 };
  210. for (int i = 0; i < b.color_count; i++) {
  211. sum[0] += b.colors[i].color.col[0];
  212. sum[1] += b.colors[i].color.col[1];
  213. sum[2] += b.colors[i].color.col[2];
  214. sum[3] += b.colors[i].color.col[3];
  215. }
  216. BColor c(sum[0] / b.color_count, sum[1] / b.color_count, sum[2] / b.color_count, sum[3] / b.color_count);
  217. //printf(" %i: %i,%i,%i,%i out of %i\n",res_colors,c.r,c.g,c.b,c.a,b.color_count);
  218. for (int i = 0; i < comp_size; i++) {
  219. iwptr[color_count + res_colors * comp_size + i] = c.col[i];
  220. }
  221. if (quantize_fast) {
  222. for (int i = 0; i < b.color_count; i++) {
  223. iwptr[b.colors[i].index] = res_colors;
  224. }
  225. } else {
  226. pallete[res_colors] = c;
  227. }
  228. res_colors++;
  229. block_queue.erase(block_queue.back());
  230. }
  231. if (!quantize_fast) {
  232. for (int i = 0; i < color_count; i++) {
  233. const BColor &c = drptr[i];
  234. uint8_t best_dist_idx = 0;
  235. uint32_t dist = 0xFFFFFFFF;
  236. for (int j = 0; j < res_colors; j++) {
  237. const BColor &pc = pallete[j];
  238. uint32_t d = 0;
  239. {
  240. int16_t v = (int16_t)c.r - (int16_t)pc.r;
  241. d += v * v;
  242. }
  243. {
  244. int16_t v = (int16_t)c.g - (int16_t)pc.g;
  245. d += v * v;
  246. }
  247. {
  248. int16_t v = (int16_t)c.b - (int16_t)pc.b;
  249. d += v * v;
  250. }
  251. {
  252. int16_t v = (int16_t)c.a - (int16_t)pc.a;
  253. d += v * v;
  254. }
  255. if (d <= dist) {
  256. best_dist_idx = j;
  257. dist = d;
  258. }
  259. }
  260. iwptr[i] = best_dist_idx;
  261. }
  262. }
  263. //iw = DVector<uint8_t>::Write();
  264. //dr = DVector<uint8_t>::Read();
  265. //wb = DVector<uint8_t>::Write();
  266. }
  267. print_line(itos(indexed_data.size()));
  268. data = indexed_data;
  269. format = has_alpha ? FORMAT_INDEXED_ALPHA : FORMAT_INDEXED;
  270. } //do none
  271. #else
  272. void Image::quantize() {} //do none
  273. #endif