/** * Shift a given color, using a reference pair and a target blend color. * * Note: this function is significantly different from the JS version, as it * is written to match the blended images perfectly. * * Constraint: if (ref2 == target + (ref1 - target) * delta) for some fraction delta * then (return == target + (given - target) * delta) * * Loose constraint: Preserve relative positions in saturation and luminance * space. */ function _color_shift($given, $ref1, $ref2, $target) { // We assume that ref2 is a blend of ref1 and target and find // delta based on the length of the difference vectors: // delta = 1 - |ref2 - ref1| / |white - ref1| $target = _color_unpack($target, true); $ref1 = _color_unpack($ref1, true); $ref2 = _color_unpack($ref2, true); for ($i = 0; $i < 3; ++$i) { $numerator += ($ref2[$i] - $ref1[$i]) * ($ref2[$i] - $ref1[$i]); $denominator += ($target[$i] - $ref1[$i]) * ($target[$i] - $ref1[$i]); } $delta = $denominator > 0 ? 1 - sqrt($numerator / $denominator) : 0; // Calculate the color that ref2 would be if the assumption was true. for ($i = 0; $i < 3; ++$i) { $ref3[$i] = $target[$i] + ($ref1[$i] - $target[$i]) * $delta; } // If the assumption is not true, there is a difference between ref2 and ref3. // We measure this in HSL space. Notation: x' = hsl(x). $ref2 = _color_rgb2hsl($ref2); $ref3 = _color_rgb2hsl($ref3); for ($i = 0; $i < 3; ++$i) { $shift[$i] = $ref2[$i] - $ref3[$i]; } // Take the given color, and blend it towards the target. $given = _color_unpack($given, true); for ($i = 0; $i < 3; ++$i) { $result[$i] = $target[$i] + ($given[$i] - $target[$i]) * $delta; } // Finally, we apply the extra shift in HSL space. // Note: if ref2 is a pure blend of ref1 and target, then |shift| = 0. $result = _color_rgb2hsl($result); for ($i = 0; $i < 3; ++$i) { $result[$i] = min(1, max(0, $result[$i] + $shift[$i])); } $result = _color_hsl2rgb($result); // Return hex color. return _color_pack($result, true); }
/** * Preprocessor for theme_spaces_design(). */ function ginkgo_preprocess_spaces_design(&$vars) { if (module_exists('color') && !empty($vars['color'])) { if ($rgb = _color_unpack($vars['color'], TRUE)) { $classes = context_get('theme', 'body_classes'); $classes .= ' color'; context_set('theme', 'body_classes', $classes); $hsl = _color_rgb2hsl($rgb); if ($hsl[2] > 0.8) { $hsl[2] = 0.7; $rgb = _color_hsl2rgb($hsl); } // This code generates color values that are blended against // Black/White -- IT DOES NOT PRESERVE SATURATION. $modifiers = array('upshift' => $hsl[2] < 0.25 ? array('+', 0.1) : array('+', 0.25), 'downshift' => array('-', 0.38)); foreach ($modifiers as $id => $modifier) { $color = $rgb; foreach ($rgb as $k => $v) { switch ($modifier[0]) { case '-': $color[$k] = $color[$k] * (1 - $modifier[1]); break; default: $color[$k] = $color[$k] + (1 - $color[$k]) * $modifier[1]; break; } } $vars[$id] = _color_pack($color, TRUE); } $vars['color'] = _color_pack($rgb, TRUE); } } }
/** * Autohift colors in HSL color space * @param color * CSS hex color to be shifted (e.g. #000000 ) * @param $X_min * Hue/Saturation/Lightness minimum value, normalized to a fraction of 1 * @param $X_max * Hue/Saturation/Lightness maximum value, normalized to a fraction of 1 * @return a string containing a CSS hexcolor (e.g. #000000 ) */ function color_autoshift($color, $min_h, $max_h, $min_s, $max_s, $min_l, $max_l) { $newcolor = _color_unpack($color, TRUE); // hex to RGB $newcolor = _color_rgb2hsl($newcolor); // RGB to HSL if ($min_h) { if ($newcolor[0] < $min_h) { $newcolor[0] = $min_h; } } if ($max_h) { if ($newcolor[0] > $max_h) { $newcolor[0] = $max_h; } } if ($min_s) { if ($newcolor[1] < $min_s) { $newcolor[1] = $min_s; } } if ($max_s) { if ($newcolor[1] > $max_s) { $newcolor[1] = $max_s; } } if ($min_l) { if ($newcolor[2] < $min_l) { $newcolor[2] = $min_l; } } if ($max_l) { if ($newcolor[2] > $max_l) { $newcolor[2] = $max_l; } } $newcolor = _color_hsl2rgb($newcolor); // Back to RGB $newcolor = _color_pack($newcolor, TRUE); // RGB back to hex return $newcolor; }