PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/class-Shoestrap_Color.php

https://gitlab.com/aristath/shoestrap-3
PHP | 481 lines | 254 code | 112 blank | 115 comment | 46 complexity | dc74b2a788077d1a773b7d998a4d7a22 MD5 | raw file
  1. <?php
  2. if ( ! class_exists( 'Shoestrap_Color' ) ) {
  3. /**
  4. * Color Calculations class for Shoestrap
  5. */
  6. class Shoestrap_Color {
  7. /**
  8. * Sanitises a HEX value.
  9. * The way this works is by splitting the string in 6 substrings.
  10. * Each sub-string is individually sanitized, and the result is then returned.
  11. *
  12. * @var string The hex value of a color
  13. * @param boolean Whether we want to include a hash (#) at the beginning or not
  14. * @return string The sanitized hex color.
  15. */
  16. public static function sanitize_hex( $color = '#FFFFFF', $hash = true ) {
  17. // Remove any spaces and special characters before and after the string
  18. $color = trim( $color );
  19. // Remove any trailing '#' symbols from the color value
  20. $color = str_replace( '#', '', $color );
  21. // If the string is 6 characters long then use it in pairs.
  22. if ( 3 == strlen( $color ) ) {
  23. $color = substr( $color, 0, 1 ) . substr( $color, 0, 1 ) . substr( $color, 1, 1 ) . substr( $color, 1, 1 ) . substr( $color, 2, 1 ) . substr( $color, 2, 1 );
  24. }
  25. $substr = array();
  26. for ( $i = 0; $i <= 5; $i++ ) {
  27. $default = ( 0 == $i ) ? 'F' : ( $substr[$i-1] );
  28. $substr[$i] = substr( $color, $i, 1 );
  29. $substr[$i] = ( false === $substr[$i] || ! ctype_xdigit( $substr[$i] ) ) ? $default : $substr[$i];
  30. }
  31. $hex = implode( '', $substr );
  32. return ( ! $hash ) ? $hex : '#' . $hex;
  33. }
  34. /**
  35. * Gets the rgb value of the $hex color.
  36. *
  37. * @var string The hex value of a color
  38. * @param boolean Whether we want to implode the values or not
  39. * @return mixed array|string
  40. */
  41. public static function get_rgb( $hex, $implode = false ) {
  42. // Remove any trailing '#' symbols from the color value
  43. $hex = self::sanitize_hex( $hex, false );
  44. $red = hexdec( substr( $hex, 0, 2 ) );
  45. $green = hexdec( substr( $hex, 2, 2 ) );
  46. $blue = hexdec( substr( $hex, 4, 2 ) );
  47. // rgb is an array
  48. $rgb = array( $red, $green, $blue );
  49. return ( $implode ) ? implode( ',', $rgb ) : $rgb;
  50. }
  51. /**
  52. * Gets the rgb value of the $hex color.
  53. *
  54. * @var string The hex value of a color
  55. * @param int Opacity level (1-100)
  56. * @return string
  57. */
  58. public static function get_rgba( $hex = '#fff', $opacity = 100, $echo = false ) {
  59. $hex = self::sanitize_hex( $hex, false );
  60. // Make sure that opacity is properly formatted :
  61. // Set the opacity to 100 if a larger value has been entered by mistake.
  62. // If a negative value is used, then set to 0.
  63. // If an opacity value is entered in a decimal form (for example 0.25), then multiply by 100.
  64. if ( $opacity >= 100 ) {
  65. $opacity = 100;
  66. } elseif ( $opacity < 0 ) {
  67. $opacity = 0;
  68. } elseif ( $opacity < 1 && $opacity != 0 ) {
  69. $opacity = ( $opacity * 100 );
  70. } else {
  71. $opacity = $opacity;
  72. }
  73. // Divide the opacity by 100 to end-up with a CSS value for the opacity
  74. $opacity = ( $opacity / 100 );
  75. $color = 'rgba(' . self::get_rgb( $hex, true ) . ', ' . $opacity . ')';
  76. if ( $echo ) {
  77. echo $color;
  78. } else {
  79. return $color;
  80. }
  81. }
  82. /**
  83. * Gets the brightness of the $hex color.
  84. *
  85. * @var string The hex value of a color
  86. * @return int value between 0 and 255
  87. */
  88. public static function get_brightness( $hex ) {
  89. $hex = self::sanitize_hex( $hex, false );
  90. // returns brightness value from 0 to 255
  91. $red = hexdec( substr( $hex, 0, 2 ) );
  92. $green = hexdec( substr( $hex, 2, 2 ) );
  93. $blue = hexdec( substr( $hex, 4, 2 ) );
  94. return ( ( $red * 299 ) + ( $green * 587 ) + ( $blue * 114 ) ) / 1000;
  95. }
  96. /**
  97. * Adjusts brightness of the $hex color.
  98. *
  99. * @var string The hex value of a color
  100. * @param int a value between -255 (darken) and 255 (lighten)
  101. * @return string returns hex color
  102. */
  103. public static function adjust_brightness( $hex, $steps ) {
  104. $hex = self::sanitize_hex( $hex, false );
  105. // Steps should be between -255 and 255. Negative = darker, positive = lighter
  106. $steps = max( -255, min( 255, $steps ) );
  107. // Get decimal values
  108. $red = hexdec( substr( $hex, 0, 2 ) );
  109. $green = hexdec( substr( $hex, 2, 2 ) );
  110. $blue = hexdec( substr( $hex, 4, 2 ) );
  111. // Adjust number of steps and keep it inside 0 to 255
  112. $red = max( 0, min( 255, $red + $steps ) );
  113. $green = max( 0, min( 255, $green + $steps ) );
  114. $blue = max( 0, min( 255, $blue + $steps ) );
  115. $red_hex = str_pad( dechex( $red ), 2, '0', STR_PAD_LEFT );
  116. $green_hex = str_pad( dechex( $green ), 2, '0', STR_PAD_LEFT );
  117. $blue_hex = str_pad( dechex( $blue ), 2, '0', STR_PAD_LEFT );
  118. return self::sanitize_hex( $red_hex . $green_hex . $blue_hex );
  119. }
  120. /**
  121. * Mixes 2 hex colors.
  122. * the "percentage" variable is the percent of the first color
  123. * to be used it the mix. default is 50 (equal mix)
  124. *
  125. * @var string The hex value of color 1
  126. * @var string The hex value of color 2
  127. * @param int a value between 0 and 100
  128. * @return string returns hex color
  129. */
  130. public static function mix_colors( $hex1, $hex2, $percentage ) {
  131. $hex1 = self::sanitize_hex( $hex1, false );
  132. $hex2 = self::sanitize_hex( $hex2, false );
  133. // Get decimal values
  134. $red_1 = hexdec( substr( $hex1, 0, 2 ) );
  135. $green_1 = hexdec( substr( $hex1, 2, 2 ) );
  136. $blue_1 = hexdec( substr( $hex1, 4, 2 ) );
  137. $red_2 = hexdec( substr( $hex2, 0, 2 ) );
  138. $green_2 = hexdec( substr( $hex2, 2, 2 ) );
  139. $blue_2 = hexdec( substr( $hex2, 4, 2 ) );
  140. $red = ( $percentage * $red_1 + ( 100 - $percentage ) * $red_2 ) / 100;
  141. $green = ( $percentage * $green_1 + ( 100 - $percentage ) * $green_2 ) / 100;
  142. $blue = ( $percentage * $blue_1 + ( 100 - $percentage ) * $blue_2 ) / 100;
  143. $red_hex = str_pad( dechex( $red ), 2, '0', STR_PAD_LEFT );
  144. $green_hex = str_pad( dechex( $green ), 2, '0', STR_PAD_LEFT );
  145. $blue_hex = str_pad( dechex( $blue ), 2, '0', STR_PAD_LEFT );
  146. return self::sanitize_hex( $red_hex . $green_hex . $blue_hex );
  147. }
  148. /**
  149. * Convert hex color to hsv
  150. *
  151. * @var string The hex value of color 1
  152. * @return array returns array( 'h', 's', 'v' )
  153. */
  154. public static function hex_to_hsv( $hex ) {
  155. $hex = self::sanitize_hex( $hex, false );
  156. $rgb = self::get_rgb( $hex );
  157. $hsv = self::rgb_to_hsv( $rgb );
  158. return $hsv;
  159. }
  160. /**
  161. * Convert hex color to hsv
  162. *
  163. * @var array The rgb color to conver array( 'r', 'g', 'b' )
  164. * @return array returns array( 'h', 's', 'v' )
  165. */
  166. public static function rgb_to_hsv( $color = array() ) {
  167. $r = $color[0];
  168. $g = $color[1];
  169. $b = $color[2];
  170. $hsl = array();
  171. $var_r = ( $r / 255 );
  172. $var_g = ( $g / 255 );
  173. $var_b = ( $b / 255 );
  174. $var_min = min( $var_r, $var_g, $var_b);
  175. $var_max = max( $var_r, $var_g, $var_b);
  176. $del_max = $var_max - $var_min;
  177. $v = $var_max;
  178. if ( $del_max == 0 ) {
  179. $h = 0;
  180. $s = 0;
  181. } else {
  182. $s = $del_max / $var_max;
  183. $del_r = ( ( ( $var_max - $var_r ) / 6 ) + ( $del_max / 2 ) ) / $del_max;
  184. $del_g = ( ( ( $var_max - $var_g ) / 6 ) + ( $del_max / 2 ) ) / $del_max;
  185. $del_b = ( ( ( $var_max - $var_b ) / 6 ) + ( $del_max / 2 ) ) / $del_max;
  186. if ( $var_r == $var_max ) {
  187. $h = $del_b - $del_g;
  188. } elseif ( $var_g == $var_max ) {
  189. $h = ( 1 / 3 ) + $del_r - $del_b;
  190. } elseif ( $var_b == $var_max ) {
  191. $h = ( 2 / 3 ) + $del_g - $del_r;
  192. }
  193. if ( $h < 0 ) {
  194. $h++;
  195. }
  196. if ( $h > 1 ) {
  197. $h--;
  198. }
  199. }
  200. $hsl['h'] = $h;
  201. $hsl['s'] = $s;
  202. $hsl['v'] = $v;
  203. return $hsl;
  204. }
  205. /**
  206. * Get the brightest color from an array of colors.
  207. * Return the key of the array if $context = 'key'
  208. * Return the hex value of the color if $context = 'value'
  209. *
  210. * @var array flat array of hex colors
  211. * @param string 'key' or 'value'
  212. * @return mixed int|string
  213. */
  214. public static function brightest_color( $colors = array(), $context = 'key' ) {
  215. $brightest = false;
  216. foreach ( $colors as $color ) {
  217. $color = self::sanitize_hex( $color, false );
  218. $brightness = self::get_brightness( $color );
  219. if ( ! $brightest || self::get_brightness( $color ) > self::get_brightness( $brightest ) ) {
  220. $brightest = $color;
  221. }
  222. }
  223. if ( $context == 'key' ) {
  224. return array_search( $brightest, $colors );
  225. } elseif ( $context == 'value' ) {
  226. return $brightest;
  227. }
  228. }
  229. /*
  230. * Get the most saturated color from an array of colors.
  231. * Return the key of the array if $context = 'key'
  232. * Return the hex value of the color if $context = 'value'
  233. */
  234. public static function most_saturated_color( $colors = array(), $context = 'key' ) {
  235. $most_saturated = false;
  236. foreach ( $colors as $color ) {
  237. $color = self::sanitize_hex( $color, false );
  238. $hsv = self::hex_to_hsv( $hex );
  239. $saturation = $hsv['s'];
  240. if ( $most_saturated ) {
  241. $hsv_old = self::hex_to_hsv( $most_saturated );
  242. }
  243. if ( ! $most_saturated || $saturation > $hsv_old['s'] ) {
  244. $most_saturated = $hex;
  245. }
  246. }
  247. if ( $context == 'key' ) {
  248. return array_search( $most_saturated, $colors );
  249. } elseif ( $context == 'value' ) {
  250. return $most_saturated;
  251. }
  252. }
  253. /*
  254. * Get the most intense color from an array of colors.
  255. * Return the key of the array if $context = 'key'
  256. * Return the hex value of the color if $context = 'value'
  257. */
  258. public static function most_intense_color( $colors = array(), $context = 'key' ) {
  259. $most_intense = false;
  260. foreach ( $colors as $color ) {
  261. $color = self::sanitize_hex( $color, false );
  262. $hsv = self::hex_to_hsv( $hex );
  263. $saturation = $hsv['s'];
  264. if ( $most_intense ) {
  265. $hsv_old = self::hex_to_hsv( $most_intense );
  266. }
  267. if ( ! $most_intense || $saturation > $hsv_old['s'] ) {
  268. $most_intense = $hex;
  269. }
  270. }
  271. if ( $context == 'key' ) {
  272. return array_search( $most_intense, $colors );
  273. } elseif ( $context == 'value' ) {
  274. return $most_intense;
  275. }
  276. }
  277. /*
  278. * Get the brightest color from an array of colors.
  279. * Return the key of the array if $context = 'key'
  280. * Return the hex value of the color if $context = 'value'
  281. */
  282. public static function brightest_dull_color( $colors = array(), $context = 'key' ) {
  283. $brightest_dull = false;
  284. foreach ( $colors as $color ) {
  285. $color = self::sanitize_hex( $color, false );
  286. $hsv = self::hex_to_hsv( $hex );
  287. $brightness = self::get_brightness( $hex );
  288. // Prevent "division by zero" messages.
  289. $hsv['s'] = ( $hsv['s'] == 0 ) ? 0.0001 : $hsv['s'];
  290. $dullness = 1 / $hsv['s'];
  291. if ( $brightest_dull ) {
  292. $hsv_old = self::hex_to_hsv( $brightest_dull );
  293. // Prevent "division by zero" messages.
  294. $hsv_old['s'] = ( $hsv_old['s'] == 0 ) ? 0.0001 : $hsv_old['s'];
  295. $dullness_old = 1 / $hsv_old['s'];
  296. }
  297. if ( ! $brightest_dull || self::get_brightness( $hex ) * $dullness > self::get_brightness( $brightest_dull ) * $dullness_old ) {
  298. $brightest_dull = $hex;
  299. }
  300. }
  301. if ( $context == 'key' ) {
  302. return array_search( $brightest_dull, $colors );
  303. } elseif ( $context == 'value' ) {
  304. return $brightest_dull;
  305. }
  306. }
  307. /*
  308. * This is a very simple algorithm that works by summing up the differences between the three color components red, green and blue.
  309. * A value higher than 500 is recommended for good readability.
  310. */
  311. public static function color_difference( $color_1 = '#ffffff', $color_2 = '#000000' ) {
  312. $color_1 = self::sanitize_hex( $color_1, false );
  313. $color_2 = self::sanitize_hex( $color_2, flase );
  314. $color_1_rgb = self::get_rgb( $color_1 );
  315. $color_2_rgb = self::get_rgb( $color_2 );
  316. $r1 = $color_1_rgb[0];
  317. $g1 = $color_1_rgb[1];
  318. $b1 = $color_1_rgb[2];
  319. $r2 = $color_2_rgb[0];
  320. $g2 = $color_2_rgb[1];
  321. $b2 = $color_2_rgb[2];
  322. $r_diff = max( $r1, $r2 ) - min( $r1, $r2 );
  323. $g_diff = max( $g1, $g2 ) - min( $g1, $g2 );
  324. $b_diff = max( $b1, $b2 ) - min( $b1, $b2 );
  325. $color_diff = $r_diff + $g_diff + $b_diff;
  326. return $color_diff;
  327. }
  328. /*
  329. * This function tries to compare the brightness of the colors.
  330. * A return value of more than 125 is recommended.
  331. * Combining it with the color_difference function above might make sense.
  332. */
  333. public static function brightness_difference( $color_1 = '#ffffff', $color_2 = '#000000' ) {
  334. $color_1 = self::sanitize_hex( $color_1, false );
  335. $color_2 = self::sanitize_hex( $color_2, false );
  336. $color_1_rgb = self::get_rgb( $color_1 );
  337. $color_2_rgb = self::get_rgb( $color_2 );
  338. $r1 = $color_1_rgb[0];
  339. $g1 = $color_1_rgb[1];
  340. $b1 = $color_1_rgb[2];
  341. $r2 = $color_2_rgb[0];
  342. $g2 = $color_2_rgb[1];
  343. $b2 = $color_2_rgb[2];
  344. $br_1 = ( 299 * $r1 + 587 * $g1 + 114 * $b1 ) / 1000;
  345. $br_2 = ( 299 * $r2 + 587 * $g2 + 114 * $b2 ) / 1000;
  346. return abs( $br_1 - $br_2 );
  347. }
  348. /*
  349. * Uses the luminosity to calculate the difference between the given colors.
  350. * The returned value should be bigger than 5 for best readability.
  351. */
  352. public static function lumosity_difference( $color_1 = '#ffffff', $color_2 = '#000000' ) {
  353. $color_1 = self::sanitize_hex( $color_1, false );
  354. $color_2 = self::sanitize_hex( $color_2, false );
  355. $color_1_rgb = self::get_rgb( $color_1 );
  356. $color_2_rgb = self::get_rgb( $color_2 );
  357. $r1 = $color_1_rgb[0];
  358. $g1 = $color_1_rgb[1];
  359. $b1 = $color_1_rgb[2];
  360. $r2 = $color_2_rgb[0];
  361. $g2 = $color_2_rgb[1];
  362. $b2 = $color_2_rgb[2];
  363. $l1 = 0.2126 * pow( $r1 / 255, 2.2 ) + 0.7152 * pow( $g1 / 255, 2.2 ) + 0.0722 * pow( $b1 / 255, 2.2 );
  364. $l2 = 0.2126 * pow( $r2 / 255, 2.2 ) + 0.7152 * pow( $g2 / 255, 2.2 ) + 0.0722 * pow( $b2 / 255, 2.2 );
  365. $lum_diff = ( $l1 > $l2 ) ? ( $l1 + 0.05 ) / ( $l2 + 0.05 ) : ( $l2 + 0.05 ) / ( $l1 + 0.05 );
  366. return $lum_diff;
  367. }
  368. }
  369. }