示例#1
0
 /**
  * Generate a gradient
  *
  * @param int    $width
  * @param int    $height
  * @param array  $color_stops      Color stops, in format (position, unit, color)
  * @param string $direction        Gradient direction (vertical, horizontal, diagonal, radial, square, diamond)
  * @param bool   $invert           Inver gradient
  * @param array  $background_color If set, the final color of the gradient will be saved here
  *
  * @return Tinyfier_Image_Tool
  */
 public static function generate($width, $height, $color_stops, $direction = 'vertical', $invert = false, &$background_color = null)
 {
     //Crear imagen
     $image = imagecreateTRUEcolor($width, $height);
     //Calcular el número de líneas a dibujar
     $lines;
     $fill_background = false;
     switch ($direction) {
         case 'vertical':
             $lines = $height;
             break;
         case 'horizontal':
             $lines = $width;
             break;
         case 'diagonal':
             $lines = max($width, $height) * 2;
             break;
         case 'radial':
             $center_x = $width / 2;
             $center_y = $height / 2;
             $rh = $height > $width ? 1 : $width / $height;
             $rw = $width > $height ? 1 : $height / $width;
             $lines = ceil(max($width, $height) / 1.5);
             //Lo correcto sería /2, pero se aplica 1.5 para expandir el degradado y hacerlo más similar al generado por los navegadores
             $fill_background = true;
             $invert = !$invert;
             //The gradient is drawn from outside to inside
             break;
         case 'square':
         case 'rectangle':
             $direction = 'square';
             $lines = max($width, $height) / 2;
             $invert = !$invert;
             //The gradient is drawn from outside to inside
             break;
         case 'diamond':
             $rh = $height > $width ? 1 : $width / $height;
             $rw = $width > $height ? 1 : $height / $width;
             $lines = min($width, $height);
             $invert = !$invert;
             //The gradient is drawn from outside to inside
             break;
         default:
             return false;
             break;
     }
     //Ordenar paradas de color
     $colors = array();
     foreach ($color_stops as $stop) {
         list($position, $unit, $color) = $stop;
         $percentage;
         switch ($unit) {
             case 'px':
                 $percentage = 100 / $lines * $position;
                 break;
             default:
                 $percentage = $position;
                 break;
         }
         $colors[floatval($position)] = Tinyfier_CSS_Color::create($color)->to_array();
     }
     ksort($colors);
     $positions = array_keys($colors);
     if (!isset($colors[0])) {
         //Usar el primero como color de inicio
         $colors[0] = $colors[reset($positions)];
     }
     if (!isset($colors[100])) {
         //Usar el último como color final
         $colors[100] = $colors[end($positions)];
     }
     //Fill background
     $background_color = $colors[100];
     if ($fill_background) {
         list($r1, $g1, $b1) = $colors[100];
         imagefill($image, 0, 0, imagecolorallocate($image, $r1, $g1, $b1));
     }
     //Invert colors
     if ($invert) {
         $invert_colors = array();
         foreach ($colors as $key => $value) {
             $invert_colors[100 - $key] = $value;
         }
         $colors = $invert_colors;
     }
     ksort($colors);
     //Draw line by line
     $incr = 1;
     $color_change_positions = array_keys($colors);
     $end_color_progress = 0;
     //Forzar que en la primera iteración se seleccione el rango de colores
     for ($i = 0; $i < $lines; $i = $i + $incr) {
         //Escoger color
         $total_progress = 100 / $lines * $i;
         if ($total_progress >= $end_color_progress) {
             //Cambiar de rango de colores
             //Buscar color inicial a partir del progreso total
             $j = intval($total_progress);
             do {
                 $color_index = array_search($j--, $color_change_positions);
             } while ($color_index === false && $j >= 0);
             //Obtener colores inicio y final para este rango
             $start_color_progress = $color_change_positions[$color_index];
             $start_color = $colors[$start_color_progress];
             $end_color_progress = $color_change_positions[$color_index + 1];
             $end_color = $colors[$end_color_progress];
         }
         $internal_progress = ($total_progress - $start_color_progress) / ($end_color_progress - $start_color_progress);
         $r = $start_color[0] + ($end_color[0] - $start_color[0]) * $internal_progress;
         $g = $start_color[1] + ($end_color[1] - $start_color[1]) * $internal_progress;
         $b = $start_color[2] + ($end_color[2] - $start_color[2]) * $internal_progress;
         $color = imagecolorallocate($image, $r, $g, $b);
         //Dibujar línea
         switch ($direction) {
             case 'vertical':
                 //Draw from top to bottom
                 imagefilledrectangle($image, 0, $i, $width, $i + $incr, $color);
                 break;
             case 'horizontal':
                 //Draw from left to right
                 imagefilledrectangle($image, $i, 0, $i + $incr, $height, $color);
                 break;
             case 'diagonal':
                 //Draw from top-left to bottom-right
                 imagefilledpolygon($image, array($i, 0, $i + $incr, 0, 0, $i + $incr, 0, $i), 4, $color);
                 break;
             case 'square':
                 //Draw from outside to center
                 imagefilledrectangle($image, $i * $width / $height, $i * $height / $width, $width - $i * $width / $height, $height - $i * $height / $width, $color);
                 break;
             case 'radial':
                 //Draw from outside to center
                 imagefilledellipse($image, $center_x, $center_y, ($lines - $i) * $rh * 2, ($lines - $i) * $rw * 2, $color);
                 break;
             case 'diamond':
                 //Draw from outside to center
                 imagefilledpolygon($image, array($width / 2, $i * $rw - 0.5 * $height, $i * $rh - 0.5 * $width, $height / 2, $width / 2, 1.5 * $height - $i * $rw, 1.5 * $width - $i * $rh, $height / 2), 4, $color);
                 break;
         }
     }
     return new Tinyfier_Image_Tool($image);
 }
示例#2
0
文件: LESS.php 项目: ideatic/tinyfier
 /**
  * Generates a gradient compatible with old browsers
  */
 public function lib_gradient($arguments)
 {
     $color_stops = array();
     $gradient_type = 'vertical';
     $gradient_width = 1;
     $gradient_height = 50;
     $size_changed = false;
     //Get input parameters
     foreach ($arguments[2] as $argument) {
         $type = $argument[0];
         switch ($type) {
             case 'raw_color':
             case 'color':
                 //Start or end color
                 $argument = $this->coerceColor($argument);
                 $is_initial_color = isset($is_initial_color) ? false : true;
                 // $color = $type == 'color' ? array($argument[1], $argument[2], $argument[3]) : $this->coerceColor($argument[1]);
                 $color_stops[] = array($is_initial_color ? 0 : 100, '%', array($argument[1], $argument[2], $argument[3]));
                 break;
             case 'list':
                 $list_data = $argument[2];
                 if ($list_data[0][0] == 'color' || $list_data[0][0] == 'raw_color') {
                     //Color and position
                     $color_index = 0;
                     $position_index = 1;
                     $list_data[$color_index] = $this->coerceColor($list_data[$color_index]);
                 } else {
                     //Position and color
                     $color_index = 1;
                     $position_index = 0;
                 }
                 $color = array($list_data[$color_index][1], $list_data[$color_index][2], $list_data[$color_index][3]);
                 $position = $list_data[$position_index][1];
                 $unit = $list_data[$position_index][2];
                 $color_stops[] = array($position, $unit, $color);
                 break;
             case 'string':
                 //Gradient type
                 $gradient_type = strtolower($this->_remove_quotes($argument[2][0]));
                 if ($gradient_type == 'vertical' && !$size_changed) {
                     $gradient_width = 1;
                     $gradient_height = 50;
                 } else {
                     if ($gradient_type == 'horizontal' && !$size_changed) {
                         $gradient_width = 50;
                         $gradient_height = 1;
                     }
                 }
                 break;
             case 'number':
                 //Image size (first time received: width, other times: height)
                 if (!$size_changed) {
                     if ($gradient_type == 'vertical') {
                         $gradient_height = $argument[1];
                     } else {
                         $gradient_width = $argument[1];
                     }
                     $size_changed = true;
                 } else {
                     if ($gradient_type == 'vertical') {
                         $gradient_width = $gradient_height;
                     }
                     $gradient_height = $argument[1];
                 }
                 break;
         }
     }
     //Generate gradient
     // var_dump($arguments,$gradient_width, $gradient_height, $color_stops, $gradient_type, FALSE, $back_color);die;
     $image = Tinyfier_Image_Gradient::generate($gradient_width, $gradient_height, $color_stops, $gradient_type, false, $back_color);
     $path = $this->_get_cache_path('gradient', 'png');
     $image->save($path, 100, $this->_settings['optimize_images']);
     //Save gradients at maximum quality to avoid color loss
     //Create CSS code
     $color_positions = array();
     foreach ($color_stops as $stop) {
         list($position, $unit, $color) = $stop;
         $color = Tinyfier_CSS_Color::create($color);
         $color_positions[] = ($color->a == 1 ? $color->to_hex() : $color->to_rgb()) . " {$position}{$unit}";
     }
     $color_positions = implode(',', $color_positions);
     $back_color = Tinyfier_CSS_Color::create($back_color)->to_hex();
     if (in_array($gradient_type, array('vertical', 'horizontal', 'diagonal'))) {
         switch ($gradient_type) {
             case 'vertical':
                 $repeat = 'repeat-x';
                 $position = 'to bottom';
                 break;
             case 'horizontal':
                 $repeat = 'repeat-y';
                 $position = 'to right';
                 break;
             case 'diagonal':
                 $repeat = '';
                 $position = '-45deg';
                 break;
             default:
                 $repeat = '';
                 $position = $gradient_type;
                 break;
         }
         $css = "background-repeat: {$repeat};\nbackground-image: url('{$this->_get_cache_url($path)}'); /* Old browsers */\nbackground-image: linear-gradient({$position}, {$color_positions});";
     } else {
         if ($gradient_type == 'radial') {
             $css = "background-image: url('{$this->_get_cache_url($path)}'); /* Old browsers */\nbackground-image: radial-gradient(ellipse at center, {$color_positions});";
         } else {
             //It is necessary to use images
             $css = "background-image: url('{$this->_get_cache_url($path)}');";
         }
     }
     return array('string', '', array("{$back_color};{$css}"));
 }