Работа с изображениями на PHP


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

Конечно, можно обрабатывать изображение в фотошопе и только после этого загружать его на сервер. А что если контент-менеджер сайта «тетя Люся», которая даже не представляет, что фотографии можно редактировать ещё чем-то кроме ножниц и карандашей, будет загружать фотки? В этом случае все ваши старания, порой большие, по верстке шаблона сайта могут отправиться «тетё Люсе» в пятую точку.

Настало время, и я решил заполнить этот пробел в своих знаниях. Об этом сейчас и поговорим.

Начнем с первой проблемой с которой я столкнулся – это конвертация .png в .jpg средствами php. Казалось-бы – поменял расширение и готово. Но если начать работать с получившимся изображением через php, зразу появляются ошибки.

Для полноценной конвертации png в jpg я написал следующую функцию:

<?
function png2jpg($originalFile, $outputFile)
   {
   if (file_exist($originalFile)) {
      $type = getimagesize($originalFile);
      if ($type['mime'] == "image/png") {
         $source = imagecreatefrompng($originalFile);
         $image = imagecreatetruecolor(imagesx($source), imagesy($source));
         
         $white = imagecolorallocate($image, 255, 255, 255);
         imagefill($image, 0, 0, $white);
      
         imagecopy($image, $source, 0, 0, 0, 0, imagesx($image), imagesy($image));
   
         imagejpeg($image, $outputFile, 75);
         imagedestroy($image);
         imagedestroy($source);
         } else {
         copy($originalFile, $outputFile);
         }
      }
   }
?>

Разберём функцию построчно:

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

png2jpg($_SERVER[‘DOCUMENT_ROOT’].’/pic/file.png’, $_SERVER[‘DOCUMENT_ROOT’].’/pic/EndFile.jpg’);

Далее функция проверяет существует ли файл или нет. Это больше для удобства.

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

Если поискать описание функции getimagesize() в интернете, то скорее всего вы найдёте что-то вроде «возвращает размеры изображения». На деле все обстоит несколько иначе. Функция возвращает не только размеры, но и биты, число каналов и тип файла, но это так, отступление.
Так вот, этой функцией мы получаем тип файла и проверяем чтобы он обязательно был png. В противном случае, программа просто скопирует изначальное изображение с именем конечного. Задача всё-таки такая)))

Начиная с седьмой строчки, функция создает из изображения специальный объект, с которым уже можно работать программно. Этот объект заносится в переменную $source.

Функция imagecreatetruecolor() создает изображение заданных размеров черного цвета (по умолчанию далее мы его перекрасим). Именно его мы будем подкладывать под png, чтоб залить фон белым цветом.

Функция imagecolorallocate() как раз создает белую заливку, которая объединяется с $source функцией imagefill(). Вот мы и получили белый фон.
И последний шаг, на который стоит обратить внимание, это объединение белого фона с png-изображением, для того чтобы вышла jpg.
Последний – завершающий шаг из объекта формируется изображение функцией imagejpeg(). В неё передается сам объект, путь, где будет создано изображение, и качество (75 будет достаточно).

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

Вот мы и получили простую, на первый взгляд, функцию.

Если вас интересует конвертация JPEG в PNG, создавая прозрачный фон у изображения, можете почитать об этом здесь. В данной статье я не стал об этом рассказывать, т.к. это отдельная история и требует отдельного рассмотрения.

Следующая проблема, с корой я столкнулся – это изменение размеров изображения на php.

Например, контент-менеджер загружает на сайта изображение 1000 на 1000 пикселей. Для сайта вполне достаточно 500 на 500. Конечно можно ужимать изображения параметрами у тега <img>, но это не правильно, т.к. это все трафик посетителя сайта. А его нужно экономить…

Тут мне помогла следующая функция, которую мне пришлось собирать по крупицам с пендосовских форумов:

<?
function resizeImage($urlToImg, $_width, $_height = 0)  {
   $urlToImg = trim($urlToImg);

   if (file_exists($urlToImg)) {

      list($width, $height, $type, $attr) = getimagesize($urlToImg);
      $ratio = $width / $height;

      $type = getimagesize($urlToImg);

      switch ($type['mime']) {
         case "image/jpeg":
         $isrc = imageCreateFromJPEG($urlToImg);
         break;

         case "image/gif":
         $isrc = imageCreateFromGIF($urlToImg);
         break;

         case "image/png":
         $isrc = imageCreateFromPNG($urlToImg);
         break;

         default:
         die("<p style='color:red;'>Тип файла не распознан - " . $type['mime'] . "</p>");
         }

   imagealphablending($isrc, false); //что-то из черной магии
   imagesavealpha($isrc, true); // походу имгэху делает прозрачной.... (если конечно это пээнгэшка)


   //if ($width < $_width) {return 0;} // Если она уже меньше нужной ширины, то ничего не меняю и выхожу из функции...
   if ($_height == 0) {
      $sheight = floor($_width / $ratio);
      } else {
      $sheight = $_height;
      }
   $idest = imagecreatetruecolor($_width, $sheight);
   $bg = imagecolorallocate($idest, 255, 255, 255);
   imagealphablending($idest, false); //что-то из черной магии
   imagesavealpha($idest, true); // походу имгэху делает прозрачной....
   imagefill($idest, 0, 0, $bg);
   imagecopyresampled($idest, $isrc, 0, 0, 0, 0, $_width, $sheight, $width, $height);

   switch ($type['mime']) {
      case "image/jpeg":
      imagejpeg($idest, $urlToImg);
      break;

      case "image/gif":
      imagegif($idest, $urlToImg);
      break;

      case "image/png":
      imagepng($idest, $urlToImg);
      break;

      default:
      die("<p style='color:red;'>Тип файла не распознан - " . $type['mime'] . "</p>");
      }
   
   } else {
   echo "<p style='color:red;'>Изображение не найдено!!!</p>";
   return 0;
   }
}
?>

Данная функция чем-то похожа на предыдущую, но она немного универсальнее.

Во первых – она определяет тип файла, и в зависимости от типа, создает разные объекты. Тоже самое относится и созданию файлов в конце функции.
Во вторых – если ей помимо ссылки на изображения указать ещё и ширину изображения, она растянет изображение и параллельно подсчитает сколько необходимо сделать высоту, чтобы сохранить пропорции изображения.

Если скормить функции третий параметр – высоту изображения, то она не будет соблюдать пропорции, а сделает их такими, какие указаны в параметрах.

Теперь предположим, что верстка вашего интернет магазина рассчитана только на квадратный изображения 500 на 500 пикселей. А менеджер «тётя Люся» загружает какие есть.

Конечно, можно воспользоваться предыдущей функцией, и задать ей два последних параметра 500 и 500. Но в этом случае, если изображение изначально не квадратное, то на выходе получим растянутое «безобразие».

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

<?
function imageresize_to_square($urlToImg, $new_size)   {
$urlToImg = trim($urlToImg);

if (file_exists($urlToImg)) {
   $type = getimagesize($urlToImg);

   switch ($type['mime']) {
      case "image/jpeg":
      $isrc = imageCreateFromJPEG($urlToImg);
      break;

      case "image/gif":
      $isrc = imageCreateFromGIF($urlToImg);
      break;

      case "image/png":
      $isrc = imageCreateFromPNG($urlToImg);
      break;

      default:
      die("<p style='color:red;'>Тип файла не распознан - " . $type['mime'] . "</p>");
      }
   
   $k1 = $new_size / imagesx($isrc);
   $k2 = $new_size / imagesy($isrc);
   
   $koordX = 0;
   $koordY = 0;
   if ($k1 > $k2) {
      // Высокая картинка
      $k = $k2;
      $koordX = ($new_size / 2) - (intval(imagesx($isrc) * $k) / 2);
      } else {
      // Широкая картинка
      $k = $k1;
      $koordY = ($new_size / 2) - (intval(imagesy($isrc) * $k) / 2);
      }

   $w = intval(imagesx($isrc) * $k);
   $h = intval(imagesy($isrc) * $k);
   
   $idest = imagecreatetruecolor($new_size, $new_size);
   
   /*Делаю фон белый*/
   $bg = imagecolorallocate($idest, 255, 255, 255);
   imagealphablending($idest, false); //что-то из черной магии
   imagesavealpha($idest, true); // походу имгэху делает прозрачной....
   imagefill($idest, 0, 0, $bg);
   /* Все, фон белый */
   
   imagecopyresampled($idest, $isrc, $koordX, $koordY, 0, 0, $w, $h, imagesx($isrc),
   imagesy($isrc));
   
   
   switch ($type['mime']) {
      case "image/jpeg":
      imagejpeg($idest, $urlToImg);
      break;

      case "image/gif":
      imagegif($idest, $urlToImg);
      break;

      case "image/png":
      imagepng($idest, $urlToImg);
      break;

      default:
      die("<p style='color:red;'>Тип файла не распознан - " . $type['mime'] . "</p>");
      }
   
   imagedestroy($isrc);
   imagedestroy($idest);
   }
}
?>

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

Если найдете какие-то неточности, я с удовольствием их выслушаю.

 


Тэги:

Комментарии: 3

Прокомментировать »

 
 
Анал Запорович Неудержимый
28.05.2013
 

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

Мурад
16.11.2015
 

А как jpg в jpeg то преобразовать? нет такой функции или она не нужна и подходит одна из тех что перечислены? тем более jpg один из самых частых

LAVRIK
16.11.2015
 

JPG и JPEG это одно и тоже...

 

Прокомментировать

 
 
Сообщение *
 
Проверочный код *
 
 
 
Яндекс.Метрика