Работа с изображениями в PHP. Делаем thumbnails

Когда я еще только начинал набираться опыта в программировании на более-менее серьезных проектах, я всё писал с нуля (чего и вам советую, если вы хотите по-настоящему разбираться в языке). Потом, когда достигнете понимания, переходите на более сложные вещи, разберитесь в чужом коде: каком-нибудь фреймворке или движке, как он устроен и почему именно так. А вообще, сейчас не об этом. Так я часто не то чтобы изобретал велосипед, а скорее собирал его по деталям =) Парой таких деталей стали функции для работы с изображениями в PHP.

Приведу их ниже и разберу, может полезно кому будет =)

Я их делал для генерации самнейлов (thumbnails).

Первая getProportions($width, $height, $max_w, $max_h) вычисляет размеры уменьшенного изображения с соблюдением пропорций картинки. $width это ширина текущего большого изображения, $height соответственно - текущая высота, а $max_w и $max_h это максимальные ширина и высота будущей "тумбы", т.е. эти значения не должны превышаться.

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

Вторая функция makeSmaller() непосредственно занимается уменьшением и использует getProportions(), так что до нее еще дойдем, а пока...

// функция для получения пропорций
function getProportions($width, $height, $max_w, $max_h) {

   // получаем соотношение
   $ratio = $width / $height;
 
  if ( $ratio == 1 ) { // если стороны равны
    if ( $height > $max_h ) {
      $height = $width = min($max_w, $max_h);
    }
    else {
      $width = $max_w;
      $height = $max_h;
    }
   }
  else if ( $ratio > 1 ) { // если ширина больше высоты
    $height = ( $height * $max_w ) / $width;
    $width = $max_w;
  }
  else if ( $ratio < 1 ) { // если больше высота
    $width = ( $width * $max_h ) / $height;
    $height = $max_h;
  }
 
  return array('width' => $width, 'height' => $height);
}


А теперь беремся за нашу основную функцию-"ресайзилку" :)
Небольшое введение в работу с библиотекой GD2: чтобы проводить какие-то манипуляции с изображением, вам нужно загрузить его в оперативную память. Для этого используются функции imagecreate(), imagecreatetruecolor(), imagecreatefromjpeg() и другие (полный список всех функций GD2 тут). Приведенные в частности возвращают так называемый "ресурс" изображения (поэтому переменные у меня обзываются $im_res и $small_res). Именно ввиду этого, если вы новичок, простое уменьшение картинки вам может показаться чересчур мудреным.

Наша функция называется makeSmaller() и принимает следующие аргументы: $image_path - путь к изображению, которое мы хотим уменьшить, $width - требуемая ширина, $height - требуемая высота, $smaller - путь к новому уменьшенному изображению.

В частном порядке расскажу о функции imagecopyresampled(), поскольку без нее функция называлась бы makeSomeStupidityButNotSmaller().

Итак, 
imagecopyresampled (
  $dst_image - ресурс конечного изображения, т.е. самнэйла нашего, 
  $src_image - ресурс исходного изображения, 
  $dst_x - с какого пиксела начать вставку в уменьшенном изображении (destination X), т.е. как бы точка отсчета,
  $dst_y - с какого пиксела по оси Y, 
  $src_x - с какого пиксела по X исходного изображения брать данные, 
  $src_y - то же, но по Y, 
  $dst_w - какая ширина будет у , 
  $dst_h , 
  $src_w , 
  $src_h 
)

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

Пример: мы хотим взять изображение 800х600 и уменьшить его до 400х300, тогда пишем
imagecopyresampled($dst_im, $src_im, 0, 0, 0, 0, 400, 300, 800, 600);
а если нам нужно взять не все изображение, а с отступом в 20 пикселей и вставить в изображение с параметрами 200х150, то мы можем написать так
imagecopyresampled($dst_im, $src_im, 0, 0, 20, 20, 200, 150, 760, 560);

Надеюсь, более-менее понятно %) А вот и сама функция makeSmaller()

function makeSmaller($image_path, $width, $height, $smaller) {

   // получаем тип изображения
   $type = exif_imagetype($image_path);
 
   if ( $type == IMAGETYPE_JPEG ) {
     // создаем ресурс изображения, с которым мы будем работать, из файла $image_path
     $im_res = imagecreatefromjpeg($image_path);
   }
   else if ( $type == IMAGETYPE_GIF ) {
     $im_res = imagecreatefromgif($image_path);
   }
  else if ( $type == IMAGETYPE_PNG ) {
     $im_res = imagecreatefrompng($image_path);
   }
   else // а если нам подкинули файл левого типа, то мы молча отстраняемся и забиваем на задачу
     return false;
 
   $imw = imagesx($im_res); // узнаем ширину полученного изображения
   $imh = imagesy($im_res); // высоту
 
   // и вот тут мы используем ту нашу первую функцию
   $props = getProportions($imw, $imh, $width, $height);
 
   $small_res = imagecreatetruecolor($width, $height); // создаем ресурс изображения; лучше использовать imagecreatetruecolor вместо imagecreate, т.к. цветопередача, а следовательно и качество, пострадают. Можете сами поэкспериментировать
   $grey = imagecolorallocate($small_res, 218, 218, 218); // чтобы использовать какой-то цвет в функциях gd2 (например imagefill), сначала нужно создать его "идентификатор", чем и занимается функция imagecolorallocate
 
   // а здесь, собственно, заливаем нашим цветом уменьшенное изображение, ресурс которого недавно создали
   imagefill($small_res, 0, 0, $grey);
 
   imagecopyresampled($small_res, $im_res, round(($width - $props['width']) / 2), round(($height - $props['height']) / 2), 0, 0, $props['width'], $props['height'], $imw, $imh);
 
 /*
 К чему такие странные вычисления? Мне нужно узнать, с какой точки вставлять картинку, т.к. она может либо по ширине, либо по высоте оказаться меньше, чем задано. То есть если мы изображение размером 400х300 уменьшаем этой функцией до 200х200, то наше получится 200х150, но нам его хотелось бы отцентрировать, для этого и вычисляем точку отсчета.
 */
 
   if ( $type == IMAGETYPE_JPEG ) {
     imagejpeg($small_res, $smaller, 100); // сохраняем в файл $smaller; 100 - это качество, указывается для jpeg
   }
   else if ( $type == IMAGETYPE_GIF ) {
     imagegif($small_res, $smaller);
   }
   else if ( $type == IMAGETYPE_PNG ) {
     imagepng($small_res, $smaller);
   }
}

Итак, если у меня есть картинка cat.jpg

Котик

То после применения функции makeSmaller('cat.jpg', 320, 260, 'cat-small.jpg') у меня теперь будет еще и такая

Думаю, вы понимаете, откуда светло-серые поля. В функцией можно и нужно поэкспериментировать для своего же развития, чтобы лучше понять, да и просто подогнать под свои нужды. Удачи)

 Жду с нетерпением
ваших комментариев!
 

Подписаться на RSS

Вы можете нажать "подписаться", чтобы следить за моими новостями!
Так вы всегда будете в курсе появления новостей на сайте =)
О том, что такое RSS можно прочитать здесь.

Подписаться

Подписаться на Twitter

Я специально зарегистрировался в Твиттере, чтобы вы могли следить за обновлениями на сайте =)

Подписаться

Envato marketplace А эти люди занимаются прокатом карнавальных костюмов и масок в Минске. К слову, я им делал сайт.