Недавно возникла необходимость изменять размер фотографий (да и вообще картинок) средствами 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;
- }
- }
- }
- }
- }