Недавно возникла необходимость изменять размер фотографий (да и вообще картинок) средствами 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; } } } } }
root4root aka admin
Большое спасибо за скрипт! Сэкономил много времени.
[…] времен публикации предыдущей статьи уже много воды утекло. Библиотека стала более […]
Огромное спасибо!
[…] ← Предыдущая Следующая → […]