Ресайз картинок (фотографий) на PHP
PHP

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

Добавить комментарий