Ресайзер изображений

от автора

Довольно давно работаю в веб-студии, занимаемся разработкой сайтов в back-end’ом на php. Практически на каждом проекте используется «универсальный» ужиматель картинок, основными целями которого являются уменьшение объема загружаемых данных и избавление вносящего контент от мыслей о правильных пропорциях изображений.

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

— ресайз jpg, png, gif;
— возможность задания ширины и высоты сжатого изображения либо только одного из параметров, второй будет подсчитан пропорционально от исходного изображения;
— три вида ресайзинга (добавление полос — определенного цвета или прозрачных, обрезка изображения);
— кеширование обработанных картинок.

Примеры и код под катом.

Для работы ресайзера используется собственно сам скрипт и файл .htaccess для более простого задания адресов картинок. В принципе, можно обойтись и без последнего, но тогда атрибут src у изображений будет несколько страшным.

В случае использования htaccess вызов ресайзера выглядит следующим образом:
image/<resize_type>/<new_width>/[new_height]/<img_src>
Где:

  • resize_type — обязательный параметр, принимает значения b — borders, t — transparent, c — crop;
  • new_width — обязательный параметр, ширина нового изображения в пикселах. Если указан 0 — посчитает ширину изображения автоматически, исходя из высоты нового изображения с сохранением пропорций. В этом случае, поскольку полученная картинка будет полностью пропорциональна исходной выбор вида ресайзинга не играет никакой роли. Использование нуля актуально для горизонтальных слайдеров, высота которых должна быть фиксирована;
  • new_height — необязательный параметр высоты нового изображения. Если его не указать или указать 0 — посчитает автоматически с сохранением пропорций;
  • img_src — путь к картинке.

Собственно, примеры работы в различных режимах с одним и тем же исходным изображением. Размер исходной картинки — 450х411 пикселей.

Ресайз с добавлением полос к размеру 300х200 (image/b/300/200/img_1.jpg):

Работа ресайзера в данном случае простая. Сначала определяется, какая из сторон имеет больший коэффициент сжатия: 450/300 = 1.5 и 411/200 = 2.055. Затем изображение уменьшается в 2.055 раза по обоим параметрам, в результате чего получаем картинку в размере 219х200 и добавляются полосы слева и справа до заданных 300 пикселей. Аналогичным образом будет выглядеть и использование параметра t, так как формат сохраняемого в кеше изображения совпадает с исходным, а правильное его отображение (с прозрачностью) достигается за счет передачи header’ов для png изображений.

Ресайз с пропорциональным обрезанием к размеру 300х200 (image/c/300/200/img_1.jpg):

В данном случае будет выбран минимальный из коэффициентов сжатия, в данном случае — 1.5. Затем изображение уменьшается в 1.5 раза по обоим параметрам, что дает на выходе 300х274, а затем лишние 74 будут обрезаны — по 37 сверху и снизу.

Если не указать параметр высоты, оставив только ширину, то она будет рассчитана автоматически. К примеру, для ширины 300 — это 2/3 от ширины исходного изображения, значит и новая высота должна составить 2/3 от исходных 411, а конкретно 274 (image/b/300/img_1.jpg):

Аналогичным образом, если указать ширину равной нулю, то получим её автоматический расчет (image/b/0/300/img_1.jpg):

Сам скрипт

image.php

<?  error_reporting( 0 ); //цвет "полос" по бокам $color = array( 255, 255, 255 ); $file_name = $_GET["src"]; list( $width, $height, $ext ) = getimagesize( $file_name );  //задаем новые ширину и высоту $params["width"] = (int)$_GET["w"]; if( !isset( $_GET["h"] ) || 0 == (int)$_GET["h"] ){ 	$params["height"] = $height * $params["width"]/$width; } else { 	$params["height"] = (int)$_GET["h"]; } if( 0 == $params["width"] ){ 	$params["width"] = $width * $params["height"]/$height; }  //папка с кешем изображений. Внутри img_cache/ повторяется полный путь исходного изображения $cache_file_folder = "img_cache/" . substr( $file_name, 0, strrpos( $file_name, "/" ) ); $cache_file_name = "img_cache/" . substr( $file_name, 0, strrpos( $file_name, "." ) ) . "_" . $_GET["resize_type"] . "_" . $params["width"] . "_" . $params["height"] . substr( $file_name, strrpos( $file_name, "." ) );  //проверка наличия изображения в кеше. Если оно есть и было создано после последнего изменения исходного изображения - берем его if( file_exists( $cache_file_name ) ){ 	if( filemtime( $cache_file_name ) > filemtime( $file_name ) ){ 		if( 1 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_GIF ) ); 		} else if( 2 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_JPEG ) ); 		} else if( 3 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_PNG ) ); 		} 		//обновление времени последнего изменения. Используется, если необходима очистка давно не запрашиваемых картинок 		touch( $cache_file_name ); 		echo file_get_contents( $cache_file_name ); 		exit(); 	} }  //пытаемся создать папку для кеша mkdir( $cache_file_folder, 0755, true );  //непосредственно код ресайзинга switch( $_GET["resize_type"] ){ 	case "b": 		if( 1 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_GIF ) ); 			$image = imagecreatefromgif( $file_name ); 		} else if( 2 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_JPEG ) ); 			$image = imagecreatefromjpeg( $file_name ); 		} else if( 3 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_PNG ) ); 			$image = imagecreatefrompng( $file_name ); 		} 		$new_width = (int)$params["width"]; 		$new_height = (int)$params["height"]; 		if( $new_width == 0 || $new_height == 0 || !$image || !in_array( $ext, array( 1, 2, 3 ) ) ){ 			$image_new = imagecreatetruecolor( 100, 30 ); 			$bgc = imagecolorallocatealpha( $image_new, $color[0], $color[1], $color[2], 127 ); 			$tc = imagecolorallocate( $image_new, 0, 0, 0 ); 			imagefilledrectangle( $image_new, 0, 0, 100, 30, $bgc ); 			imagestring( $image_new, 1, 5, 5, "Error loading", $tc ); 			if( 1 == $ext ){ 				imagegif( $image_new ); 				imagedestroy( $image_new ); 			} else if( 2 == $ext ){ 				imagejpeg( $image_new ); 				imagedestroy( $image_new ); 			} else if( 3 == $ext ){ 				imagepng( $image_new ); 				imagedestroy( $image_new ); 			} 			exit(); 		} 		$image_new = imagecreatetruecolor( $new_width, $new_height ); 		imagealphablending( $image_new, false ); 		imagesavealpha( $image_new, true ); 		$bgc = imagecolorallocatealpha( $image_new, $color[0], $color[1], $color[2], 127 ); 		imagefilledrectangle( $image_new, 0, 0, $new_width, $new_height, $bgc ); 		if( $new_width/$new_height > $width/$height ){ 			$ins = $width*($new_height/$height); 			$out = ( $new_width - $ins )/2; 			imagecopyresampled( $image_new, $image, $out, 0, 0, 0, $ins, $new_height, $width, $height ); 		} else { 			$ins = $height*($new_width/$width); 			$out = ( $new_height - $ins )/2; 			imagecopyresampled( $image_new, $image, 0, $out, 0, 0, $new_width, $ins, $width, $height ); 		} 		 		if( 1 == $ext ){ 			imagegif( $image_new ); 			imagegif( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} else if( 2 == $ext ){ 			imagejpeg( $image_new ); 			imagejpeg( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} else if( 3 == $ext ){ 			imagepng( $image_new ); 			imagepng( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} 	break; 	case "t": 		if( 1 == $ext ){ 			$image = imagecreatefromgif( $file_name ); 		} else if( 2 == $ext ){ 			$image = imagecreatefromjpeg( $file_name ); 		} else if( 3 == $ext ){ 			$image = imagecreatefrompng( $file_name ); 		} 		header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_PNG ) ); 		$new_width = (int)$params["width"]; 		$new_height = (int)$params["height"]; 		if( $new_width == 0 || $new_height == 0 || !$image || !in_array( $ext, array( 1, 2, 3 ) ) ){ 			$image_new = imagecreatetruecolor( 100, 30 ); 			$bgc = imagecolorallocatealpha( $image_new, $color[0], $color[1], $color[2], 127 ); 			$tc = imagecolorallocate( $image_new, 0, 0, 0 ); 			imagefilledrectangle( $image_new, 0, 0, 100, 30, $bgc ); 			imagestring( $image_new, 1, 5, 5, "Error loading", $tc ); 			if( 1 == $ext ){ 				imagegif( $image_new ); 				imagedestroy( $image_new ); 			} else if( 2 == $ext ){ 				imagejpeg( $image_new ); 				imagedestroy( $image_new ); 			} else if( 3 == $ext ){ 				imagepng( $image_new ); 				imagedestroy( $image_new ); 			} 			exit(); 		} 		$image_new = imagecreatetruecolor( $new_width, $new_height ); 		imagealphablending( $image_new, false ); 		imagesavealpha( $image_new, true ); 		$bgc = imagecolorallocatealpha( $image_new, $color[0], $color[1], $color[2], 127 ); 		imagefilledrectangle( $image_new, 0, 0, $new_width, $new_height, $bgc ); 		if( $new_width/$new_height > $width/$height ){ 			$ins = $width*($new_height/$height); 			$out = ( $new_width - $ins )/2; 			imagecopyresampled( $image_new, $image, $out, 0, 0, 0, $ins, $new_height, $width, $height ); 		} else { 			$ins = $height*($new_width/$width); 			$out = ( $new_height - $ins )/2; 			imagecopyresampled( $image_new, $image, 0, $out, 0, 0, $new_width, $ins, $width, $height ); 		} 		imagepng( $image_new ); 		imagepng( $image_new, $cache_file_name ); 		imagedestroy( $image_new ); 	break; 	case "c": 		if( 1 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_GIF ) ); 			$image = imagecreatefromgif( $file_name ); 		} else if( 2 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_JPEG ) ); 			$image = imagecreatefromjpeg( $file_name ); 		} else if( 3 == $ext ){ 			header( "Content-type: " . image_type_to_mime_type( IMAGETYPE_PNG ) ); 			$image = imagecreatefrompng( $file_name ); 		} 		$new_width = (int)$params["width"]; 		$new_height = (int)$params["height"]; 		if( $new_width == 0 || $new_height == 0 || !$image || !in_array( $ext, array( 1, 2, 3 ) ) ){ 			$image_new = imagecreatetruecolor( 100, 30 ); 			$bgc = imagecolorallocate( $image_new, 255, 255, 255 ); 			$tc = imagecolorallocate( $image_new, 0, 0, 0 ); 			imagefilledrectangle( $image_new, 0, 0, 100, 30, $bgc ); 			imagestring( $image_new, 1, 5, 5, "Error loading", $tc ); 			if( 1 == $ext ){ 				imagegif( $image_new ); 				imagedestroy( $image_new ); 			} else if( 2 == $ext ){ 				imagejpeg( $image_new ); 				imagedestroy( $image_new ); 			} else if( 3 == $ext ){ 				imagepng( $image_new ); 				imagedestroy( $image_new ); 			} 			exit(); 		} 		$image_new = imagecreatetruecolor( $new_width, $new_height ); 		imagealphablending( $image_new, false ); 		imagesavealpha( $image_new, true ); 		$width/$new_width < $height/$new_height ? $coef = $width/$new_width : $coef = $height/$new_height; 		$start_x = ( $width - $new_width*$coef )/2; 		$start_y = ( $height - $new_height*$coef )/2; 		$end_x = $width - 2*$start_x; 		$end_y = $height - 2*$start_y; 		imagecopyresampled( $image_new, $image, 0, 0, $start_x, $start_y, $new_width, $new_height, $end_x, $end_y ); 		if( 1 == $ext ){ 			imagegif( $image_new ); 			imagegif( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} else if( 2 == $ext ){ 			imagejpeg( $image_new ); 			imagejpeg( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} else if( 3 == $ext ){ 			imagepng( $image_new ); 			imagepng( $image_new, $cache_file_name ); 			imagedestroy( $image_new ); 		} 	break; } 

.htaccess:

<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /  RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^image/([a-z])/([0-9]+)/([0-9]+)/([A-z0-9-\/\.]+)$ image.php?resize_type=$1&w=$2&h=$3&src=$4 [QSA,L]  RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^image/([a-z])/([0-9]+)/([A-z0-9-\/\.]+)$ image.php?resize_type=$1&w=$2&src=$4 [QSA,L]  </IfModule> 

Спасибо за внимание. Надеюсь, скрипт кому-нибудь да пригодится.

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


Комментарии

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

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