/[drupal]/drupal/modules/color/color.module
ViewVC logotype

Contents of /drupal/modules/color/color.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.76 - (show annotations) (download) (as text)
Wed Nov 4 05:39:14 2009 UTC (3 weeks, 3 days ago) by webchick
Branch: MAIN
CVS Tags: DRUPAL-7-0-UNSTABLE-10
Changes since 1.75: +2 -3 lines
File MIME type: text/x-php
#571086 follow-up by sun: Allow specifying a 'wrapper callback' before executing a form builder function.
1 <?php
2 // $Id: color.module,v 1.75 2009/11/04 04:56:54 webchick Exp $
3
4 /**
5 * Implement hook_help().
6 */
7 function color_help($path, $arg) {
8 switch ($path) {
9 case 'admin/help#color':
10 $output = '<p>' . t('The color module allows a site administrator to quickly and easily change the color scheme of certain themes. Although not all themes support color module, both Garland (the default theme) and Minnelli were designed to take advantage of its features. By using color module with a compatible theme, you can easily change the color of links, backgrounds, text, and other theme elements.', array('@url' => url('admin/config/media/file-system'))) . '</p>';
11 $output .= '<p>' . t("It is important to remember that color module saves a modified copy of the theme's specified stylesheets in the files directory. This means that if you make any manual changes to your theme's stylesheet, you must save your color settings again, even if they haven't changed. This causes the color module generated version of the stylesheets in the files directory to be recreated using the new version of the original file.") . '</p>';
12 $output .= '<p>' . t('To change the color settings for a compatible theme, select the "configure" link for the theme on the <a href="@themes">themes administration page</a>.', array('@themes' => url('admin/appearance'))) . '</p>';
13 $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@color">Color module</a>.', array('@color' => 'http://drupal.org/handbook/modules/color/')) . '</p>';
14
15 return $output;
16 }
17 }
18
19 /**
20 * Implement hook_theme().
21 */
22 function color_theme() {
23 return array(
24 'color_scheme_form' => array(
25 'render element' => 'form',
26 ),
27 );
28 }
29
30 /**
31 * Implement hook_form_FORM_ID_alter().
32 */
33 function color_form_system_theme_settings_alter(&$form, &$form_state) {
34 if (isset($form_state['build_info']['args'][0]) && ($theme = $form_state['build_info']['args'][0]) && color_get_info($theme) && function_exists('gd_info')) {
35 $form['color'] = array(
36 '#type' => 'fieldset',
37 '#title' => t('Color scheme'),
38 '#weight' => -1,
39 '#attributes' => array('id' => 'color_scheme_form'),
40 '#theme' => 'color_scheme_form',
41 );
42 $form['color'] += color_scheme_form($form, $form_state, $theme);
43 $form['#submit'][] = 'color_scheme_form_submit';
44 }
45 }
46
47 /**
48 * Implement hook_form_FORM_ID_alter().
49 */
50 function color_form_system_themes_alter(&$form, &$form_state) {
51 _color_theme_select_form_alter($form, $form_state);
52 }
53
54 /**
55 * Helper for hook_form_FORM_ID_alter() implementations.
56 */
57 function _color_theme_select_form_alter(&$form, &$form_state) {
58 // Use the generated screenshot in the theme list.
59 $themes = list_themes();
60 foreach (element_children($form) as $theme) {
61 if ($screenshot = variable_get('color_' . $theme . '_screenshot')) {
62 if (isset($form[$theme]['screenshot'])) {
63 $form[$theme]['screenshot']['#markup'] = theme('image', array('path' => $screenshot, 'alt' => '', 'title' => '', 'attributes' => array('class' => array('screenshot')), 'getsize' => FALSE));
64 }
65 }
66 }
67 }
68
69 /**
70 * Callback for the theme to alter the resources used.
71 */
72 function _color_html_alter(&$vars) {
73 global $language, $theme_key;
74 $themes = list_themes();
75
76 // Override stylesheets.
77 $color_paths = variable_get('color_' . $theme_key . '_stylesheets', array());
78 if (!empty($color_paths)) {
79
80 foreach ($themes[$theme_key]->stylesheets['all'] as $base_filename => $old_path) {
81 // Loop over the path array with recolored CSS files to find matching
82 // paths which could replace the non-recolored paths.
83 foreach ($color_paths as $color_path) {
84 // Color module currently requires unique file names to be used,
85 // which allows us to compare different file paths.
86 if (basename($old_path) == basename($color_path)) {
87 // Replace the path to the new css file.
88 // This keeps the order of the stylesheets intact.
89 $vars['css'][$old_path]['data'] = $color_path;
90 }
91 }
92 }
93
94 $vars['styles'] = drupal_get_css($vars['css']);
95 }
96 }
97
98 /**
99 * Callback for the theme to alter the resources used.
100 */
101 function _color_page_alter(&$vars) {
102 global $language, $theme_key;
103
104 // Override logo.
105 $logo = variable_get('color_' . $theme_key . '_logo');
106 if ($logo && $vars['logo'] && preg_match('!' . $theme_key . '/logo.png$!', $vars['logo'])) {
107 $vars['logo'] = base_path() . $logo;
108 }
109 }
110
111 /**
112 * Retrieve the color.module info for a particular theme.
113 */
114 function color_get_info($theme) {
115 $path = drupal_get_path('theme', $theme);
116 $file = DRUPAL_ROOT . '/' . $path . '/color/color.inc';
117 if ($path && file_exists($file)) {
118 include $file;
119 return $info;
120 }
121 }
122
123 /**
124 * Helper function to retrieve the color palette for a particular theme.
125 */
126 function color_get_palette($theme, $default = FALSE) {
127 // Fetch and expand default palette.
128 $fields = array('base', 'link', 'top', 'bottom', 'text');
129 $info = color_get_info($theme);
130 $keys = array_keys($info['schemes']);
131 foreach (explode(',', array_shift($keys)) as $k => $scheme) {
132 $palette[$fields[$k]] = $scheme;
133 }
134
135 // Load variable.
136 return $default ? $palette : variable_get('color_' . $theme . '_palette', $palette);
137 }
138
139 /**
140 * Form callback. Returns the configuration form.
141 */
142 function color_scheme_form($complete_form, &$form_state, $theme) {
143 $base = drupal_get_path('module', 'color');
144 $info = color_get_info($theme);
145
146 // See if we're using a predefined scheme.
147 $current = implode(',', variable_get('color_' . $theme . '_palette', array()));
148 // Note: we use the original theme when the default scheme is chosen.
149 $current = isset($info['schemes'][$current]) ? $current : ($current == '' ? reset($info['schemes']) : '');
150
151 // Add scheme selector.
152 $info['schemes'][''] = t('Custom');
153 $form['scheme'] = array(
154 '#type' => 'select',
155 '#title' => t('Color set'),
156 '#options' => $info['schemes'],
157 '#default_value' => $current,
158 '#attached' => array(
159 // Add Farbtastic color picker.
160 'library' => array(
161 array('system', 'farbtastic'),
162 ),
163 // Add custom CSS.
164 'css' => array(
165 $base . '/color.css' => array('preprocess' => FALSE),
166 ),
167 // Add custom JavaScript.
168 'js' => array(
169 $base . '/color.js',
170 array(
171 'data' => array(
172 'color' => array('reference' => color_get_palette($theme, TRUE)),
173 ),
174 'type' => 'setting',
175 ),
176 ),
177 ),
178 );
179
180 // Add palette fields.
181 $palette = color_get_palette($theme);
182 $names = array(
183 'base' => t('Base color'),
184 'link' => t('Link color'),
185 'top' => t('Header top'),
186 'bottom' => t('Header bottom'),
187 'text' => t('Text color'),
188 );
189 $form['palette']['#tree'] = TRUE;
190 foreach ($palette as $name => $value) {
191 $form['palette'][$name] = array(
192 '#type' => 'textfield',
193 '#title' => $names[$name],
194 '#default_value' => $value,
195 '#size' => 8,
196 );
197 }
198 $form['theme'] = array('#type' => 'value', '#value' => $theme);
199 $form['info'] = array('#type' => 'value', '#value' => $info);
200
201 return $form;
202 }
203
204 /**
205 * Theme the color form.
206 *
207 * @ingroup themeable
208 */
209 function theme_color_scheme_form($variables) {
210 $form = $variables['form'];
211
212 $theme = $form['theme']['#value'];
213 $info = $form['info']['#value'];
214 $path = drupal_get_path('theme', $theme) . '/';
215 drupal_add_css($path . $info['preview_css']);
216
217 $output = '';
218 $output .= '<div class="color-form clearfix">';
219 // Color schemes
220 $output .= drupal_render($form['scheme']);
221 // Palette
222 $output .= '<div id="palette" class="clearfix">';
223 foreach (element_children($form['palette']) as $name) {
224 $output .= drupal_render($form['palette'][$name]);
225 }
226 $output .= '</div>';
227 // Preview
228 $output .= drupal_render_children($form);
229 $output .= '<h2>' . t('Preview') . '</h2>';
230 $output .= '<div id="preview"><div id="text"><h2>Lorem ipsum dolor</h2><p>Sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud <a href="#">exercitation ullamco</a> laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div><div id="img" style="background-image: url(' . base_path() . $path . $info['preview_image'] . ')"></div></div>';
231 // Close the wrapper div.
232 $output .= '</div>';
233
234 return $output;
235 }
236
237 /**
238 * Submit handler for color change form.
239 */
240 function color_scheme_form_submit($form, &$form_state) {
241 // Get theme coloring info.
242 if (!isset($form_state['values']['info'])) {
243 return;
244 }
245 $theme = $form_state['values']['theme'];
246 $info = $form_state['values']['info'];
247
248 // Resolve palette.
249 $palette = $form_state['values']['palette'];
250 if ($form_state['values']['scheme'] != '') {
251 $scheme = explode(',', $form_state['values']['scheme']);
252 foreach ($palette as $k => $color) {
253 $palette[$k] = array_shift($scheme);
254 }
255 }
256
257 // Make sure enough memory is available, if PHP's memory limit is compiled in.
258 if (function_exists('memory_get_usage')) {
259 // Fetch source image dimensions.
260 $source = drupal_get_path('theme', $theme) . '/' . $info['base_image'];
261 list($width, $height) = getimagesize($source);
262
263 // We need at least a copy of the source and a target buffer of the same
264 // size (both at 32bpp).
265 $required = $width * $height * 8;
266 $usage = memory_get_usage();
267 $limit = parse_size(ini_get('memory_limit'));
268 if ($usage + $required > $limit) {
269 drupal_set_message(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size more. Check the <a href="@url">PHP documentation</a> for more information.', array('%size' => format_size($usage + $required - $limit), '@url' => 'http://www.php.net/manual/ini.core.php#ini.sect.resource-limits')), 'error');
270 return;
271 }
272 }
273
274 // Delete old files.
275 foreach (variable_get('color_' . $theme . '_files', array()) as $file) {
276 @unlink($file);
277 }
278 if (isset($file) && $file = dirname($file)) {
279 @rmdir($file);
280 }
281
282 // Don't render the default colorscheme, use the standard theme instead.
283 if (implode(',', color_get_palette($theme, TRUE)) == implode(',', $palette)) {
284 variable_del('color_' . $theme . '_palette');
285 variable_del('color_' . $theme . '_stylesheets');
286 variable_del('color_' . $theme . '_logo');
287 variable_del('color_' . $theme . '_files');
288 variable_del('color_' . $theme . '_screenshot');
289 return;
290 }
291
292 // Prepare target locations for generated files.
293 $id = $theme . '-' . substr(md5(serialize($palette) . microtime()), 0, 8);
294 $paths['color'] = 'public://color';
295 $paths['target'] = $paths['color'] . '/' . $id;
296 foreach ($paths as $path) {
297 file_prepare_directory($path, FILE_CREATE_DIRECTORY);
298 }
299 $paths['target'] = $paths['target'] . '/';
300 $paths['id'] = $id;
301 $paths['source'] = drupal_get_path('theme', $theme) . '/';
302 $paths['files'] = $paths['map'] = array();
303
304 // Save palette and logo location.
305 variable_set('color_' . $theme . '_palette', $palette);
306 variable_set('color_' . $theme . '_logo', $paths['target'] . 'logo.png');
307
308 // Copy over neutral images.
309 foreach ($info['copy'] as $file) {
310 $base = basename($file);
311 $source = $paths['source'] . $file;
312 $filepath = file_unmanaged_copy($source, $paths['target'] . $base);
313 $paths['map'][$file] = $base;
314 $paths['files'][] = $filepath;
315 }
316
317 // Render new images, if image has been provided.
318 if ($info['base_image']) {
319 _color_render_images($theme, $info, $paths, $palette);
320 }
321
322 // Rewrite theme stylesheets.
323 $css = array();
324 foreach ($info['css'] as $stylesheet) {
325 // Build a temporary array with LTR and RTL files.
326 $files = array();
327 if (file_exists($paths['source'] . $stylesheet)) {
328 $files[] = $stylesheet;
329
330 $rtl_file = str_replace('.css', '-rtl.css', $stylesheet);
331 if (file_exists($paths['source'] . $rtl_file)) {
332 $files[] = $rtl_file;
333 }
334 }
335
336 foreach ($files as $file) {
337 // Aggregate @imports recursively for each configured top level CSS file
338 // without optimization. Aggregation and optimization will be
339 // handled by drupal_build_css_cache() only.
340 $style = drupal_load_stylesheet($paths['source'] . $file, FALSE);
341
342 // Return the path to where this CSS file originated from, stripping
343 // off the name of the file at the end of the path.
344 $base = base_path() . dirname($paths['source'] . $file) . '/';
345 _drupal_build_css_path(NULL, $base);
346
347 // Prefix all paths within this CSS file, ignoring absolute paths.
348 $style = preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_drupal_build_css_path', $style);
349
350 // Rewrite stylesheet with new colors.
351 $style = _color_rewrite_stylesheet($theme, $info, $paths, $palette, $style);
352 $base_file = basename($file);
353 $css[] = $paths['target'] . $base_file;
354 _color_save_stylesheet($paths['target'] . $base_file, $style, $paths);
355 }
356 }
357
358 // Maintain list of files.
359 variable_set('color_' . $theme . '_stylesheets', $css);
360 variable_set('color_' . $theme . '_files', $paths['files']);
361 }
362
363 /**
364 * Rewrite the stylesheet to match the colors in the palette.
365 */
366 function _color_rewrite_stylesheet($theme, &$info, &$paths, $palette, $style) {
367 $themes = list_themes();
368 // Prepare color conversion table.
369 $conversion = $palette;
370 unset($conversion['base']);
371 foreach ($conversion as $k => $v) {
372 $conversion[$k] = drupal_strtolower($v);
373 }
374 $default = color_get_palette($theme, TRUE);
375
376 // Split off the "Don't touch" section of the stylesheet.
377 $split = "Color Module: Don't touch";
378 if (strpos($style, $split) !== FALSE) {
379 list($style, $fixed) = explode($split, $style);
380 }
381
382 // Find all colors in the stylesheet and the chunks in between.
383 $style = preg_split('/(#[0-9a-f]{6}|#[0-9a-f]{3})/i', $style, -1, PREG_SPLIT_DELIM_CAPTURE);
384 $is_color = FALSE;
385 $output = '';
386 $base = 'base';
387
388 // Iterate over all the parts.
389 foreach ($style as $chunk) {
390 if ($is_color) {
391 $chunk = drupal_strtolower($chunk);
392 // Check if this is one of the colors in the default palette.
393 if ($key = array_search($chunk, $default)) {
394 $chunk = $conversion[$key];
395 }
396 // Not a pre-set color. Extrapolate from the base.
397 else {
398 $chunk = _color_shift($palette[$base], $default[$base], $chunk, $info['blend_target']);
399 }
400 }
401 else {
402 // Determine the most suitable base color for the next color.
403
404 // 'a' declarations. Use link.
405 if (preg_match('@[^a-z0-9_-](a)[^a-z0-9_-][^/{]*{[^{]+$@i', $chunk)) {
406 $base = 'link';
407 }
408 // 'color:' styles. Use text.
409 elseif (preg_match('/(?<!-)color[^{:]*:[^{#]*$/i', $chunk)) {
410 $base = 'text';
411 }
412 // Reset back to base.
413 else {
414 $base = 'base';
415 }
416 }
417 $output .= $chunk;
418 $is_color = !$is_color;
419 }
420 // Append fixed colors segment.
421 if (isset($fixed)) {
422 $output .= $fixed;
423 }
424
425 // Replace paths to images.
426 foreach ($paths['map'] as $before => $after) {
427 $before = base_path() . $paths['source'] . $before;
428 $before = preg_replace('`(^|/)(?!../)([^/]+)/../`', '$1', $before);
429 $output = str_replace($before, $after, $output);
430 }
431
432 return $output;
433 }
434
435 /**
436 * Save the rewritten stylesheet to disk.
437 */
438 function _color_save_stylesheet($file, $style, &$paths) {
439 $filepath = file_unmanaged_save_data($style, $file, FILE_EXISTS_REPLACE);
440 $paths['files'][] = $filepath;
441
442 // Set standard file permissions for webserver-generated files.
443 drupal_chmod($file);
444 }
445
446 /**
447 * Render images that match a given palette.
448 */
449 function _color_render_images($theme, &$info, &$paths, $palette) {
450
451 // Prepare template image.
452 $source = $paths['source'] . '/' . $info['base_image'];
453 $source = imagecreatefrompng($source);
454 $width = imagesx($source);
455 $height = imagesy($source);
456
457 // Prepare target buffer.
458 $target = imagecreatetruecolor($width, $height);
459 imagealphablending($target, TRUE);
460
461 // Fill regions of solid color.
462 foreach ($info['fill'] as $color => $fill) {
463 imagefilledrectangle($target, $fill[0], $fill[1], $fill[0] + $fill[2], $fill[1] + $fill[3], _color_gd($target, $palette[$color]));
464 }
465
466 // Render gradient.
467 for ($y = 0; $y < $info['gradient'][3]; ++$y) {
468 $color = _color_blend($target, $palette['top'], $palette['bottom'], $y / ($info['gradient'][3] - 1));
469 imagefilledrectangle($target, $info['gradient'][0], $info['gradient'][1] + $y, $info['gradient'][0] + $info['gradient'][2], $info['gradient'][1] + $y + 1, $color);
470 }
471
472 // Blend over template.
473 imagecopy($target, $source, 0, 0, 0, 0, $width, $height);
474
475 // Clean up template image.
476 imagedestroy($source);
477
478 // Cut out slices.
479 foreach ($info['slices'] as $file => $coord) {
480 list($x, $y, $width, $height) = $coord;
481 $base = basename($file);
482 $image = drupal_realpath($paths['target'] . $base);
483
484 // Cut out slice.
485 if ($file == 'screenshot.png') {
486 $slice = imagecreatetruecolor(150, 90);
487 imagecopyresampled($slice, $target, 0, 0, $x, $y, 150, 90, $width, $height);
488 variable_set('color_' . $theme . '_screenshot', $image);
489 }
490 else {
491 $slice = imagecreatetruecolor($width, $height);
492 imagecopy($slice, $target, 0, 0, $x, $y, $width, $height);
493 }
494
495 // Save image.
496 imagepng($slice, $image);
497 imagedestroy($slice);
498 $paths['files'][] = $image;
499
500 // Set standard file permissions for webserver-generated files
501 drupal_chmod($image);
502
503 // Build before/after map of image paths.
504 $paths['map'][$file] = $base;
505 }
506
507 // Clean up target buffer.
508 imagedestroy($target);
509 }
510
511 /**
512 * Shift a given color, using a reference pair and a target blend color.
513 *
514 * Note: this function is significantly different from the JS version, as it
515 * is written to match the blended images perfectly.
516 *
517 * Constraint: if (ref2 == target + (ref1 - target) * delta) for some fraction delta
518 * then (return == target + (given - target) * delta)
519 *
520 * Loose constraint: Preserve relative positions in saturation and luminance
521 * space.
522 */
523 function _color_shift($given, $ref1, $ref2, $target) {
524 // We assume that ref2 is a blend of ref1 and target and find
525 // delta based on the length of the difference vectors.
526
527 // delta = 1 - |ref2 - ref1| / |white - ref1|
528 $target = _color_unpack($target, TRUE);
529 $ref1 = _color_unpack($ref1, TRUE);
530 $ref2 = _color_unpack($ref2, TRUE);
531 $numerator = 0;
532 $denominator = 0;
533 for ($i = 0; $i < 3; ++$i) {
534 $numerator += ($ref2[$i] - $ref1[$i]) * ($ref2[$i] - $ref1[$i]);
535 $denominator += ($target[$i] - $ref1[$i]) * ($target[$i] - $ref1[$i]);
536 }
537 $delta = ($denominator > 0) ? (1 - sqrt($numerator / $denominator)) : 0;
538
539 // Calculate the color that ref2 would be if the assumption was true.
540 for ($i = 0; $i < 3; ++$i) {
541 $ref3[$i] = $target[$i] + ($ref1[$i] - $target[$i]) * $delta;
542 }
543
544 // If the assumption is not true, there is a difference between ref2 and ref3.
545 // We measure this in HSL space. Notation: x' = hsl(x).
546 $ref2 = _color_rgb2hsl($ref2);
547 $ref3 = _color_rgb2hsl($ref3);
548 for ($i = 0; $i < 3; ++$i) {
549 $shift[$i] = $ref2[$i] - $ref3[$i];
550 }
551
552 // Take the given color, and blend it towards the target.
553 $given = _color_unpack($given, TRUE);
554 for ($i = 0; $i < 3; ++$i) {
555 $result[$i] = $target[$i] + ($given[$i] - $target[$i]) * $delta;
556 }
557
558 // Finally, we apply the extra shift in HSL space.
559 // Note: if ref2 is a pure blend of ref1 and target, then |shift| = 0.
560 $result = _color_rgb2hsl($result);
561 for ($i = 0; $i < 3; ++$i) {
562 $result[$i] = min(1, max(0, $result[$i] + $shift[$i]));
563 }
564 $result = _color_hsl2rgb($result);
565
566 // Return hex color.
567 return _color_pack($result, TRUE);
568 }
569
570 /**
571 * Convert a hex triplet into a GD color.
572 */
573 function _color_gd($img, $hex) {
574 $c = array_merge(array($img), _color_unpack($hex));
575 return call_user_func_array('imagecolorallocate', $c);
576 }
577
578 /**
579 * Blend two hex colors and return the GD color.
580 */
581 function _color_blend($img, $hex1, $hex2, $alpha) {
582 $in1 = _color_unpack($hex1);
583 $in2 = _color_unpack($hex2);
584 $out = array($img);
585 for ($i = 0; $i < 3; ++$i) {
586 $out[] = $in1[$i] + ($in2[$i] - $in1[$i]) * $alpha;
587 }
588
589 return call_user_func_array('imagecolorallocate', $out);
590 }
591
592 /**
593 * Convert a hex color into an RGB triplet.
594 */
595 function _color_unpack($hex, $normalize = FALSE) {
596 if (strlen($hex) == 4) {
597 $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
598 }
599 $c = hexdec($hex);
600 for ($i = 16; $i >= 0; $i -= 8) {
601 $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
602 }
603
604 return $out;
605 }
606
607 /**
608 * Convert an RGB triplet to a hex color.
609 */
610 function _color_pack($rgb, $normalize = FALSE) {
611 $out = 0;
612 foreach ($rgb as $k => $v) {
613 $out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
614 }
615
616 return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
617 }
618
619 /**
620 * Convert a HSL triplet into RGB.
621 */
622 function _color_hsl2rgb($hsl) {
623 $h = $hsl[0];
624 $s = $hsl[1];
625 $l = $hsl[2];
626 $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
627 $m1 = $l * 2 - $m2;
628
629 return array(
630 _color_hue2rgb($m1, $m2, $h + 0.33333),
631 _color_hue2rgb($m1, $m2, $h),
632 _color_hue2rgb($m1, $m2, $h - 0.33333),
633 );
634 }
635
636 /**
637 * Helper function for _color_hsl2rgb().
638 */
639 function _color_hue2rgb($m1, $m2, $h) {
640 $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
641 if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
642 if ($h * 2 < 1) return $m2;
643 if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
644
645 return $m1;
646 }
647
648 /**
649 * Convert an RGB triplet to HSL.
650 */
651 function _color_rgb2hsl($rgb) {
652 $r = $rgb[0];
653 $g = $rgb[1];
654 $b = $rgb[2];
655 $min = min($r, min($g, $b));
656 $max = max($r, max($g, $b));
657 $delta = $max - $min;
658 $l = ($min + $max) / 2;
659 $s = 0;
660
661 if ($l > 0 && $l < 1) {
662 $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
663 }
664
665 $h = 0;
666 if ($delta > 0) {
667 if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
668 if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
669 if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
670 $h /= 6;
671 }
672
673 return array($h, $s, $l);
674 }

  ViewVC Help
Powered by ViewVC 1.1.2