Класс Image.php

 

Класс Image

Класс предназначен для работы с изображения сайта (товары, категории и т.д)

Функция resize()

Код функции (спойлер)
     public function resize($filename,$original_images_dir = null, $resized_images_dir = null) {
        list($source_file, $width , $height, $set_watermark) = $this->get_resize_params($filename);

        $size = $width.'x'.$height;
        $image_sizes = array();
        if ($this->settings->image_sizes) {
            $image_sizes = explode('|', $this->settings->image_sizes);
        }
        if (!in_array($size, $image_sizes)){
            header("http/1.0 404 not found");
            exit();
        }

        // Если вайл удаленный (http://), зальем его себе
        if(substr($source_file, 0, 7) == 'http://') {
            // Имя оригинального файла
            if(!$original_file = $this->download_image($source_file)) {
                return false;
            }
            $resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
        } else {
            $original_file = $source_file;
        }

        $resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);

        // Пути к папкам с картинками
        if ($original_images_dir && !$resized_images_dir) {
            $resized_images_dir = $original_images_dir;
        } else {
            if (!$original_images_dir) {
                $original_images_dir = $this->config->original_images_dir;
            }
            if (!$resized_images_dir) {
                $resized_images_dir = $this->config->resized_images_dir;
            }
        }
        $originals_dir = $this->config->root_dir.$original_images_dir;
        $preview_dir = $this->config->root_dir.$resized_images_dir;

        $watermark_offet_x = $this->settings->watermark_offset_x;
        $watermark_offet_y = $this->settings->watermark_offset_y;

        $sharpen = min(100, $this->settings->images_sharpen)/100;
        $watermark_transparency =  1-min(100, $this->settings->watermark_transparency)/100;

        if($set_watermark && is_file($this->config->root_dir.$this->config->watermark_file)) {
            $watermark = $this->config->root_dir.$this->config->watermark_file;
        } else {
            $watermark = null;
        }

        if(class_exists('Imagick') && $this->config->use_imagick) {
            $this->image_constrain_imagick($originals_dir.$original_file, $preview_dir.$resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency, $sharpen);
        } else {
            $this->image_constrain_gd($originals_dir.$original_file, $preview_dir.$resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency);
        }

        return $preview_dir.$resized_file;
    }

Функция ресайза изображения (его нарезки до нужных размеров) Важно! Функция не делает кроп изображения, она его пропорционально уменьшает

Функция принимает три аргумента ($filename,$original_images_dir, $resized_images_dir)

Параметры которые содержит функция:

  • $filename - имя изображения
  • $original_images_dir - название директории с оригинальными фото
  • $resized_images_dir - название директории с уменьшенными изображениями

Функция возвращает полный путь к наресайзеному изображению


Функция add_resize_params()

Код функции (спойлер)
   /*Добавление параметров ресайза для изображения*/
    public function add_resize_params($filename, $width=0, $height=0, $set_watermark=false) {
        if('.' != ($dirname = pathinfo($filename,  PATHINFO_DIRNAME))) {
            $file = $dirname.'/'.pathinfo($filename, PATHINFO_FILENAME);
        } else {
            $file = pathinfo($filename, PATHINFO_FILENAME);
        }
        $ext = pathinfo($filename, PATHINFO_EXTENSION);

        if($width>0 || $height>0) {
            $resized_filename = $file.'.'.($width>0?$width:'').'x'.($height>0?$height:'').($set_watermark?'w':'').'.'.$ext;
        } else {
            $resized_filename = $file.'.'.($set_watermark?'w.':'').$ext;
        }

        return $resized_filename;
    }

Функция добавление пераметров ресайза к изображению

Функция принимает 4 аргумента $filename, $width, $height, $set_watermark

Параметры которые содержит функция:

  • $filename - имя изображения
  • $width - ширина изображения в пикселях
  • $height - высота изображения в пикселях
  • $set_watermark - установка водяного знака (true/false)

Функция возвращает имя файла с установленными параметрами


Функция get_resize_params()

Код функции (спойлер)
     /*Выборка параметров изображения для ресайза*/
    public function get_resize_params($filename) {
        // Определаяем параметры ресайза
        if(!preg_match('/(.+)\.([0-9]*)x([0-9]*)(w)?\.([^\.]+)$/', $filename, $matches)) {
            return false;
        }

        $file = $matches[1];                    // имя запрашиваемого файла
        $width = $matches[2];                    // ширина будущего изображения
        $height = $matches[3];                    // высота будущего изображения
        $set_watermark = $matches[4] == 'w';    // ставить ли водяной знак
        $ext = $matches[5];                        // расширение файла

        return array($file.'.'.$ext, $width, $height, $set_watermark);
    }

Функция для получения параметров ресайза из названия изображения

Функция принимает аргумент $filename

Параметры которые содержит функция:

  • $filename - название файла изображения

Функция возвращает массив с параметрами ресайза


Функция download_image()

Код функции (спойлер)
    /*Загрузка изображения*/
    public function download_image($filename) {
        // Заливаем только есть такой файл есть в базе
        $this->db->query('SELECT 1 FROM __images WHERE filename=? LIMIT 1', $filename);
        if(!$this->db->result()) {
            return false;
        }

        // Имя оригинального файла
        $basename = preg_replace('~(.+)\.([0-9]*)x([0-9]*)(w)?\.([^\.\?]+)(\?.*)?$~', '${1}.${5}', $filename);
        $basename = explode('&', pathinfo($basename, PATHINFO_BASENAME));
        $uploaded_file = array_shift($basename);
        $base = urldecode(pathinfo($uploaded_file, PATHINFO_FILENAME));
        $ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);

        // Если такой файл существует, нужно придумать другое название
        $new_name = urldecode($uploaded_file);

        while(file_exists($this->config->root_dir.$this->config->original_images_dir.$new_name)) {
            $new_base = pathinfo($new_name, PATHINFO_FILENAME);
            if(preg_match('/_([0-9]+)$/', $new_base, $parts)) {
                $new_name = $base.'_'.($parts[1]+1).'.'.$ext;
            } else {
                $new_name = $base.'_1.'.$ext;
            }
        }

        // Перед долгим копированием займем это имя
        fclose(fopen($this->config->root_dir.$this->config->original_images_dir.$new_name, 'w'));
        if (copy($filename, $this->config->root_dir.$this->config->original_images_dir.$new_name)) {
            $this->db->query('UPDATE __images SET filename=? WHERE filename=?', $new_name, $filename);
            return $new_name;
        } else {
            @unlink($this->config->root_dir.$this->config->original_images_dir.$new_name);
            return false;
        }
    }

Функция загрузки изображения с удаленного ресурса

Функция принимает аргумент $filename

Параметры которые содержит функция:

  • $filename - название файла изображения

Функция возвращает имя загруженного файла в случае успеха


Функция upload_image()

Код функции (спойлер)
   /*Загрузка изображения*/
    public function upload_image($filename, $name, $original_dir = null) {
        // Имя оригинального файла
        $name = preg_replace('~(.+)\.([0-9]*)x([0-9]*)(w)?\.([^\.\?]+)$~', '${1}.${5}', $name);
        $name = $this->correct_filename($name);
        $uploaded_file = $new_name = pathinfo($name, PATHINFO_BASENAME);
        $base = pathinfo($uploaded_file, PATHINFO_FILENAME);
        $ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);

        if (!$original_dir) {
            $original_dir = $this->config->original_images_dir;
        }
        if(in_array(strtolower($ext), $this->allowed_extentions)) {
            while(file_exists($this->config->root_dir.$original_dir.$new_name)) {
                $new_base = pathinfo($new_name, PATHINFO_FILENAME);
                if(preg_match('/_([0-9]+)$/', $new_base, $parts)) {
                    $new_name = $base.'_'.($parts[1]+1).'.'.$ext;
                } else {
                    $new_name = $base.'_1.'.$ext;
                }
            }
            if(move_uploaded_file($filename, $this->config->root_dir.$original_dir.$new_name)) {
                return $new_name;
            }
        }
        return false;
    }

Функция загрузки изображения на сервер

Функция принимает 3 аргумента ($filename, $name, $original_dir)

Параметры которые содержит функция:

  • $filename - путь к изображению на сервере (временная папка)
  • $name - имя файла изображения
  • $original_dir - директория назначения (папка в которую будет помещен новый файл)

Функция возвращает имя загруженного файла в случае успеха


Функция image_constrain_gd()

Код функции (спойлер)
   private function image_constrain_gd($src_file, $dst_file, $max_w, $max_h, $watermark=null, $watermark_offet_x=0, $watermark_offet_y=0, $watermark_opacity=1) {
        $quality = 100;

        // Параметры исходного изображения
        @list($src_w, $src_h, $src_type) = array_values(getimagesize($src_file));
        $src_type = image_type_to_mime_type($src_type);

        if(empty($src_w) || empty($src_h) || empty($src_type)) {
            return false;
        }

        // Нужно ли обрезать?
        if (!$watermark && ($src_w <= $max_w) && ($src_h <= $max_h)) {
            // Нет - просто скопируем файл
            if (!copy($src_file, $dst_file)) {
                return false;
            }
            return true;
        }

        // Размеры превью при пропорциональном уменьшении
        @list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);

        // Читаем изображение
        switch ($src_type) {
            case 'image/jpeg':
                $src_img = imageCreateFromJpeg($src_file);
                break;
            case 'image/gif':
                $src_img = imageCreateFromGif($src_file);
                break;
            case 'image/png':
                $src_img = imageCreateFromPng($src_file);
                imagealphablending($src_img, true);
                break;
            default:
                return false;
        }

        if(empty($src_img)) {
            return false;
        }

        $src_colors = imagecolorstotal($src_img);

        // create destination image (indexed, if possible)
        if ($src_colors > 0 && $src_colors <= 256) {
            $dst_img = imagecreate($dst_w, $dst_h);
        } else {
            $dst_img = imagecreatetruecolor($dst_w, $dst_h);
        }

        if (empty($dst_img)) {
            return false;
        }

        $transparent_index = imagecolortransparent($src_img);
        if ($transparent_index >= 0 && $transparent_index <= 128) {
            $t_c = imagecolorsforindex($src_img, $transparent_index);
            $transparent_index = imagecolorallocate($dst_img, $t_c['red'], $t_c['green'], $t_c['blue']);
            if ($transparent_index === false) {
                return false;
            }
            if (!imagefill($dst_img, 0, 0, $transparent_index)) {
                return false;
            }
            imagecolortransparent($dst_img, $transparent_index);
        }
        // or preserve alpha transparency for png
        elseif ($src_type === 'image/png') {
            if (!imagealphablending($dst_img, false)) {
                return false;
            }
            $transparency = imagecolorallocatealpha($dst_img, 0, 0, 0, 127);
            if (false === $transparency) {
                return false;
            }
            if (!imagefill($dst_img, 0, 0, $transparency)) {
                return false;
            }
            if (!imagesavealpha($dst_img, true)) {
                return false;
            }
        }

        // resample the image with new sizes
        if (!imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_w, $dst_h, $src_w, $src_h)) {
            return false;
        }

        // Watermark
        if(!empty($watermark) && is_readable($watermark)) {
            $overlay = imagecreatefrompng($watermark);

            // Get the size of overlay
            $owidth = imagesx($overlay);
            $oheight = imagesy($overlay);

            $watermark_x = min(($dst_w-$owidth)*$watermark_offet_x/100, $dst_w);
            $watermark_y = min(($dst_h-$oheight)*$watermark_offet_y/100, $dst_h);

            imagecopy($dst_img, $overlay, $watermark_x, $watermark_y, 0, 0, $owidth, $oheight);
        }

        // recalculate quality value for png image
        if ('image/png' === $src_type) {
            $quality = round(($quality / 100) * 10);
            if ($quality < 1) {
                $quality = 1;
            } elseif ($quality > 10) {
                $quality = 10;
            }
            $quality = 10 - $quality;
        }

        // Сохраняем изображение
        switch ($src_type) {
            case 'image/jpeg':
                return imageJpeg($dst_img, $dst_file, $quality);
            case 'image/gif':
                return imageGif($dst_img, $dst_file, $quality);
            case 'image/png':
                imagesavealpha($dst_img, true);
                return imagePng($dst_img, $dst_file, $quality);
            default:
                return false;
        }
    }

Функция построения конечного изображения с использованием библиотеки GD

Функция принимает такие аргументы ($src_file, $dst_file, $max_w, $max_h, $watermark, $watermark_offet_x, $watermark_offet_y)

Параметры которые содержит функция:

  • $src_file - исходный файл
  • $dst_file - файл с результатом
  • $max_w - максимальная ширина
  • $max_h - максимальная высота
  • $watermark - водяной знак
  • $watermark_offet_x - сдвиг знака по оси х
  • $watermark_offet_у - сдвиг знака по оси у

Функция возвращает построенный файл


Функция image_constrain_imagick()

Код функции (спойлер)
  private function image_constrain_imagick($src_file, $dst_file, $max_w, $max_h, $watermark=null, $watermark_offet_x=0, $watermark_offet_y=0, $watermark_opacity=1, $sharpen=0.2) {
        $thumb = new Imagick();

        // Читаем изображение
        if(!$thumb->readImage($src_file)) {
            return false;
        }

        // Размеры исходного изображения
        $src_w = $thumb->getImageWidth();
        $src_h = $thumb->getImageHeight();

        // Нужно ли обрезать?
        if (!$watermark && ($src_w <= $max_w) && ($src_h <= $max_h)) {
            // Нет - просто скопируем файл
            if (!copy($src_file, $dst_file)) {
                return false;
            }
            return true;
        }

        // Размеры превью при пропорциональном уменьшении
        list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);

        // Уменьшаем
        $thumb->thumbnailImage($dst_w, $dst_h);

        // Устанавливаем водяной знак
        if($watermark && is_readable($watermark)) {
            $overlay = new Imagick($watermark);
            $overlay->evaluateImage(Imagick::EVALUATE_MULTIPLY, $watermark_opacity, Imagick::CHANNEL_ALPHA);

            // Get the size of overlay
            $owidth = $overlay->getImageWidth();
            $oheight = $overlay->getImageHeight();

            $watermark_x = min(($dst_w-$owidth)*$watermark_offet_x/100, $dst_w);
            $watermark_y = min(($dst_h-$oheight)*$watermark_offet_y/100, $dst_h);
        }

        // Анимированные gif требуют прохода по фреймам
        foreach($thumb as $frame) {
            // Уменьшаем
            $frame->thumbnailImage($dst_w, $dst_h);

            /* Set the virtual canvas to correct size */
            $frame->setImagePage($dst_w, $dst_h, 0, 0);

            // Наводим резкость
            if($sharpen > 0) {
                $thumb->adaptiveSharpenImage($sharpen, $sharpen);
            }

            if(isset($overlay) && is_object($overlay)) {
                $frame->compositeImage($overlay, imagick::COMPOSITE_OVER, $watermark_x, $watermark_y, imagick::COLOR_ALPHA);
            }
        }

        // Убираем комменты и т.п. из картинки
        $thumb->stripImage();
        $thumb->setImageCompressionQuality($this->settings->image_quality ? $this->settings->image_quality : 80 );
        $thumb->setImageCompression($this->settings->image_quality ? $this->settings->image_quality : 80);

        // Записываем картинку
        if(!$thumb->writeImages($dst_file, true)) {
            return false;
        }

        // Уборка
        $thumb->destroy();
        if(isset($overlay) && is_object($overlay)) {
            $overlay->destroy();
        }
        return true;
    }

Функция построения конечного изображения с использованием библиотеки Imagick

Функция принимает такие аргументы ($src_file, $dst_file, $max_w, $max_h, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_opacity, $sharpen)

Параметры которые содержит функция:

  • $src_file - исходный файл
  • $dst_file - файл с результатом
  • $max_w - максимальная ширина
  • $max_h - максимальная высота
  • $watermark - водяной знак
  • $watermark_offet_x - сдвиг знака по оси х
  • $watermark_offet_у - сдвиг знака по оси у
  • $watermark_opacity - прозрачность водяного знака
  • $sharpen - резкость изображения

Функция возвращает построенный файл


Функция calc_contrain_size()

Код функции (спойлер)
    public function calc_contrain_size($src_w, $src_h, $max_w = 0, $max_h = 0) {
        if($src_w == 0 || $src_h == 0) {
            return false;
        }

        $dst_w = $src_w;
        $dst_h = $src_h;

        if($src_w > $max_w && $max_w>0) {
            $dst_h = $src_h * ($max_w/$src_w);
            $dst_w = $max_w;
        }
        if($dst_h > $max_h && $max_h>0) {
            $dst_w = $dst_w * ($max_h/$dst_h);
            $dst_h = $max_h;
        }
        return array($dst_w, $dst_h);
    }

Функция вычисления размера изображения, до которых нужно его пропорционально уменьшить, чтобы вписать в квадрат $max_w x $max_h

Функция принимает аргументы($src_w, $src_h, $max_w = 0, $max_h = 0)

Параметры которые содержит функция:

  • $src_w - языка, который необходимо выбрать
  • $src_h - языка, который необходимо выбрать
  • $max_w - языка, который необходимо выбрать
  • $max_h - языка, который необходимо выбрать

Функция возвращает вычисленную ширину и высоту


Функция delete_image()

Код функции (спойлер)
   public function delete_image($id, $field = null, $table = null, $original_dir = null, $resized_dir = null, $lang_id = 0, $lang_field = '') {
        if (!$field || !$table || !$original_dir) {
            return false;
        }
        if (!$lang_id) {
            $query = $this->db->placehold("SELECT $field FROM __$table WHERE id=?", $id);
            $this->db->query($query);
            $filename = $this->db->result($field);

            if (!empty($filename)) {
                $query = $this->db->placehold("UPDATE __$table SET $field='' WHERE id=?", $id);
                $this->db->query($query);

                $query = $this->db->placehold("SELECT count(*) as count FROM __$table WHERE $field=? LIMIT 1", $filename);
                $this->db->query($query);
                $count = $this->db->result('count');
                if($count == 0) {
                    $file = pathinfo($filename, PATHINFO_FILENAME);
                    $ext = pathinfo($filename, PATHINFO_EXTENSION);

                    // Удалить все ресайзы
                    if (!empty($resized_dir)) {
                        $rezised_images = glob($this->config->root_dir.$resized_dir.$file.".*x*.".$ext);
                        if(is_array($rezised_images)) {
                            foreach ($rezised_images as $f) {
                                @unlink($f);
                            }
                        }
                    }

                    @unlink($this->config->root_dir.$original_dir.$filename);
                }
            }
        } else {
            $query = $this->db->placehold("SELECT $field FROM __lang_$table WHERE $lang_field=? and lang_id=?", $id, $lang_id);
            $this->db->query($query);
            $filename = $this->db->result($field);

            if (!empty($filename)) {
                $query = $this->db->placehold("UPDATE __lang_$table SET $field='' WHERE $lang_field=? and lang_id=?", $id, $lang_id);
                $this->db->query($query);

                $query = $this->db->placehold("SELECT count(*) as count FROM __lang_$table WHERE $field=? LIMIT 1", $filename);
                $this->db->query($query);
                $count = $this->db->result('count');
                if($count == 0) {
                    $file = pathinfo($filename, PATHINFO_FILENAME);
                    $ext = pathinfo($filename, PATHINFO_EXTENSION);

                    // Удалить все ресайзы
                    if (!empty($resized_dir)) {
                        $rezised_images = glob($this->config->root_dir.$resized_dir.$file.".*x*.".$ext);
                        if(is_array($rezised_images)) {
                            foreach ($rezised_images as $f) {
                                @unlink($f);
                            }
                        }
                    }

                    @unlink($this->config->root_dir.$original_dir.$filename);
                }
            }
        }
    }

Функция удаляет изображение и все его ресайзы (физически и из БД)

Функция принимает аргументы($id, $field = null, $table = null, $original_dir = null, $resized_dir = null, $lang_id = 0, $lang_field = '')

Параметры которые содержит функция:

  • $id - $id удаляемой сущности
  • $field - поле в таблице БД
  • $table - таблица в БД
  • $original_dir - директория с оригинальным файлом
  • $resized_dir - директория с ресайзами изображений
  • $lang_id - мультиязычная таблица
  • $lang_field - мультиязычные поля