Пример работы jQuery UI + PHP и GD. Нанесение аппликаций на изображение

от автора

Вступление

Всем привет! Здороваюсь с хабром я в первый, и надеюсь не последний, раз. Не смотря на то, что читаю хабр довольно давно, идея написать что-то полезное появилась совсем недавно, когда на работе я столкнулся с весьма интересной задачей — разработка он-лайн редактора коллажей. Поскольку особого ассортимента инструментов разработки не было, решили делать средствами js+jQuery и php GD. Процесс реализации задуманного оказался весьма интересным, и куча полученных положительных эмоций и новых навыков подтолкнули меня на написание статьи на хабр. В этой статейке я постараюсь рассказать о некоторых интересных моментах, с которыми столкнулся при разработке он-лайн редактора.

Задача

По изначальному плану статьи я хотел описать весь процесс разработки, но потом передумал, поскольку статья получилась бы слишком длинной и имела бы много очевидных и итак всем понятных вещей. Поэтому план статьи был переработан, и я решил оставить только самые интересные и важные, как мне кажется, моменты.
Итого: речь пойдет об использовании jQuery UI в связке с PHP библиотекой GD. В статье я постараюсь, как можно доходчивее, показать и рассказать об использовании таких возможностей jQuery UI, как перетаскивание и ресайз элементов. А также формирование картинки из созданных и обработанных пользователем элементов (картинок).
Чтобы было более понятней и наглядней думаю будет не плохо сделать рабочий пример(посмотреть можно тут). В примере реализована одна из частей он-лайн редактора, а именно работа с аппликациями, в которой пользователь может наложить на картинку дополнительные элементы, перетаскивать их как угодно и ресайзить, после чего все это «искусство» должно собраться в единую картинку.
Что-то я много говорю, пора уже и к делу приступить, начнем.

Решение

Для нетерпеливых сразу выложу рабочий пример: ссылка
И исходники: ссылка

Для начала стоит определиться, что мы будем использовать и где.
На стороне клиента (в браузере), будем пользоваться, не нуждающийся в представлении, библиотекой jQuery и несколькими ее плагинами, а именно Draggable и Resizable.
На сервере будем использовать php и библиотеку GD, которая установлена практически на каждом сервере и хостинге, в отличии от более продвинутого аналога ImageMagick.

Процесс разработки начнем с клиентской части. Нам потребуется создать рабочую область, в которой пользователь сможет таскать и ресайзить картинки. А также необходимо добавить на страницу панель, в которой будет находится несколько вариантов аппликаций.

Покажу небольшой кусочек html, для лучшего понимания:

<div class="work_area"> 	<img src="/resources/images/angelina.jpg" width="500" height="600" id="main_img_big" /> </div> <div class="applications_div"> 	<img src="/resources/applications/1.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/2.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/3.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/4.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/5.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/6.png" width="64" height="64" id="one_application" /> 	<img src="/resources/applications/7.png" width="64" height="64" id="one_application" /> </div> 

Нам необходимо добавлять элементы аппликации на рабочую область, когда пользователь кликнет по приглянувшейся картинке-аппликации. Поскольку количество добавленных элементов ни как нельзя предугадать, добавление нужно сделать динамическим, для этого можно использовать следующий код:

var num_elem = 0; // добавление аппликации в рабочую область function addApplication(element){ 	var applicImg = element.clone(); // создаем копию элемента 	// удаляем аттрибуты размеров картинки 	applicImg.removeAttr('width'); 	applicImg.removeAttr('height'); 	// добавляем родительский див для аппликации в рабочую область 	var allElement = '<div class="applic_new_el_div" id="move_applic_'+num_elem+'"><span class="close_applic"></span></div>'; 	$('.work_area').append(allElement); 	 // добавляем класс для перетаскивания 	applicImg.addClass('applic_new_el'); 	// задаем место появления в рабочей области 	$('#move_applic_'+num_elem).css({ 		'top': '0px', 		'left': '0px' 	}); 	applicImg.attr('id', 'applic_'+num_elem);  	// добавляем элемент 	$('#move_applic_'+num_elem).append(applicImg);	 	init_drag(num_elem); // задаем перетаскивание  	init_resize(num_elem); // задаем резайз  	num_elem ++; // увиличение счетчика для аппликаций } 

Как вы уже обратили внимание, добавляется не только картинка, но еще и вместе с дивом, в который обернута и span`ом. Span будет выполнять роль «крестика», который будет при необходимости удалять не нужную аппликацию из рабочей области.
После добавления аппликации, необходимо вызвать плагины, для добавления возможности ресайза и перемещения картиночки.
Для возможности ресайза будем использовать плагин Resizable, вызовем его с помощью такой функции:

// ресайз для аппликаций function init_resize(num_el){ 	$('#move_applic_'+num_el).resizable({ 		aspectRatio: true, // сохранять пропорции 		handles:     'ne, nw, se, sw', // имена классов для угловых блоков 		alsoResize: "#applic_"+num_el // расайзим еще и родительский див - рамку 	}); } 

Чтобы картинка еще и перемещалась по рабочей области, воспользуемся плагином Draggable, для его вызова напишем вот такую функцию:

// задаем перетаскивание для апликации function init_drag(num_el){ 	$('#move_applic_'+num_el).draggable({ 		cursor: 'move', // вид курсора 		containment: '.work_area', // ограничение перемещения 		scroll: false, // автоскроллинг 		drag: null // событие при перемещении		 	}); } 

На этом работа с аппликацией закончена. Все что остается сделать на клиентской стороне – это собрать все данные о добавленных аппликациях и отправить на сервер для обработки. Чтобы создать на сервере такую же картинку, как и в браузере, нам потребуется знать путь до каждой картинки-аппликации, размер (ширину и высоту) и положение на странице, относительно рабочей области.
Чтобы не делать перезагрузку страницы, а также для удобства передачи данных, воспользуемся ajax`ом. Код для сбора данных об аппликациях и отправки не сервер выглядит вот так:

// создание картинки с наложением аппликации. Запрос на сервер function ajaxMakeImage(){ 	// объявляем необходимые массивы 	var arrayWidth = []; 	var arrayHeight = []; 	var arraySrc = []; 	var arrayTop = []; 	var arrayLeft = []; 	var srcImage = $('#main_img_big').attr('src');	 	var workAreaTop = $('.work_area').offset().top; 	var workAreaLeft = $('.work_area').offset().left;	 	var num = 0; 	$('.applic_new_el_div').each(function(e) { 		arrayWidth[num] = $(this).width(); 		arrayHeight[num] = $(this).height(); 		arraySrc[num] = $(this).children('.applic_new_el').attr('src'); 		arrayTop[num] = $(this).offset().top; 		arrayLeft[num] = $(this).offset().left; 		num++; 	});	 	// отправляем данные на сервер 	$.ajax({ 		type: "POST", 		url: "/ajax_action.php", 		data: { 			'arraySrc': arraySrc, // массив путей для аппликаций 			'arrayWidth': arrayWidth, // массив длин аппликаций 			'arrayHeight': arrayHeight,// массив ширин аппликаций 			'arrayTop': arrayTop, // массив отступов сверху для аппликаций 			'arrayLeft': arrayLeft, // массив отступов слева для аппликаций 			'srcImage': srcImage, // ссылка на фотографию(главная картинка) 			'workAreaTop': workAreaTop, // отступ сверху до робочей области 			'workAreaLeft': workAreaLeft, // отступ слева до робочей области 		}, 		dataType: "json", 		success: function(data){ 			if(data.result == 'success'){	 				// если все прошло успешно 				// выводим готовую картинку 				$('#test_show').attr('src', data.imgSrc);	 				alert('Картинка создана'); 			}else{ 				// error 				// @todo вывод ошибки 			} 		} 	}); } 

Работа в браузере закончена. Теперь необходимо написать на сервере скрипт, который будет обрабатывать полученные данные и опираясь на них генерировать картинку.
Как я уже говорил, для работы с картинками будем использовать библиотеку GD.
Поскольку аппликации могут быть абсолютно любого размера, то нужно каждую полученную аппликацию нужно ресайзить. Напишем для этого небольшую функцию:

function resizePhotoPNG($source, $path, $height, $width){ 	$rgb = 0xffffff; //цвет заливки фона 	$size = getimagesize($source);//узнаем размеры исходной картинки 	$xRatio = $width / $size[0]; //пропорция ширины 	$yRatio = $height / $size[1]; //пропорция высоты 	$ratio = min($xRatio, $yRatio); 	$kRatio = ($xRatio == $ratio); //соотношения ширины к высоте 	$new_width = $kRatio  ? $width  : floor($size[0] * $ratio); //ширина 	$new_height = !$kRatio ? $height : floor($size[1] * $ratio); //высота 	// расхождение с заданными параметрами по ширине 	$new_left = $kRatio  ? 0 : floor(($width - $new_width) / 2); 	// расхождение с заданными параметрами по высоте 	$newTop = !$kRatio ? 0 : floor(($height - $new_height) / 2); 	//создаем вспомогательное изображение пропорциональное картинке 	$img = imagecreatetruecolor($width, $height); 	imagealphablending($img, false);  	imagesavealpha($img, true);		 	$photo = imagecreatefrompng($source); //достаем наш исходник 	imagecopyresampled($img, $photo, $new_left, $newTop, 0, 0, $new_width, $new_height, $size[0], $size[1]); //копируем на него превью с учетом расхождений 	imagepng($img, $path); //сохраняем результат 	// Очищаем память после выполнения скрипта 	imagedestroy($img); 	imagedestroy($photo); 	// вернем путь для картинки 	return $path; } 

Теперь, имея функцию ресайза, остается только обработать все аппликации с ее помощью и сохранить во временной папке. После этого необходимо на главную картинку по очереди нанести каждую аппликацию, конечно не забывая их смещать по осям X и Y. Смещения по осям будут равны отступам слева и сверху в браузере, относительно рабочей области.
Нанесение со смещением можно сделать следующим образом:

// $arrayApplication – массив путей до уже отресайзеных аппликаций // $mainImg – это главная рабочая картинка foreach($arrayApplication as $k=>$oneAppl){ 	//Загружаем одну аппликацию и задаем прозрачность 	$imageFon = imagecreatefrompng($oneAppl); 	imagealphablending($imageFon, false);  	imagesavealpha($imageFon, true);				 	// совмещаем картинки 	imagecopy($mainImg, $imageFon, $applX[$k]-$imgX, $applY[$k]-$imgY, 0, 0, imagesx($imageFon), imagesy($imageFon)); } 

На этом обработка картинок закончена, остается только сохранить получившуюся картинку и передать путь до нее в браузер.
Для сохранения используем следующий код:

imageJpeg($mainImg, $pathForImg, 100); // сохранение картинки в папку $pathForImg и с качеством 100 // и не забудем очистить память imagedestroy($mainImg); 

Теперь отправляем в браузер ответ, в котором передадим путь до созданной картинки:

$result = array( 		'result' => 'success', // результат работы скрипта 		'imgSrc' => $resultSrc // путь до картинке 	);	 echo json_encode($result); // кодируем массив в JSON и передаем данные браузеру 

На этом наложение аппликаций на картинку закончено.

Если меня совсем уж не заминусуют, и статья окажется хоть кому-то полезной, я постараюсь написать еще несколько статей по созданию коллажа (загрузка фотографий, наложение фильтров, наложение текста и тд).
Список полезных ссылок, опираясь на которые я писал статью:
Обработка изображений и GD
Плагин jQuery Draggable
Плагин jQuery Resizable
Рабочий пример
Исходники примера

Спасибо за внимание!

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


Комментарии

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

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