Yii, пишем виджет для ресайза картинок своими руками

от автора

Добрый вечер, хабравчане.
В данный момент занимаюсь написанием небольшой админки для сайта фото-студии.
Работу выполняю на Yii+Booster. Используя CRUD-generator достаточно быстро набросал примерный функционал, но когда дошло дело до картинок, появились маленькие проблемы. Поискав на официальном сайте подходящее дополнение пришел к тому, что придется написать простенький и «легкий» виджет для моих нужд.

Поскольку это сайт фото-студии, то картинок, разумеется, на нем будет очень много, и просто необходима функция динамического ресайза картинок.
И так…

Цель

Создать виджет который будет создавать уменьшенную копию оригинального изображения, если таковой не существует, и выводить ее путь на сайте. А также будет легко настраиваться под наши нужды.

Реализация

Для начало создаем каталог kyimages (имя нашего виджета) в папке \protected\extensions\. В ней создаем файл KYImages.php (опять же имя нашего виджета, так же должен называться и класс который мы вскоре создадим).

Теперь приступаем непосредственно к написанию самого виджета.

<?php class KYImages extends CWidget { 	public function run()     {	     } } 

А именно, создаем наш класс, который расширяет класс CWidget и переопределяем его метод run().
В этом методе будет находится тело нашего виджета.

Поскольку наш виджет будет принимать параметры для ресайза картинки, огласим переменные, которые будут их хранить.

public $params = array(); //полученные параметры //параметры по умолчанию public $_params = array( 	'image'=>'', //url каринки 	'dimensions'=>'100x100', //желаемые размеры превью 	'crop'=>true, //метод обработки (если true обрезать до указанных размеров, иначе - пропорционально уменьшить) 	'quality'=>100, //качество 	);   

Далее приступаем к написание непосредсвтенно действий выполняемых виджетом.
Представлю вам хорошо коментированный код функции

public function run()     {	 		define('WEBROOT',Yii::getPathOfAlias('webroot')); //корень приложения 		 		//преобразуем массив параметров по умолчанию в переменные 		extract($this->_params); 		//переопределяем полученными параметрами 		extract($this->params); 		 		$original_path =  WEBROOT. dirname($image); //путь к папке с картинкой на сервере 		$original_image_path = WEBROOT . $image; //путь к самой картинке на сервере 		 		$dimensions = explode('x',$dimensions); // конвертируем размеры изображения вида "100х100" в массив 		$target_width  = intval($dimensions[0]); //желаемая ширина 		$target_height = intval(empty($dimensions[1]) ? $dimensions[0] : $dimensions[1]); //желаемая высота  		$pcs = pathinfo($original_image_path); //казбиваем путь к картинке 		$name = explode('.',$pcs["basename"]); 		$name = $name[0]; //запоминаем имя файла 		$ext = $pcs["extension"]; //запоминаем расширение файла  		$new_name  = $name . "_{$target_width}x{$target_height}" . '.' . $ext; //новое имя для файла 		$new_path = $original_path . "/{$target_width}x{$target_height}/" .  $new_name; //путь для превью (рядом с оригиналом будет папка с именев вида "100х100") 		$true_path = dirname($image) . "/{$target_width}x{$target_height}/" . $new_name; //путь оносительно домена  		if (file_exists($new_path)) { //проверяем если превью уже существует 			echo $true_path; //если да, тогда просто возращаем путь, иначе генерируем превью 		} else { 		 			if (!file_exists($original_path . "/{$target_width}x{$target_height}/" )) { //проверяем создана ли папка для первью, создаем ессли нет 				mkdir($original_path . "/{$target_width}x{$target_height}/" ); 			} 			list($width, $height) = getimagesize($original_image_path); //запоминаем размеры оригинаьной картинки 			$mime = getimagesize($original_image_path); //получаем инфо о картинке 			 			$r = $width / $height; //пропорции 			if ($crop) { //проверяем установлена ли опция обрезки картинки, и задаем соответсвующее поведение 				if ($width > $height) { 					$width = ceil($width-($width*($r-$target_width/$target_height))); 				} else { 					$height = ceil($height-($height*($r-$target_width/$target_height))); 				} 				$newwidth = $target_width; 				$newheight = $target_width; 			} else { 				if ($target_width/$target_height > $r) { 					$newwidth = $target_height*$r; 					$newheight = $target_height; 				} else { 					$newheight = $target_width/$r; 					$newwidth = $target_width; 				} 			} 			switch($mime['mime']) //проверяем тип картинки, ив зависимот=сти от этого изменяем функции генерации и экспорта картинки 			{ 				case 'image/gif': 					$creationFunction	= 'imagecreatefromgif'; //фунция генерации 					$outputFunction		= 'imagepng'; //функция экспорта 					$mime				= 'image/png'; // конвертируем gif в png 					$quality			= round(10 - ($quality / 10)); // для png качество задается от 1 до 9, а не как в jpeg от 1 до 100 				break; 				 				case 'image/x-png': 				case 'image/png': 					$creationFunction	= 'imagecreatefrompng'; 					$outputFunction		= 'imagepng'; 					$quality			= round(10 - ($quality / 10)); 				break; 				 				default: 					$creationFunction	= 'imagecreatefromjpeg'; 					$outputFunction	 	= 'imagejpeg'; 				break; 			} 			 			$src = $creationFunction($original_image_path); 			$dst = imagecreatetruecolor($newwidth, $newheight); 			imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); //генерируем превью 			$outputFunction($dst, $new_path, $quality); //сохраняем на диск 			// Чистим память 			imagedestroy($src); 			imagedestroy($dst); 			 			echo $true_path; //возращаем путь относительно домена 		}     } 

Вот и готово.

Вывод на сайте

<img src="<?php $this->widget('application.extensions.kyimages.KYImages',array('params'=>array('image'=>"/media/images/img.jpeg",'dimensions'=>'138x138'))); ?>"> 

Конечно вы скажете что можно было бы сделать чтоб виджет выводил сразу готовый тег <img>, но мне требовалось именно так. Вы же можете изменить все как считаете нужным. Возможно вы знаете как можно оптимизировать мой код=)

Полный код фала KYImages.php

<source lang="php"> <?php /**  * KYImages extension controller action class  *  * PHP version 5.3  *  * LICENSE: This source file is subject to  GNU General Public License v2.  *  * @category   Extensions  * @package    KYImages  * author     Ruslan Kyba <kybargr@gmail.com>  * copyright  2013 Ruslan Kyba  * version    0.1  * see        Yii Framework  */ class KYImages extends CWidget { 	public $params = array(); 	public $_params = array(         'image'=>'',         'dimensions'=>'100x100', 		'crop'=>true, 		'quality'=>100,     ); 	 	public function run()     {	 		define('WEBROOT',Yii::getPathOfAlias('webroot')); //корень приложения 		 		//преобразуем массив параметров по умолчанию в переменные 		extract($this->_params); 		//переопределяем полученными параметрами 		extract($this->params); 		 		$original_path =  WEBROOT. dirname($image); //путь к папке с картинкой на сервере 		$original_image_path = WEBROOT . $image; //путь к самой картинке на сервере 		 		$dimensions = explode('x',$dimensions); // конвертируем размеры изображения вида "100х100" в массив 		$target_width  = intval($dimensions[0]); //желаемая ширина 		$target_height = intval(empty($dimensions[1]) ? $dimensions[0] : $dimensions[1]); //желаемая высота  		$pcs = pathinfo($original_image_path); //казбиваем путь к картинке 		$name = explode('.',$pcs["basename"]); 		$name = $name[0]; //запоминаем имя файла 		$ext = $pcs["extension"]; //запоминаем расширение файла  		$new_name  = $name . "_{$target_width}x{$target_height}" . '.' . $ext; //новое имя для файла 		$new_path = $original_path . "/{$target_width}x{$target_height}/" .  $new_name; //путь для превью (рядом с оригиналом будет папка с именев вида "100х100") 		$true_path = dirname($image) . "/{$target_width}x{$target_height}/" . $new_name; //путь оносительно домена  		if (file_exists($new_path)) { //проверяем если превью уже существует 			echo $true_path; //если да, тогда просто возращаем путь, иначе генерируем превью 		} else { 		 			if (!file_exists($original_path . "/{$target_width}x{$target_height}/" )) { //проверяем создана ли папка для первью, создаем ессли нет 				mkdir($original_path . "/{$target_width}x{$target_height}/" ); 			} 			list($width, $height) = getimagesize($original_image_path); //запоминаем размеры оригинаьной картинки 			$mime = getimagesize($original_image_path); //получаем инфо о картинке 			 			$r = $width / $height; //пропорции 			if ($crop) { //проверяем установлена ли опция обрезки картинки, и задаем соответсвующее поведение 				if ($width > $height) { 					$width = ceil($width-($width*($r-$target_width/$target_height))); 				} else { 					$height = ceil($height-($height*($r-$target_width/$target_height))); 				} 				$newwidth = $target_width; 				$newheight = $target_width; 			} else { 				if ($target_width/$target_height > $r) { 					$newwidth = $target_height*$r; 					$newheight = $target_height; 				} else { 					$newheight = $target_width/$r; 					$newwidth = $target_width; 				} 			} 			switch($mime['mime']) //проверяем тип картинки, ив зависимот=сти от этого изменяем функции генерации и экспорта картинки 			{ 				case 'image/gif': 					$creationFunction	= 'imagecreatefromgif'; //фунция генерации 					$outputFunction		= 'imagepng'; //функция экспорта 					$mime				= 'image/png'; // конвертируем gif в png 					$quality			= round(10 - ($quality / 10)); // для png качество задается от 1 до 9, а не как в jpeg от 1 до 100 				break; 				 				case 'image/x-png': 				case 'image/png': 					$creationFunction	= 'imagecreatefrompng'; 					$outputFunction		= 'imagepng'; 					$quality			= round(10 - ($quality / 10)); 				break; 				 				default: 					$creationFunction	= 'imagecreatefromjpeg'; 					$outputFunction	 	= 'imagejpeg'; 				break; 			} 			 			$src = $creationFunction($original_image_path); 			$dst = imagecreatetruecolor($newwidth, $newheight); 			imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); //генерируем превью 			$outputFunction($dst, $new_path, $quality); //сохраняем на диск 			// Чистим память 			imagedestroy($src); 			imagedestroy($dst); 			 			echo $true_path; //возращаем путь относительно домена 		}     } } </source >

ссылка на оригинал статьи http://habrahabr.ru/post/182592/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *