/** * 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); }
/** * 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}")); }