GD2: два в одном

Благодарю вас за то что не сбрасываете меня со счетов и не удаляете из ридера. Потому что я пишу когда у меня есть интересные задачи и вот сегодня я немного попишу про библиотеку GD2 и работу с ней средствами PHP

Задачка сегодня звучит так: надо загрузить на сайт два изображения (произвольного размера, разумеется) каждое изображение уменьшить до определенного размера с учетом пропорций и положить на один холст (с соотношением размеров 2:1 к размеру картинки) так чтобы обе картинки были в центре. В общем я не большой мастер объяснять на пальцах поэтому нарисовал вот такой эскиз.

gd2

Сначала я попробовал рещить эту задачу при помощи встроенной в CI (поскольку именно на CI я пишу в силу незнания других фреймворков) библиотеки которая умеет работать и с GD2 и с ImageMagic и с NetPBM. К сожалению библиотека оказалась очень громоздкой (в плане конфигурации) и не очень гибкой в плане функционала, поэтому написал три больших конфига и попытавшись отладить полученное я получил головняк на пару часов с виндовыми путями на локальной машине. Библиотека никак не хотела принимать абсолютные пути типа C:/localhost/path/to/file.jpg и относительные типа implode(DIRECTORY_SEPARATOR, array(«path»,»to»,»file.jpg»)) , в общем я сделал то чему меня учили в школе — положил на нее, и написал все на чистом PHP

Я не буду описывать как работает CI единственно что надо знать это что я перебираю массив $_FILES и преобразовываю его в массив фалов где каждый файл это элемент массива. итак внимание на экран, коменты по коду.


// это преобразование массива $_FILES в нечто человеко-удобное
$files = $this->getFileData('files');

// юник для базы и размер уменьшенной (квадратной) картинки
$uniqid = uniqid(); //md5(now());
$size = 450;

// проверяю наличие, тип файла и размер
$status = array();
$types = array("first","second");
foreach($types as $type){
	if (!$files[$type]['tmp_name']){
		$status[$type] = "а как же картинкa?";
	} elseif (!in_array($files[$type]['type'], array('image/gif','image/jpeg','image/png'))){
		$status[$type] = "это разве картинка?";
	} elseif ($files[$type]['size'] > 1048576){
		$status[$type] = "размер картинки больше 1M";
	}
}

// если ошибки - выходим
if ($status){
	echo json_encode($status);
	exit;
}

// создаю холст на котором будет все это потом лежать и делаю его прозрачным
$sample = imagecreatetruecolor(2*$size, $size);
imagesavealpha($sample, true);
$transparent = imagecolorallocatealpha($sample, 0, 0, 0, 127);
imagefill($sample, 0, 0, $transparent);

// для каждой картинки
foreach($types as $type){
	// переименовываю и переношу во временную папку
	$files[$type]['new_name'] = TEMP_DIR.'/'.$type.$uniqid.".".end(explode('/', $files[$type]['type']));
	move_uploaded_file($files[$type]['tmp_name'], $files[$type]['new_name']);
	
	// узнаю реальные размеры и высчитываю какими они должны быть
	$image[$type] = array();
	list($image[$type]['width'], $image[$type]['height']) = getimagesize($files[$type]['new_name']);
	$dim = $image[$type]['width'] > $image[$type]['height'] ? 'width' : 'height';
	if($image[$type][$dim] < $size){
		$image[$type]['new_width'] = $image[$type]['width'];
		$image[$type]['new_height'] = $image[$type]['height'];
	} else {
		$image[$type]['ratio'] = $size / $image[$type][$dim] * 100;
		$image[$type]['new_width'] = $image[$type]['width'] * $image[$type]['ratio'] / 100;
		$image[$type]['new_height'] = $image[$type]['height'] * $image[$type]['ratio'] / 100;
	}
	
	// получаю саму картинку
	switch ($files[$type]['type']){
		case 'image/gif':
			$image[$type]['source'] = imagecreatefromgif($files[$type]['new_name']);
			break;
		case 'image/jpeg':
			$image[$type]['source'] = imagecreatefromjpeg($files[$type]['new_name']);
			break;
		case 'image/png':
			$image[$type]['source'] = imagecreatefrompng($files[$type]['new_name']);
			break;
	}
	
	// а теперь собственно магия - я рисую картинку на холсте 
	imagecopyresampled(
		$sample,
		$image[$type]['source'],
		$type=='first'?$size-$image[$type]['new_width']:$size,
		($size-$image[$type]['new_height'])/2,
		0,
		0,
		$image[$type]['new_width'],
		$image[$type]['new_height'],
		$image[$type]['width'],
		$image[$type]['height']
	);
	
	// удаляю ненужное
	unlink($files[$type]['new_name']);
}

// и на последок сохраняю холст
imagepng($sample, implode(DIRECTORY_SEPARATOR, array('path','to',$uniqid.'.png')), 0);
imagedestroy($sample);

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

18 Комментарии “GD2: два в одном

  1. Да ты и на PHP красиво оформляешь код. Это не возможно :)

  2. А по теме:
    Не сложная задача, но код читаеться просто «с скриншота», не в плане оформления, а в плане прослеживания логики.

  3. Интересно на сколько тормознутый, както пробовали опенсорсный проект за рыбе, это была жесть — жетский тормоз, на похапе тот же функционал просто летал.
    А вот с питоном я бы подружился :)

  4. наскільки я знаю більшість нормальних фреймворків для пхп — ніде немає класної ліби для роботи із зображеннями.

  5. и помоему фреймворки тут не при чем, или ты знаешь хорошие библиотеки отдельно от них?

  6. > А вот с питоном я бы подружился :)
    Да, питон это вкусно. Привет, Мавр!

Комментарии закрыты