[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/modules/color/ -> color.module (source)

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7