PageRenderTime 84ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/kalium/inc/lib/colors.inc.php

https://bitbucket.org/medicalmotion/backend
PHP | 336 lines | 268 code | 28 blank | 40 comment | 55 complexity | a15b973fee49bd293607d58cbfe4fa88 MD5 | raw file
  1. <?php
  2. /**
  3. * This class can be used to get the most common colors in an image.
  4. * It needs one parameter:
  5. * $image - the filename of the image you want to process.
  6. * Optional parameters:
  7. *
  8. * $count - how many colors should be returned. 0 mmeans all. default=20
  9. * $reduce_brightness - reduce (not eliminate) brightness variants? default=true
  10. * $reduce_gradients - reduce (not eliminate) gradient variants? default=true
  11. * $delta - the amount of gap when quantizing color values.
  12. * Lower values mean more accurate colors. default=16
  13. *
  14. * Author: Csongor Zalatnai
  15. *
  16. * Modified By: Kepler Gelotte - Added the gradient and brightness variation
  17. * reduction routines. Kudos to Csongor for an excellent class. The original
  18. * version can be found at:
  19. *
  20. * http://www.phpclasses.org/browse/package/3370.html
  21. *
  22. */
  23. if ( ! defined( 'ABSPATH' ) ) {
  24. exit; // Direct access not allowed.
  25. }
  26. class GetMostCommonColors
  27. {
  28. var $PREVIEW_WIDTH = 150;
  29. var $PREVIEW_HEIGHT = 150;
  30. var $error;
  31. /**
  32. * Returns the colors of the image in an array, ordered in descending order, where the keys are the colors, and the values are the count of the color.
  33. *
  34. * @return array
  35. */
  36. function Get_Color( $img, $count=20, $reduce_brightness=true, $reduce_gradients=true, $delta=16 )
  37. {
  38. if (is_readable( $img ))
  39. {
  40. if ( $delta > 2 )
  41. {
  42. $half_delta = $delta / 2 - 1;
  43. }
  44. else
  45. {
  46. $half_delta = 0;
  47. }
  48. // WE HAVE TO RESIZE THE IMAGE, BECAUSE WE ONLY NEED THE MOST SIGNIFICANT COLORS.
  49. $size = GetImageSize($img);
  50. $scale = 1;
  51. if ($size[0]>0)
  52. $scale = min($this->PREVIEW_WIDTH/$size[0], $this->PREVIEW_HEIGHT/$size[1]);
  53. if ($scale < 1)
  54. {
  55. $width = floor($scale*$size[0]);
  56. $height = floor($scale*$size[1]);
  57. }
  58. else
  59. {
  60. $width = $size[0];
  61. $height = $size[1];
  62. }
  63. $image_resized = imagecreatetruecolor($width, $height);
  64. if ($size[2] == 1)
  65. $image_orig = imagecreatefromgif($img);
  66. if ($size[2] == 2)
  67. $image_orig = imagecreatefromjpeg($img);
  68. if ($size[2] == 3)
  69. $image_orig = imagecreatefrompng($img);
  70. // WE NEED NEAREST NEIGHBOR RESIZING, BECAUSE IT DOESN'T ALTER THE COLORS
  71. imagecopyresampled($image_resized, $image_orig, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
  72. $im = $image_resized;
  73. $imgWidth = imagesx($im);
  74. $imgHeight = imagesy($im);
  75. $total_pixel_count = 0;
  76. for ($y=0; $y < $imgHeight; $y++)
  77. {
  78. for ($x=0; $x < $imgWidth; $x++)
  79. {
  80. $total_pixel_count++;
  81. $index = imagecolorat($im,$x,$y);
  82. $colors = imagecolorsforindex($im,$index);
  83. // ROUND THE COLORS, TO REDUCE THE NUMBER OF DUPLICATE COLORS
  84. if ( $delta > 1 )
  85. {
  86. $colors['red'] = intval((($colors['red'])+$half_delta)/$delta)*$delta;
  87. $colors['green'] = intval((($colors['green'])+$half_delta)/$delta)*$delta;
  88. $colors['blue'] = intval((($colors['blue'])+$half_delta)/$delta)*$delta;
  89. if ($colors['red'] >= 256)
  90. {
  91. $colors['red'] = 255;
  92. }
  93. if ($colors['green'] >= 256)
  94. {
  95. $colors['green'] = 255;
  96. }
  97. if ($colors['blue'] >= 256)
  98. {
  99. $colors['blue'] = 255;
  100. }
  101. }
  102. $hex = substr("0".dechex($colors['red']),-2).substr("0".dechex($colors['green']),-2).substr("0".dechex($colors['blue']),-2);
  103. if ( ! isset( $hexarray[$hex] ) )
  104. {
  105. $hexarray[$hex] = 1;
  106. }
  107. else
  108. {
  109. $hexarray[$hex]++;
  110. }
  111. }
  112. }
  113. // Reduce gradient colors
  114. if ( $reduce_gradients )
  115. {
  116. // if you want to *eliminate* gradient variations use:
  117. // ksort( $hexarray );
  118. arsort( $hexarray, SORT_NUMERIC );
  119. $gradients = array();
  120. foreach ($hexarray as $hex => $num)
  121. {
  122. if ( ! isset($gradients[$hex]) )
  123. {
  124. $new_hex = $this->_find_adjacent( $hex, $gradients, $delta );
  125. $gradients[$hex] = $new_hex;
  126. }
  127. else
  128. {
  129. $new_hex = $gradients[$hex];
  130. }
  131. if ($hex != $new_hex)
  132. {
  133. $hexarray[$hex] = 0;
  134. $hexarray[$new_hex] += $num;
  135. }
  136. }
  137. }
  138. // Reduce brightness variations
  139. if ( $reduce_brightness )
  140. {
  141. // if you want to *eliminate* brightness variations use:
  142. // ksort( $hexarray );
  143. arsort( $hexarray, SORT_NUMERIC );
  144. $brightness = array();
  145. foreach ($hexarray as $hex => $num)
  146. {
  147. if ( ! isset($brightness[$hex]) )
  148. {
  149. $new_hex = $this->_normalize( $hex, $brightness, $delta );
  150. $brightness[$hex] = $new_hex;
  151. }
  152. else
  153. {
  154. $new_hex = $brightness[$hex];
  155. }
  156. if ($hex != $new_hex)
  157. {
  158. $hexarray[$hex] = 0;
  159. $hexarray[$new_hex] += $num;
  160. }
  161. }
  162. }
  163. arsort( $hexarray, SORT_NUMERIC );
  164. // convert counts to percentages
  165. foreach ($hexarray as $key => $value)
  166. {
  167. $hexarray[$key] = (float)$value / $total_pixel_count;
  168. }
  169. if ( $count > 0 )
  170. {
  171. // only works in PHP5
  172. // return array_slice( $hexarray, 0, $count, true );
  173. $arr = array();
  174. foreach ($hexarray as $key => $value)
  175. {
  176. if ($count == 0)
  177. {
  178. break;
  179. }
  180. $count--;
  181. $arr[$key] = $value;
  182. }
  183. return $arr;
  184. }
  185. else
  186. {
  187. return $hexarray;
  188. }
  189. }
  190. else
  191. {
  192. $this->error = "Image ".$img." does not exist or is unreadable";
  193. return false;
  194. }
  195. }
  196. function _normalize( $hex, $hexarray, $delta )
  197. {
  198. $lowest = 255;
  199. $highest = 0;
  200. $colors['red'] = hexdec( substr( $hex, 0, 2 ) );
  201. $colors['green'] = hexdec( substr( $hex, 2, 2 ) );
  202. $colors['blue'] = hexdec( substr( $hex, 4, 2 ) );
  203. if ($colors['red'] < $lowest)
  204. {
  205. $lowest = $colors['red'];
  206. }
  207. if ($colors['green'] < $lowest )
  208. {
  209. $lowest = $colors['green'];
  210. }
  211. if ($colors['blue'] < $lowest )
  212. {
  213. $lowest = $colors['blue'];
  214. }
  215. if ($colors['red'] > $highest)
  216. {
  217. $highest = $colors['red'];
  218. }
  219. if ($colors['green'] > $highest )
  220. {
  221. $highest = $colors['green'];
  222. }
  223. if ($colors['blue'] > $highest )
  224. {
  225. $highest = $colors['blue'];
  226. }
  227. // Do not normalize white, black, or shades of grey unless low delta
  228. if ( $lowest == $highest )
  229. {
  230. if ($delta <= 32)
  231. {
  232. if ( $lowest == 0 || $highest >= (255 - $delta) )
  233. {
  234. return $hex;
  235. }
  236. }
  237. else
  238. {
  239. return $hex;
  240. }
  241. }
  242. for (; $highest < 256; $lowest += $delta, $highest += $delta)
  243. {
  244. $new_hex = substr("0".dechex($colors['red'] - $lowest),-2).substr("0".dechex($colors['green'] - $lowest),-2).substr("0".dechex($colors['blue'] - $lowest),-2);
  245. if ( isset( $hexarray[$new_hex] ) )
  246. {
  247. // same color, different brightness - use it instead
  248. return $new_hex;
  249. }
  250. }
  251. return $hex;
  252. }
  253. function _find_adjacent( $hex, $gradients, $delta )
  254. {
  255. $red = hexdec( substr( $hex, 0, 2 ) );
  256. $green = hexdec( substr( $hex, 2, 2 ) );
  257. $blue = hexdec( substr( $hex, 4, 2 ) );
  258. if ($red > $delta)
  259. {
  260. $new_hex = substr("0".dechex($red - $delta),-2).substr("0".dechex($green),-2).substr("0".dechex($blue),-2);
  261. if ( isset($gradients[$new_hex]) )
  262. {
  263. return $gradients[$new_hex];
  264. }
  265. }
  266. if ($green > $delta)
  267. {
  268. $new_hex = substr("0".dechex($red),-2).substr("0".dechex($green - $delta),-2).substr("0".dechex($blue),-2);
  269. if ( isset($gradients[$new_hex]) )
  270. {
  271. return $gradients[$new_hex];
  272. }
  273. }
  274. if ($blue > $delta)
  275. {
  276. $new_hex = substr("0".dechex($red),-2).substr("0".dechex($green),-2).substr("0".dechex($blue - $delta),-2);
  277. if ( isset($gradients[$new_hex]) )
  278. {
  279. return $gradients[$new_hex];
  280. }
  281. }
  282. if ($red < (255 - $delta))
  283. {
  284. $new_hex = substr("0".dechex($red + $delta),-2).substr("0".dechex($green),-2).substr("0".dechex($blue),-2);
  285. if ( isset($gradients[$new_hex]) )
  286. {
  287. return $gradients[$new_hex];
  288. }
  289. }
  290. if ($green < (255 - $delta))
  291. {
  292. $new_hex = substr("0".dechex($red),-2).substr("0".dechex($green + $delta),-2).substr("0".dechex($blue),-2);
  293. if ( isset($gradients[$new_hex]) )
  294. {
  295. return $gradients[$new_hex];
  296. }
  297. }
  298. if ($blue < (255 - $delta))
  299. {
  300. $new_hex = substr("0".dechex($red),-2).substr("0".dechex($green),-2).substr("0".dechex($blue + $delta),-2);
  301. if ( isset($gradients[$new_hex]) )
  302. {
  303. return $gradients[$new_hex];
  304. }
  305. }
  306. return $hex;
  307. }
  308. }