You are here

colorizer.module in Colorizer 7

Colorize your theme

File

colorizer.module
View source
<?php

/**
 * @file
 * Colorize your theme
 */

/**
 * Saves the info for an instance
 *
 * @param $instance
 *   The instance to save the data for.
 * @param $data
 *   An array of data that corresponds to fields in table.
 *    'stylesheet': Path to a colorizer stylesheet.
 *    'palette': The palette for the instance.
 *    'files': An array of files.
 */
function colorizer_save($instance, $data) {
  if ($current = colorizer_load($instance)) {
    $data += $current;
  }
  else {
    $data += array(
      'palette' => array(),
      'stylesheet' => '',
    );
  }
  $data['palette'] = serialize($data['palette']);
  db_merge('colorizer_instance')
    ->key(array(
    'instance' => $instance,
  ))
    ->fields($data)
    ->execute();
  cache_clear_all('colorizer_data_' . $instance, 'cache');
  drupal_static_reset('colorizer_load');
}

/**
 * Deletes the info for an instance
 *
 * @param $instance
 *   The instance to delete the data for.
 */
function colorizer_delete($instance) {
  db_delete('colorizer_instance')
    ->condition('instance', $instance)
    ->execute();
  cache_clear_all('colorizer_data_' . $instance, 'cache');
  drupal_static_reset('colorizer_load');
}

/**
 * Loads data for an instance.
 *
 * @param $instance
 *   The instance to load the data for.
 * @param $field
 *   Return just specific field if configured.
 *
 * @return
 *   The data or NULL if not set.
 */
function colorizer_load($instance, $field = NULL) {
  $data =& drupal_static(__FUNCTION__, array());
  if (!array_key_exists($instance, $data)) {
    if ($cache = cache_get('colorizer_data_' . $instance)) {
      $data[$instance] = $cache->data;
    }
    else {
      $data[$instance] = db_select('colorizer_instance', 'ci')
        ->fields('ci', array(
        'stylesheet',
        'palette',
      ))
        ->condition('instance', $instance)
        ->execute()
        ->fetchAssoc();
      if (!empty($data[$instance]['palette'])) {
        $data[$instance]['palette'] = unserialize($data[$instance]['palette']);
      }
    }
  }
  if ($field) {
    return isset($data[$instance][$field]) ? $data[$instance][$field] : NULL;
  }
  return $data[$instance];
}

/**
 * Implements hook_menu().
 */
function colorizer_menu() {
  $items = array();
  $items['admin/appearance/colorizer'] = array(
    'title' => 'Colorizer',
    'description' => 'Adjust theme color settings.',
    'type' => MENU_LOCAL_TASK,
    'weight' => 100,
    'file' => 'colorizer.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'colorizer_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
  );
  return $items;
}

/**
 * Implements hook_preprocess_html().
 * Add the colorized style sheet to the site
 */
function colorizer_preprocess_html(&$vars) {
  global $theme_key;

  // If update hasn't run, this won't run.
  if (!db_table_exists('colorizer_instance')) {
    return;
  }
  $instance = $theme_key;

  // allow other modules to change the instance we are updating
  // allows for group-specific color instances rather than tying to theme
  drupal_alter('colorizer_instance', $instance);

  // check to see if colorizer css file exists on site
  $source_path = drupal_get_path('theme', $theme_key) . '/';
  $source_file = $source_path . variable_get('colorizer_cssfile', '');
  if (!file_exists($source_file)) {
    return;
  }
  $file = colorizer_load($instance, 'stylesheet');

  // recreate any missing colorize css files
  if (!file_exists($file)) {
    $palette = colorizer_get_palette($theme_key, $instance);
    if (!empty($palette)) {
      $file = colorizer_update_stylesheet($theme_key, $instance, $palette);

      // clear file status cache so file_exists will look for file again
      clearstatcache();
    }
  }
  if (file_exists($file)) {
    drupal_add_css(file_create_url($file), array(
      'type' => 'external',
      'group' => CSS_THEME,
      'every_page' => TRUE,
      'weight' => 999,
    ));
  }
}

/**
 * Retrieves the Color module information for a particular theme.
 */
function colorizer_get_info($theme, $build_colors = FALSE) {
  static $theme_info = array();
  if (isset($theme_info[$theme])) {
    return $theme_info[$theme];
  }
  $info = array();
  $path = drupal_get_path('theme', $theme);
  $inc_file = variable_get('colorizer_incfile', '');
  $file = DRUPAL_ROOT . '/' . $path . '/' . $inc_file;
  if ($inc_file && file_exists($file)) {
    include $file;
    if ($build_colors) {
      $info = colorizer_fill_defaults($info);
    }
    $theme_info[$theme] = $info;
  }
  return $info;
}

/**
 * Retrieves the color palette for a particular theme and instance.
 */
function colorizer_get_palette($theme, $instance = '', $default = FALSE) {

  // Fetch and expand default palette.
  $info = colorizer_get_info($theme);
  if (empty($info)) {
    return array();
  }
  $palette = $info['schemes']['default']['colors'];
  $instance = empty($instance) ? $theme : $instance;
  if (!$default && ($loaded_palette = colorizer_load($instance, 'palette'))) {
    return $loaded_palette;
  }
  return $palette;
}

/**
 * Fill in any missing colors in palette with defaults
 * scaled to the correct hue
 */
function colorizer_fill_defaults($info) {
  foreach ($info['schemes'] as $scheme => $colors) {
    if ($scheme == 'default') {
      continue;
    }
    foreach ($info['fields'] as $key => $value) {
      if (empty($colors['colors'][$key]) && !empty($colors['base'])) {

        // compute missing color
        $def_color = _colorizer_unpack($info['schemes']['default']['colors'][$key], TRUE);
        $def_hsl = _colorizer_rgb2hsl($def_color);
        $base_color = _colorizer_unpack($colors['base'], TRUE);
        $base_hsl = _colorizer_rgb2hsl($base_color);
        $def_hsl[0] = $base_hsl[0];

        // copy hue from base into def color
        $new_color = _colorizer_hsl2rgb($def_hsl);
        $info['schemes'][$scheme]['colors'][$key] = _colorizer_pack($new_color, TRUE);
      }
    }
  }
  return $info;
}

/**
 * Create a new stylesheet by replacing color variables
 * Basic filehandling copied from Color module
 * Returns full path to new css file
 */
function colorizer_update_stylesheet($theme, $instance, $palette) {

  // Delete old files.
  $current_file = colorizer_load($instance, 'stylesheet');
  @drupal_unlink($current_file);

  // Prepare target locations for generated files.
  $id = $instance . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8);
  $target_path = 'public://colorizer';
  if (!is_dir($target_path)) {
    file_prepare_directory($target_path, FILE_CREATE_DIRECTORY);
    @drupal_chmod($target_path, 0777);
  }

  // ensure directory was created
  if (!is_dir($target_path)) {
    watchdog('file', 'The directory %file could not be created.', array(
      '%file' => $target_path,
    ), WATCHDOG_ERROR);
    return '';
  }
  $target_path = $target_path . '/';
  $target_file = '';
  $source_path = drupal_get_path('theme', $theme) . '/';
  $source_file = DRUPAL_ROOT . '/' . $source_path . variable_get('colorizer_cssfile', '');
  if (file_exists($source_file)) {

    // Aggregate @imports recursively for each configured top level CSS file
    // without optimization. Aggregation and optimization will be
    // handled by drupal_build_css_cache() only.
    $source_styles = drupal_load_stylesheet($source_file, FALSE);

    // Rewrite stylesheet with new colors.
    $target_styles = _colorizer_rewrite_stylesheet($palette, $source_styles);
    $target_file = $target_path . $id . '.css';
    _colorizer_save_stylesheet($target_file, $target_styles);
  }
  if (!empty($target_file)) {
    colorizer_save($instance, array(
      'stylesheet' => $target_file,
    ));
  }
  return $target_file;
}

/**
 * Rewrites the stylesheet to match the colors in the palette.
 */
function _colorizer_rewrite_stylesheet($palette, $style) {

  // loop through all color variables and perform string replacement in css
  foreach ($palette as $key => $value) {
    $style = preg_replace('/@' . $key . '\\b/', $value, $style);
  }
  return $style;
}

/**
 * Saves the rewritten stylesheet to disk.
 */
function _colorizer_save_stylesheet($file, $style) {
  $filepath = file_unmanaged_save_data($style, $file, FILE_EXISTS_REPLACE);

  // Set standard file permissions for webserver-generated files.
  @drupal_chmod($file);
  return $filepath;
}

/**
 * Removes css files from colorizer files cache
 * They will get recreated in hook_init on demand
 */
function colorizer_clearcache() {
  file_unmanaged_delete_recursive('public://colorizer');
}

/**
 * Implements hook_flush_caches().
 */
function colorizer_flush_caches() {
  colorizer_clearcache();
  return array();
}

/**
 * Converts a hex color into an RGB triplet.
 */
function _colorizer_unpack($hex, $normalize = FALSE) {
  if (strlen($hex) == 4) {
    $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
  }
  $c = hexdec($hex);
  for ($i = 16; $i >= 0; $i -= 8) {
    $out[] = ($c >> $i & 0xff) / ($normalize ? 255 : 1);
  }
  return $out;
}

/**
 * Converts an RGB triplet to a hex color.
 */
function _colorizer_pack($rgb, $normalize = FALSE) {
  $out = 0;
  foreach ($rgb as $k => $v) {
    $out |= $v * ($normalize ? 255 : 1) << 16 - $k * 8;
  }
  return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
}

/**
 * Converts an HSL triplet into RGB.
 */
function _colorizer_hsl2rgb($hsl) {
  $h = $hsl[0];
  $s = $hsl[1];
  $l = $hsl[2];
  $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
  $m1 = $l * 2 - $m2;
  return array(
    _colorizer_hue2rgb($m1, $m2, $h + 0.33333),
    _colorizer_hue2rgb($m1, $m2, $h),
    _colorizer_hue2rgb($m1, $m2, $h - 0.33333),
  );
}

/**
 * Helper function for _colorizer_hsl2rgb().
 */
function _colorizer_hue2rgb($m1, $m2, $h) {
  $h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h);
  if ($h * 6 < 1) {
    return $m1 + ($m2 - $m1) * $h * 6;
  }
  if ($h * 2 < 1) {
    return $m2;
  }
  if ($h * 3 < 2) {
    return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
  }
  return $m1;
}

/**
 * Converts an RGB triplet to HSL.
 */
function _colorizer_rgb2hsl($rgb) {
  $r = $rgb[0];
  $g = $rgb[1];
  $b = $rgb[2];
  $min = min($r, min($g, $b));
  $max = max($r, max($g, $b));
  $delta = $max - $min;
  $l = ($min + $max) / 2;
  $s = 0;
  if ($l > 0 && $l < 1) {
    $s = $delta / ($l < 0.5 ? 2 * $l : 2 - 2 * $l);
  }
  $h = 0;
  if ($delta > 0) {
    if ($max == $r && $max != $g) {
      $h += ($g - $b) / $delta;
    }
    if ($max == $g && $max != $b) {
      $h += 2 + ($b - $r) / $delta;
    }
    if ($max == $b && $max != $r) {
      $h += 4 + ($r - $g) / $delta;
    }
    $h /= 6;
  }
  return array(
    $h,
    $s,
    $l,
  );
}

Functions

Namesort descending Description
colorizer_clearcache Removes css files from colorizer files cache They will get recreated in hook_init on demand
colorizer_delete Deletes the info for an instance
colorizer_fill_defaults Fill in any missing colors in palette with defaults scaled to the correct hue
colorizer_flush_caches Implements hook_flush_caches().
colorizer_get_info Retrieves the Color module information for a particular theme.
colorizer_get_palette Retrieves the color palette for a particular theme and instance.
colorizer_load Loads data for an instance.
colorizer_menu Implements hook_menu().
colorizer_preprocess_html Implements hook_preprocess_html(). Add the colorized style sheet to the site
colorizer_save Saves the info for an instance
colorizer_update_stylesheet Create a new stylesheet by replacing color variables Basic filehandling copied from Color module Returns full path to new css file
_colorizer_hsl2rgb Converts an HSL triplet into RGB.
_colorizer_hue2rgb Helper function for _colorizer_hsl2rgb().
_colorizer_pack Converts an RGB triplet to a hex color.
_colorizer_rewrite_stylesheet Rewrites the stylesheet to match the colors in the palette.
_colorizer_rgb2hsl Converts an RGB triplet to HSL.
_colorizer_save_stylesheet Saves the rewritten stylesheet to disk.
_colorizer_unpack Converts a hex color into an RGB triplet.