Недавно возникла необходимость изменять размер фотографий (да и вообще картинок) средствами PHP. Покопавшись в интернете, нашел небольшую библиотеку. Но у нее обнаружился ряд недостатков, а именно:
1. Если делать из большой фотографии маленькую — сильно страдает качество (нет экстраполяции)
2. Нет разворота по EXIF. Если загружать прямо с фотоаппарата, без предварительной обработки, вертикальные снимки становятся горизонтальными. То есть отображаются боком.
3. Нет проверки на корректность исходного файла (битый снимок, например; или файл с неверным расширением).
4. Невозможно применить фильтр sharpen. Он очень даже нужен, поскольку при сильном уменьшении фото теряет четкость. Актуально при использовании resample.
5. Оригинальное изображение нигде не сохраняется в библиотеке, а переписывается. Так что если сделать сначала маленькую картинку, а потом среднюю — последняя будет наипоганейшего качества, т.к. увеличится из маленткой (!). Да и вообще ресайз в несколько этапов сильно хуже, чем в один. Приходится загружать исходник заново через функцию load. Неудобно…
Что добавлено:
1. Функция resample($width, $height). В оригинальном классе есть только resize. Различие между ними в том, что resample экстраполирует (сглаживает) изображение, а resize — нет. Поэтому в последнем случае картинка получается как бы из «кубиков». Особенно хорошо видно при сильном уменьшении.
2. resampleToHeight($height) — аналогично resizeToHeight но с экстраполяцией.
3. resampleToWidth($width) — тоже самое, но по ширине.
4. sharpen($strenght = 18) — чем меньше параметр, тем сильнее sharpen. По дефолту 18, почти всегда достаточно.
5. exifrotate — запускается из функции load автоматически, для формата JPEG.
При «неправильном» (битом, не читающемся, не поддерживающемся и т.д.) файле, вызов load возвращает false. На данный момент библиотека GD поддерживает 3 формата: png, gif и jpg. В связи с этим, мой класс тоже поддерживает только вышеозначенные типы.
Излишне напоминать, что для работы необходима поддержка GD и EXIF в PHP.
Пару примеров:
Изменяем размер картинки picture.jpg до ширины 250 и высоты 400. Пропорции не сохраняются:
- <?php
 - include(‘SimpleImage.php’); //Подключаем библиотеку
 - $image = new SimpleImage(); //Инициируем экземпляр класса
 - $image—>load(‘picture.jpg’); //Загружаем фото (картинку)
 - $image—>resample(250,400); //Изменяем размер со сглаживанием.
 - $image—>sharpen(); //Придаем резкость (не обязательно)
 - $image—>save(‘picture2.jpg’); //Сохраняем в файл
 
Делаем ресайз по ширине, при этом сохраняются пропорции:
- <?php
 - include(‘SimpleImage.php’);
 - $image = new SimpleImage();
 - $image—>load(‘picture.jpg’);
 - $image—>resampleToWidth(250);
 - header(‘Content-Type: image/jpeg’); //Обязательно отправляем перед выводом заголовок
 - $image—>output(); //Выводим на экран, вместо сохранения.
 
Что делают остальные функции легко догадаться изучив код.
Непосредственно сам класс:
- <?php
 - class SimpleImage
 - {
 - public $nativeimg;
 - public $image;
 - public $image_type;
 - public function load($filename)
 - {
 - $image_info = getimagesize($filename);
 - $this—>image_type = $image_info[2];
 - if( $this—>image_type == IMAGETYPE_JPEG )
 - {
 - $this—>nativeimg = imagecreatefromjpeg($filename);
 - if($this—>getHeight() < $this—>getWidth())
 - $this—>exifrotate($filename);
 - return true;
 - }
 - elseif( $this—>image_type == IMAGETYPE_GIF )
 - {
 - $this—>nativeimg = imagecreatefromgif($filename);
 - return true;
 - }
 - elseif( $this—>image_type == IMAGETYPE_PNG )
 - {
 - $this—>nativeimg = imagecreatefrompng($filename);
 - return true;
 - }
 - else
 - return false;
 - }
 - public function save($filename, $image_type=IMAGETYPE_JPEG, $compression=90, $owner=null, $permissions=null)
 - {
 - if( $image_type == IMAGETYPE_JPEG )
 - {
 - imagejpeg($this—>image,$filename,$compression);
 - }
 - elseif( $image_type == IMAGETYPE_GIF )
 - {
 - imagegif($this—>image,$filename);
 - }
 - elseif( $image_type == IMAGETYPE_PNG )
 - {
 - imagepng($this—>image,$filename);
 - }
 - if( $permissions != null)
 - {
 - chown($filename, $permissions);
 - }
 - if( $permissions != null)
 - {
 - chmod($filename, $owner);
 - }
 - }
 - public function output($image_type=IMAGETYPE_JPEG)
 - {
 - if( $image_type == IMAGETYPE_JPEG )
 - {
 - imagejpeg($this—>image);
 - }
 - elseif( $image_type == IMAGETYPE_GIF )
 - {
 - imagegif($this—>image);
 - }
 - elseif( $image_type == IMAGETYPE_PNG )
 - {
 - imagepng($this—>image);
 - }
 - }
 - public function getWidth()
 - {
 - return imagesx($this—>nativeimg);
 - }
 - public function getHeight()
 - {
 - return imagesy($this—>nativeimg);
 - }
 - public function resizeToHeight($height)
 - {
 - $ratio = $height / $this—>getHeight();
 - $width = $this—>getWidth() * $ratio;
 - $this—>resize($width,$height);
 - }
 - public function resizeToWidth($width)
 - {
 - $ratio = $width / $this—>getWidth();
 - $height = $this—>getheight() * $ratio;
 - $this—>resize($width,$height);
 - }
 - public function resampleToHeight($height)
 - {
 - $ratio = $height / $this—>getHeight();
 - $width = $this—>getWidth() * $ratio;
 - $this—>resample($width,$height);
 - }
 - public function resampleToWidth($width)
 - {
 - $ratio = $width / $this—>getWidth();
 - $height = $this—>getheight() * $ratio;
 - $this—>resample($width,$height);
 - }
 - public function scale($scale)
 - {
 - $width = $this—>getWidth() * $scale/100;
 - $height = $this—>getheight() * $scale/100;
 - $this—>resize($width,$height);
 - }
 - public function resize($width,$height)
 - {
 - $new_image = imagecreatetruecolor($width, $height);
 - imagecopyresized($new_image, $this—>nativeimg, 0, 0, 0, 0, $width, $height, $this—>getWidth(), $this—>getHeight());
 - $this—>image = $new_image;
 - }
 - public function resample($width,$height)
 - {
 - $new_image = imagecreatetruecolor($width, $height);
 - imagecopyresampled($new_image, $this—>nativeimg, 0, 0, 0, 0, $width, $height, $this—>getWidth(), $this—>getHeight());
 - $this—>image = $new_image;
 - }
 - public function sharpen($strenght = 18)
 - {
 - /*Less value in the middle means more sharpen*/
 - $sharpen_matrix=array( array(0, —1, 0),
 - array(—1, $strenght, —1),
 - array(0, —1, 0));
 - $divisor=array_sum(array_map(‘array_sum’, $sharpen_matrix));
 - imageconvolution($this—>image, $sharpen_matrix, $divisor, 0);
 - }
 - public function exifrotate($path)
 - {
 - if(function_exists(‘exif_read_data’))
 - {
 - $exif = exif_read_data($path);
 - if(!empty($exif[‘Orientation’]))
 - {
 - switch($exif[‘Orientation’])
 - {
 - case 8:
 - $this—>nativeimg = imagerotate($this—>nativeimg, 90, 0);
 - break;
 - case 3:
 - $this—>nativeimg = imagerotate($this—>nativeimg, 180, 0);
 - break;
 - case 6:
 - $this—>nativeimg = imagerotate($this—>nativeimg, —90, 0);
 - break;
 - }
 - }
 - }
 - }
 - }