/_inc/lib/class.color.php

  1. <?php 
  2. /** 
  3. * Color utility and conversion 
  4. * 
  5. * Represents a color value, and converts between RGB/HSV/XYZ/Lab/HSL 
  6. * 
  7. * Example: 
  8. * $color = new Jetpack_Color(0xFFFFFF); 
  9. * 
  10. * @author Harold Asbridge <hasbridge@gmail.com> 
  11. * @author Matt Wiebe <wiebe@automattic.com> 
  12. * @license http://www.opensource.org/licenses/MIT 
  13. */ 
  14.  
  15. class Jetpack_Color { 
  16. /** 
  17. * @var int 
  18. */ 
  19. protected $color = 0; 
  20.  
  21. /** 
  22. * Initialize object 
  23. * 
  24. * @param string|array $color A color of the type $type 
  25. * @param string $type The type of color we will construct from. 
  26. * One of hex (default), rgb, hsl, int 
  27. */ 
  28. public function __construct( $color = null, $type = 'hex' ) { 
  29. if ( $color ) { 
  30. switch ( $type ) { 
  31. case 'hex': 
  32. $this->fromHex( $color ); 
  33. break; 
  34. case 'rgb': 
  35. if ( is_array( $color ) && count( $color ) == 3 ) { 
  36. list( $r, $g, $b ) = array_values( $color ); 
  37. $this->fromRgbInt( $r, $g, $b ); 
  38. break; 
  39. case 'hsl': 
  40. if ( is_array( $color ) && count( $color ) == 3 ) { 
  41. list( $h, $s, $l ) = array_values( $color ); 
  42. $this->fromHsl( $h, $s, $l ); 
  43. break; 
  44. case 'int': 
  45. $this->fromInt( $color ); 
  46. break; 
  47. default: 
  48. // there is no default. 
  49. break; 
  50.  
  51. /** 
  52. * Init color from hex value 
  53. * 
  54. * @param string $hexValue 
  55. * 
  56. * @return Jetpack_Color 
  57. */ 
  58. public function fromHex($hexValue) { 
  59. $hexValue = str_replace( '#', '', $hexValue ); 
  60. // handle short hex codes like #fff 
  61. if ( 3 === strlen( $hexValue ) ) { 
  62. $short = $hexValue; 
  63. $i = 0; 
  64. $hexValue = ''; 
  65. while ( $i < 3 ) { 
  66. $chunk = substr($short, $i, 1 ); 
  67. $hexValue .= $chunk . $chunk; 
  68. $i++; 
  69. $intValue = hexdec( $hexValue ); 
  70.  
  71. if ( $intValue < 0 || $intValue > 16777215 ) { 
  72. throw new RangeException( $hexValue . " out of valid color code range" ); 
  73.  
  74. $this->color = $intValue; 
  75.  
  76. return $this; 
  77.  
  78. /** 
  79. * Init color from integer RGB values 
  80. * 
  81. * @param int $red 
  82. * @param int $green 
  83. * @param int $blue 
  84. * 
  85. * @return Jetpack_Color 
  86. */ 
  87. public function fromRgbInt($red, $green, $blue) 
  88. if ( $red < 0 || $red > 255 ) 
  89. throw new RangeException( "Red value " . $red . " out of valid color code range" ); 
  90.  
  91. if ( $green < 0 || $green > 255 ) 
  92. throw new RangeException( "Green value " . $green . " out of valid color code range" ); 
  93.  
  94. if ( $blue < 0 || $blue > 255 ) 
  95. throw new RangeException( "Blue value " . $blue . " out of valid color code range" ); 
  96.  
  97. $this->color = (int)(($red << 16) + ($green << 8) + $blue); 
  98.  
  99. return $this; 
  100.  
  101. /** 
  102. * Init color from hex RGB values 
  103. * 
  104. * @param string $red 
  105. * @param string $green 
  106. * @param string $blue 
  107. * 
  108. * @return Jetpack_Color 
  109. */ 
  110. public function fromRgbHex($red, $green, $blue) 
  111. return $this->fromRgbInt(hexdec($red), hexdec($green), hexdec($blue)); 
  112.  
  113. /** 
  114. * Converts an HSL color value to RGB. Conversion formula 
  115. * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 
  116. * @param int $h Hue. [0-360] 
  117. * @param in $s Saturation [0, 100] 
  118. * @param int $l Lightness [0, 100] 
  119. */ 
  120. public function fromHsl( $h, $s, $l ) { 
  121. $h /= 360; $s /= 100; $l /= 100; 
  122.  
  123. if ( $s == 0 ) { 
  124. $r = $g = $b = $l; // achromatic 
  125. else { 
  126. $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s; 
  127. $p = 2 * $l - $q; 
  128. $r = $this->hue2rgb( $p, $q, $h + 1/3 ); 
  129. $g = $this->hue2rgb( $p, $q, $h ); 
  130. $b = $this->hue2rgb( $p, $q, $h - 1/3 ); 
  131.  
  132. return $this->fromRgbInt( $r * 255, $g * 255, $b * 255 ); 
  133.  
  134. /** 
  135. * Helper function for Jetpack_Color::fromHsl() 
  136. */ 
  137. private function hue2rgb( $p, $q, $t ) { 
  138. if ( $t < 0 ) $t += 1; 
  139. if ( $t > 1 ) $t -= 1; 
  140. if ( $t < 1/6 ) return $p + ( $q - $p ) * 6 * $t; 
  141. if ( $t < 1/2 ) return $q; 
  142. if ( $t < 2/3 ) return $p + ( $q - $p ) * ( 2/3 - $t ) * 6; 
  143. return $p; 
  144.  
  145. /** 
  146. * Init color from integer value 
  147. * 
  148. * @param int $intValue 
  149. * 
  150. * @return Jetpack_Color 
  151. */ 
  152. public function fromInt($intValue) 
  153. if ( $intValue < 0 || $intValue > 16777215 ) 
  154. throw new RangeException( $intValue . " out of valid color code range" ); 
  155.  
  156. $this->color = $intValue; 
  157.  
  158. return $this; 
  159.  
  160. /** 
  161. * Convert color to hex 
  162. * 
  163. * @return string 
  164. */ 
  165. public function toHex() 
  166. return str_pad(dechex($this->color), 6, '0', STR_PAD_LEFT); 
  167.  
  168. /** 
  169. * Convert color to RGB array (integer values) 
  170. * 
  171. * @return array 
  172. */ 
  173. public function toRgbInt() 
  174. return array( 
  175. 'red' => (int)(255 & ($this->color >> 16)),  
  176. 'green' => (int)(255 & ($this->color >> 8)),  
  177. 'blue' => (int)(255 & ($this->color)) 
  178. ); 
  179.  
  180. /** 
  181. * Convert color to RGB array (hex values) 
  182. * 
  183. * @return array 
  184. */ 
  185. public function toRgbHex() 
  186. $r = array(); 
  187. foreach ($this->toRgbInt() as $item) { 
  188. $r[] = dechex($item); 
  189. return $r; 
  190.  
  191. /** 
  192. * Get Hue/Saturation/Value for the current color 
  193. * (float values, slow but accurate) 
  194. * 
  195. * @return array 
  196. */ 
  197. public function toHsvFloat() 
  198. $rgb = $this->toRgbInt(); 
  199.  
  200. $rgbMin = min($rgb); 
  201. $rgbMax = max($rgb); 
  202.  
  203. $hsv = array( 
  204. 'hue' => 0,  
  205. 'sat' => 0,  
  206. 'val' => $rgbMax 
  207. ); 
  208.  
  209. // If v is 0, color is black 
  210. if ($hsv['val'] == 0) { 
  211. return $hsv; 
  212.  
  213. // Normalize RGB values to 1 
  214. $rgb['red'] /= $hsv['val']; 
  215. $rgb['green'] /= $hsv['val']; 
  216. $rgb['blue'] /= $hsv['val']; 
  217. $rgbMin = min($rgb); 
  218. $rgbMax = max($rgb); 
  219.  
  220. // Calculate saturation 
  221. $hsv['sat'] = $rgbMax - $rgbMin; 
  222. if ($hsv['sat'] == 0) { 
  223. $hsv['hue'] = 0; 
  224. return $hsv; 
  225.  
  226. // Normalize saturation to 1 
  227. $rgb['red'] = ($rgb['red'] - $rgbMin) / ($rgbMax - $rgbMin); 
  228. $rgb['green'] = ($rgb['green'] - $rgbMin) / ($rgbMax - $rgbMin); 
  229. $rgb['blue'] = ($rgb['blue'] - $rgbMin) / ($rgbMax - $rgbMin); 
  230. $rgbMin = min($rgb); 
  231. $rgbMax = max($rgb); 
  232.  
  233. // Calculate hue 
  234. if ($rgbMax == $rgb['red']) { 
  235. $hsv['hue'] = 0.0 + 60 * ($rgb['green'] - $rgb['blue']); 
  236. if ($hsv['hue'] < 0) { 
  237. $hsv['hue'] += 360; 
  238. } else if ($rgbMax == $rgb['green']) { 
  239. $hsv['hue'] = 120 + (60 * ($rgb['blue'] - $rgb['red'])); 
  240. } else { 
  241. $hsv['hue'] = 240 + (60 * ($rgb['red'] - $rgb['green'])); 
  242.  
  243. return $hsv; 
  244.  
  245. /** 
  246. * Get HSV values for color 
  247. * (integer values from 0-255, fast but less accurate) 
  248. * 
  249. * @return int 
  250. */ 
  251. public function toHsvInt() 
  252. $rgb = $this->toRgbInt(); 
  253.  
  254. $rgbMin = min($rgb); 
  255. $rgbMax = max($rgb); 
  256.  
  257. $hsv = array( 
  258. 'hue' => 0,  
  259. 'sat' => 0,  
  260. 'val' => $rgbMax 
  261. ); 
  262.  
  263. // If value is 0, color is black 
  264. if ($hsv['val'] == 0) { 
  265. return $hsv; 
  266.  
  267. // Calculate saturation 
  268. $hsv['sat'] = round(255 * ($rgbMax - $rgbMin) / $hsv['val']); 
  269. if ($hsv['sat'] == 0) { 
  270. $hsv['hue'] = 0; 
  271. return $hsv; 
  272.  
  273. // Calculate hue 
  274. if ($rgbMax == $rgb['red']) { 
  275. $hsv['hue'] = round(0 + 43 * ($rgb['green'] - $rgb['blue']) / ($rgbMax - $rgbMin)); 
  276. } else if ($rgbMax == $rgb['green']) { 
  277. $hsv['hue'] = round(85 + 43 * ($rgb['blue'] - $rgb['red']) / ($rgbMax - $rgbMin)); 
  278. } else { 
  279. $hsv['hue'] = round(171 + 43 * ($rgb['red'] - $rgb['green']) / ($rgbMax - $rgbMin)); 
  280. if ($hsv['hue'] < 0) { 
  281. $hsv['hue'] += 255; 
  282.  
  283. return $hsv; 
  284.  
  285. /** 
  286. * Converts an RGB color value to HSL. Conversion formula 
  287. * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 
  288. * Assumes r, g, and b are contained in the set [0, 255] and 
  289. * returns h in [0, 360], s in [0, 100], l in [0, 100] 
  290. * 
  291. * @return Array The HSL representation 
  292. */ 
  293. public function toHsl() { 
  294. list( $r, $g, $b ) = array_values( $this->toRgbInt() ); 
  295. $r /= 255; $g /= 255; $b /= 255; 
  296. $max = max( $r, $g, $b ); 
  297. $min = min( $r, $g, $b ); 
  298. $h = $s = $l = ( $max + $min ) / 2; 
  299. #var_dump( array( compact('max', 'min', 'r', 'g', 'b')) ); 
  300. if ( $max == $min ) { 
  301. $h = $s = 0; // achromatic 
  302. else { 
  303. $d = $max - $min; 
  304. $s = $l > 0.5 ? $d / ( 2 - $max - $min ) : $d / ( $max + $min ); 
  305. switch ( $max ) { 
  306. case $r: 
  307. $h = ( $g - $b ) / $d + ( $g < $b ? 6 : 0 ); 
  308. break; 
  309. case $g: 
  310. $h = ( $b - $r ) / $d + 2; 
  311. break; 
  312. case $b: 
  313. $h = ( $r - $g ) / $d + 4; 
  314. break; 
  315. $h /= 6; 
  316. $h = (int) round( $h * 360 ); 
  317. $s = (int) round( $s * 100 ); 
  318. $l = (int) round( $l * 100 ); 
  319. return compact( 'h', 's', 'l' ); 
  320.  
  321. public function toCSS( $type = 'hex', $alpha = 1 ) { 
  322. switch ( $type ) { 
  323. case 'hex': 
  324. return $this->toString(); 
  325. break; 
  326. case 'rgb': 
  327. case 'rgba': 
  328. list( $r, $g, $b ) = array_values( $this->toRgbInt() ); 
  329. if ( is_numeric( $alpha ) && $alpha < 1 ) { 
  330. return "rgba( {$r}, {$g}, {$b}, $alpha )"; 
  331. else { 
  332. return "rgb( {$r}, {$g}, {$b} )"; 
  333. break; 
  334. case 'hsl': 
  335. case 'hsla': 
  336. list( $h, $s, $l ) = array_values( $this->toHsl() ); 
  337. if ( is_numeric( $alpha ) && $alpha < 1 ) { 
  338. return "hsla( {$h}, {$s}, {$l}, $alpha )"; 
  339. else { 
  340. return "hsl( {$h}, {$s}, {$l} )"; 
  341. break; 
  342. default: 
  343. return $this->toString(); 
  344. break; 
  345.  
  346. /** 
  347. * Get current color in XYZ format 
  348. * 
  349. * @return array 
  350. */ 
  351. public function toXyz() 
  352. $rgb = $this->toRgbInt(); 
  353.  
  354. // Normalize RGB values to 1 
  355.  
  356. $rgb_new = array(); 
  357. foreach ($rgb as $item) { 
  358. $rgb_new[] = $item / 255; 
  359. $rgb = $rgb_new; 
  360.  
  361. $rgb_new = array(); 
  362. foreach ($rgb as $item) { 
  363. if ($item > 0.04045) { 
  364. $item = pow((($item + 0.055) / 1.055), 2.4); 
  365. } else { 
  366. $item = $item / 12.92; 
  367. $rgb_new[] = $item * 100; 
  368. $rgb = $rgb_new; 
  369.  
  370. //Observer. = 2*, Illuminant = D65 
  371. $xyz = array( 
  372. 'x' => ($rgb['red'] * 0.4124) + ($rgb['green'] * 0.3576) + ($rgb['blue'] * 0.1805),  
  373. 'y' => ($rgb['red'] * 0.2126) + ($rgb['green'] * 0.7152) + ($rgb['blue'] * 0.0722),  
  374. 'z' => ($rgb['red'] * 0.0193) + ($rgb['green'] * 0.1192) + ($rgb['blue'] * 0.9505) 
  375. ); 
  376.  
  377. return $xyz; 
  378.  
  379. /** 
  380. * Get color CIE-Lab values 
  381. * 
  382. * @return array 
  383. */ 
  384. public function toLabCie() 
  385. $xyz = $this->toXyz(); 
  386.  
  387. //Ovserver = 2*, Iluminant=D65 
  388. $xyz['x'] /= 95.047; 
  389. $xyz['y'] /= 100; 
  390. $xyz['z'] /= 108.883; 
  391.  
  392. $xyz_new = array(); 
  393. foreach ($xyz as $item) { 
  394. if ($item > 0.008856) { 
  395. $xyz_new[] = pow($item, 1/3); 
  396. } else { 
  397. $xyz_new[] = (7.787 * $item) + (16 / 116); 
  398. $xyz = $xyz_new; 
  399.  
  400. $lab = array( 
  401. 'l' => (116 * $xyz['y']) - 16,  
  402. 'a' => 500 * ($xyz['x'] - $xyz['y']),  
  403. 'b' => 200 * ($xyz['y'] - $xyz['z']) 
  404. ); 
  405.  
  406. return $lab; 
  407.  
  408. /** 
  409. * Convert color to integer 
  410. * 
  411. * @return int 
  412. */ 
  413. public function toInt() 
  414. return $this->color; 
  415.  
  416. /** 
  417. * Alias of toString() 
  418. * 
  419. * @return string 
  420. */ 
  421. public function __toString() 
  422. return $this->toString(); 
  423.  
  424. /** 
  425. * Get color as string 
  426. * 
  427. * @return string 
  428. */ 
  429. public function toString() 
  430. $str = $this->toHex(); 
  431. return strtoupper("#{$str}"); 
  432.  
  433. /** 
  434. * Get the distance between this color and the given color 
  435. * 
  436. * @param Jetpack_Color $color 
  437. * 
  438. * @return int 
  439. */ 
  440. public function getDistanceRgbFrom(Jetpack_Color $color) 
  441. $rgb1 = $this->toRgbInt(); 
  442. $rgb2 = $color->toRgbInt(); 
  443.  
  444. $rDiff = abs($rgb1['red'] - $rgb2['red']); 
  445. $gDiff = abs($rgb1['green'] - $rgb2['green']); 
  446. $bDiff = abs($rgb1['blue'] - $rgb2['blue']); 
  447.  
  448. // Sum of RGB differences 
  449. $diff = $rDiff + $gDiff + $bDiff; 
  450. return $diff; 
  451.  
  452. /** 
  453. * Get distance from the given color using the Delta E method 
  454. * 
  455. * @param Jetpack_Color $color 
  456. * 
  457. * @return float 
  458. */ 
  459. public function getDistanceLabFrom(Jetpack_Color $color) 
  460. $lab1 = $this->toLabCie(); 
  461. $lab2 = $color->toLabCie(); 
  462.  
  463. $lDiff = abs($lab2['l'] - $lab1['l']); 
  464. $aDiff = abs($lab2['a'] - $lab1['a']); 
  465. $bDiff = abs($lab2['b'] - $lab1['b']); 
  466.  
  467. $delta = sqrt($lDiff + $aDiff + $bDiff); 
  468.  
  469. return $delta; 
  470.  
  471. public function toLuminosity() { 
  472. extract( $this->toRgbInt() ); 
  473. return 0.2126 * pow( $red / 255, 2.2 ) + 0.7152 * pow( $green / 255, 2.2 ) + 0.0722 * pow( $blue / 255, 2.2); 
  474.  
  475. /** 
  476. * Get distance between colors using luminance. 
  477. * Should be more than 5 for readable contrast 
  478. * 
  479. * @param Jetpack_Color $color Another color 
  480. * @return float 
  481. */ 
  482. public function getDistanceLuminosityFrom(Jetpack_Color $color) { 
  483. $L1 = $this->toLuminosity(); 
  484. $L2 = $color->toLuminosity(); 
  485. if ( $L1 > $L2 ) { 
  486. return ( $L1 + 0.05 ) / ( $L2 + 0.05 ); 
  487. else{ 
  488. return ( $L2 + 0.05 ) / ( $L1 + 0.05 ); 
  489.  
  490. public function getMaxContrastColor() { 
  491. $lum = $this->toLuminosity(); 
  492. $color = new Jetpack_Color; 
  493. $hex = ( $lum >= 0.5 ) ? '000000' : 'ffffff'; 
  494. return $color->fromHex( $hex ); 
  495.  
  496. public function getGrayscaleContrastingColor( $contrast = false ) { 
  497. if ( ! $contrast ) { 
  498. return $this->getMaxContrastColor(); 
  499. // don't allow less than 5 
  500. $target_contrast = ( $contrast < 5 ) ? 5 : $contrast; 
  501. $color = $this->getMaxContrastColor(); 
  502. $contrast = $color->getDistanceLuminosityFrom( $this ); 
  503.  
  504. // if current max contrast is less than the target contrast, we had wishful thinking. 
  505. if ( $contrast <= $target_contrast ) { 
  506. return $color; 
  507.  
  508. $incr = ( '#000000' === $color->toString() ) ? 1 : -1; 
  509. while ( $contrast > $target_contrast ) { 
  510. $color = $color->incrementLightness( $incr ); 
  511. $contrast = $color->getDistanceLuminosityFrom( $this ); 
  512.  
  513. return $color; 
  514.  
  515. /** 
  516. * Gets a readable contrasting color. $this is assumed to be the text and $color the background color. 
  517. * @param object $bg_color A Color object that will be compared against $this 
  518. * @param integer $min_contrast The minimum contrast to achieve, if possible. 
  519. * @return object A Color object, an increased contrast $this compared against $bg_color 
  520. */ 
  521. public function getReadableContrastingColor( $bg_color = false, $min_contrast = 5 ) { 
  522. if ( ! $bg_color || ! is_a( $bg_color, 'Jetpack_Color' ) ) { 
  523. return $this; 
  524. // you shouldn't use less than 5, but you might want to. 
  525. $target_contrast = $min_contrast; 
  526. // working things 
  527. $contrast = $bg_color->getDistanceLuminosityFrom( $this ); 
  528. $max_contrast_color = $bg_color->getMaxContrastColor(); 
  529. $max_contrast = $max_contrast_color->getDistanceLuminosityFrom( $bg_color ); 
  530.  
  531. // if current max contrast is less than the target contrast, we had wishful thinking. 
  532. // still, go max 
  533. if ( $max_contrast <= $target_contrast ) { 
  534. return $max_contrast_color; 
  535. // or, we might already have sufficient contrast 
  536. if ( $contrast >= $target_contrast ) { 
  537. return $this; 
  538.  
  539. $incr = ( 0 === $max_contrast_color->toInt() ) ? -1 : 1; 
  540. while ( $contrast < $target_contrast ) { 
  541. $this->incrementLightness( $incr ); 
  542. $contrast = $bg_color->getDistanceLuminosityFrom( $this ); 
  543. // infininite loop prevention: you never know. 
  544. if ( $this->color === 0 || $this->color === 16777215 ) { 
  545. break; 
  546.  
  547. return $this; 
  548.  
  549. /** 
  550. * Detect if color is grayscale 
  551. * 
  552. * @param int @threshold 
  553. * 
  554. * @return bool 
  555. */ 
  556. public function isGrayscale($threshold = 16) 
  557. $rgb = $this->toRgbInt(); 
  558.  
  559. // Get min and max rgb values, then difference between them 
  560. $rgbMin = min($rgb); 
  561. $rgbMax = max($rgb); 
  562. $diff = $rgbMax - $rgbMin; 
  563.  
  564. return $diff < $threshold; 
  565.  
  566. /** 
  567. * Get the closest matching color from the given array of colors 
  568. * 
  569. * @param array $colors array of integers or Jetpack_Color objects 
  570. * 
  571. * @return mixed the array key of the matched color 
  572. */ 
  573. public function getClosestMatch(array $colors) 
  574. $matchDist = 10000; 
  575. $matchKey = null; 
  576. foreach($colors as $key => $color) { 
  577. if (false === ($color instanceof Jetpack_Color)) { 
  578. $c = new Jetpack_Color($color); 
  579. $dist = $this->getDistanceLabFrom($c); 
  580. if ($dist < $matchDist) { 
  581. $matchDist = $dist; 
  582. $matchKey = $key; 
  583.  
  584. return $matchKey; 
  585.  
  586. /** TRANSFORMS */ 
  587.  
  588. public function darken( $amount = 5 ) { 
  589. return $this->incrementLightness( - $amount ); 
  590.  
  591. public function lighten( $amount = 5 ) { 
  592. return $this->incrementLightness( $amount ); 
  593.  
  594. public function incrementLightness( $amount ) { 
  595. $hsl = $this->toHsl(); 
  596. extract( $hsl ); 
  597. $l += $amount; 
  598. if ( $l < 0 ) $l = 0; 
  599. if ( $l > 100 ) $l = 100; 
  600. return $this->fromHsl( $h, $s, $l ); 
  601.  
  602. public function saturate( $amount = 15 ) { 
  603. return $this->incrementSaturation( $amount ); 
  604.  
  605. public function desaturate( $amount = 15 ) { 
  606. return $this->incrementSaturation( - $amount ); 
  607.  
  608. public function incrementSaturation( $amount ) { 
  609. $hsl = $this->toHsl(); 
  610. extract( $hsl ); 
  611. $s += $amount; 
  612. if ( $s < 0 ) $s = 0; 
  613. if ( $s > 100 ) $s = 100; 
  614. return $this->fromHsl( $h, $s, $l ); 
  615.  
  616. public function toGrayscale() { 
  617. $hsl = $this->toHsl(); 
  618. extract( $hsl ); 
  619. $s = 0; 
  620. return $this->fromHsl( $h, $s, $l ); 
  621.  
  622. public function getComplement() { 
  623. return $this->incrementHue( 180 ); 
  624.  
  625. public function getSplitComplement( $step = 1 ) { 
  626. $incr = 180 + ( $step * 30 ); 
  627. return $this->incrementHue( $incr ); 
  628.  
  629. public function getAnalog( $step = 1 ) { 
  630. $incr = $step * 30; 
  631. return $this->incrementHue( $incr ); 
  632.  
  633. public function getTetrad( $step = 1 ) { 
  634. $incr = $step * 60; 
  635. return $this->incrementHue( $incr ); 
  636.  
  637. public function getTriad( $step = 1 ) { 
  638. $incr = $step * 120; 
  639. return $this->incrementHue( $incr ); 
  640.  
  641. public function incrementHue( $amount ) { 
  642. $hsl = $this->toHsl(); 
  643. extract( $hsl ); 
  644. $h = ( $h + $amount ) % 360; 
  645. if ( $h < 0 ) $h = 360 - $h; 
  646. return $this->fromHsl( $h, $s, $l ); 
  647.  
  648. } // class Jetpack_Color 
.