CImageHandler - работа с изображениями

Выкладываем свои наработки
ATI
Сообщения: 69
Зарегистрирован: 2009.09.27, 12:35

Re: CImageHandler - работа с изображениями

Сообщение ATI » 2011.06.09, 09:59

Открой само расширение и посмотри там метод thumb. Там можно увидеть, что он принимает и что делает.

Аватара пользователя
Tokolist
Сообщения: 113
Зарегистрирован: 2010.03.01, 22:03

Re: CImageHandler - работа с изображениями

Сообщение Tokolist » 2011.06.10, 15:48

Понимаю, что последний ответ был довольно таки давно, но поддерживается ли еще разработка расширения.
В принципе, на данный момент я его не совершенствую...

У меня в процессе работы возник вопрос, можно ли в функцию ->thumb() передать один из параметров false, чтобы ресайз шел пропорционально, но только используя один из параметров функции? Т.е. если мне нужно, чтобы все загруженные фото были точно 200px по ширине, а высота не имеет значения.
На данный момент можно попробовать использовать метод

Код: Выделить всё

public function resize($toWidth, $toHeight, $proportional = true) 
следующим образом

Код: Выделить всё

resize(200, 1000000) 
в этом случае ширина всегда будет 200, даже если у оригинала она меньше, а высота просто очень большое число
на выходных добавлю возможность указывать неограниченную высоту/ширину

Аватара пользователя
Tokolist
Сообщения: 113
Зарегистрирован: 2010.03.01, 22:03

Re: CImageHandler - работа с изображениями

Сообщение Tokolist » 2011.06.12, 18:18

Добавил возможность задавать неограниченную высоту/ширину для превюшек и ресайза а также более детальное описание методов класса.
Решил таки развивать класс, поэтому ждите версию 2.0 с серьезными улучшениями.

Аватара пользователя
Psyhos
Сообщения: 124
Зарегистрирован: 2011.04.13, 15:04
Контактная информация:

Re: CImageHandler - работа с изображениями

Сообщение Psyhos » 2011.08.17, 10:10

Стал использовать ваше расширение! Спасибо!
В функции сохранения исправил выбор типа сохранения файлов в формат:

Код: Выделить всё

switch ($toFormat)
        {
            case 'IMG_GIF':
                if (!imagegif($this->image, $file))
                {
                    throw new Exception('Can\'t save gif file');
                }
                break;
            case 'IMG_JPEG':
                if (!imagejpeg($this->image, $file, $jpegQuality))
                {
                    throw new Exception('Can\'t save jpeg file');
                }
                break;
            case 'IMG_PNG':
                if (!imagepng($this->image, $file))
                {
                    throw new Exception('Can\'t save png file');
                }
                break;
            default:
                throw new Exception('Invalid image format for save');
        } 
было:

Код: Выделить всё

switch ($toFormat)
        {
            case self::IMG_GIF:
                if (!imagegif($this->image, $file))
                {
                    throw new Exception('Can\'t save gif file');
                }
                break; 

Аватара пользователя
Tokolist
Сообщения: 113
Зарегистрирован: 2010.03.01, 22:03

Re: CImageHandler - работа с изображениями

Сообщение Tokolist » 2011.08.17, 14:23

Константы лучше использовать, поскольку в случае неправильного написания интерпретатор выдаст ошибку, да и автодополнение работает...

Аватара пользователя
Kirill
Сообщения: 128
Зарегистрирован: 2010.08.28, 22:34

Re: CImageHandler - работа с изображениями

Сообщение Kirill » 2011.08.17, 18:27

Почему бы не выложить код на github, чтобы все смогли его дополнять?
github profile: https://github.com/kirs

Аватара пользователя
Tokolist
Сообщения: 113
Зарегистрирован: 2010.03.01, 22:03

Re: CImageHandler - работа с изображениями

Сообщение Tokolist » 2011.08.17, 19:08

Я уже давно планирую выложить этот (и остальные написанные мной компоненты, у меня их много) компонент в YiiExt репозиторий, но все не найду время на написание нормальной английской и русской документации... Через две недели у меня времени будет однозначно больше, поэтому займусь всем этим. Кроме того у меня на 80% готова вторая версия CImageHandler, думаю есть смысл выложить уже последнюю версию.

В любом случае код распространяется под свободной лицензией, поэтому Вы можете выложить его куда угодно самостоятельно, только сохраните, пожалуйста, авторство. Но я все равно считаю, что лучше когда один человек вносит правки в небольшие проекты, поэтому лучше будет если вы напишете замечание здесь :)

Ruganin
Сообщения: 14
Зарегистрирован: 2011.10.20, 15:25

Re: CImageHandler - работа с изображениями

Сообщение Ruganin » 2011.11.01, 09:31

Добрый день, подскажите пожалуйста как сделать проверку на наличие файла?
Допустим есть массив с ссылками и соответствующий код:

Код: Выделить всё

$i = 1;
                foreach ($photos as $photo) {
                    Yii::app()->ih->load($photo)->resize(600, 450)->save($_SERVER['DOCUMENT_ROOT'] .
                        '/images/photo/' . $i . '.jpg');
                    $i++;
                }
 
Как прописать continue; в случае если ссылка битая и файл отсутствует?
Не откажите в помощи начинающему.


Аватара пользователя
usualdesigner
Сообщения: 119
Зарегистрирован: 2011.08.08, 13:23
Откуда: Киев, Украина
Контактная информация:

Re: CImageHandler - работа с изображениями

Сообщение usualdesigner » 2011.11.05, 10:27

Вот у автора для сорса изображения можно указать как полный серверный путь, так и URL. В чистом GD или ImageMagic можно делать также, или там нужно именно серверный путь скармливать сорсу?

Аватара пользователя
usualdesigner
Сообщения: 119
Зарегистрирован: 2011.08.08, 13:23
Откуда: Киев, Украина
Контактная информация:

Re: CImageHandler - работа с изображениями

Сообщение usualdesigner » 2011.11.05, 20:20

И еще возникло несколько вопросов по расширению:

1. Как залить фон у изображения с сохранением оригинального размера?
2. При рендере исходного изображения (png) с прозрачным фоном получаю вместо прозрачного черный фон с какими то артефактами.

Код: Выделить всё

        Yii::app()->ih
            ->load($image->fullPath)
            ->show();
 
Вложения
index.php.png
index.php.png (209.66 КБ) 6334 просмотра

Аватара пользователя
phillip
Сообщения: 53
Зарегистрирован: 2011.01.24, 18:03
Контактная информация:

Re: CImageHandler - работа с изображениями

Сообщение phillip » 2012.01.27, 16:25

Все хорошо, но качество полученных картинок очень плохое. С чем может быть связано, как исправить?

Аватара пользователя
nidkor
Сообщения: 37
Зарегистрирован: 2011.09.07, 01:28
Откуда: Украина, Харьков

Re: CImageHandler - работа с изображениями

Сообщение nidkor » 2012.02.01, 16:05

Тоже с этим столкнулся, судя по всему это из-за jpeg. По умолчанию изображения сжимаются до 75% качества

Код: Выделить всё

public function save($file = false, $toFormat = false, $jpegQuality = 75, $touch = false)

cioxideru
Сообщения: 26
Зарегистрирован: 2012.03.05, 17:57

Re: CImageHandler - работа с изображениями

Сообщение cioxideru » 2012.03.14, 16:39

Автор проделал хорошую работу, молодец!
Данное решение может быть полезно в случае когда imageMagic использовать нет возможности.

alisherdavronov
Сообщения: 21
Зарегистрирован: 2011.09.21, 15:34

Re: CImageHandler - работа с изображениями

Сообщение alisherdavronov » 2012.06.17, 11:56

спасибо за полезный код

ждем кеширование :)


ну например чтото типа из скрипта image-crop.php
// Smart Image Resizer 1.4.1
// Resizes images, intelligently sharpens, crops based on width:height ratios, color fills
// transparent GIFs and PNGs, and caches variations for optimal performance

// Created by: Joe Lencioni (http://shiftingpixel.com)
// Date: August 6, 2008
// Based on: http://veryraw.com/history/2005/03/imag ... -with-php/

HotAlex
Сообщения: 7
Зарегистрирован: 2012.02.22, 20:33

Re: CImageHandler - работа с изображениями

Сообщение HotAlex » 2012.06.19, 20:28

Здравствуйте!
Заметил, что resizeCanvas немного некорректно вычисляет новые размеры картинки, в результате чего картинки некоторых размеров оказываются обрезанными. Немного модернизировал метод:

Код: Выделить всё

    public function resizeCanvas($toWidth, $toHeight, $backgroundColor = array(255, 255, 255))
    {
        $this->checkLoaded();

        $newWidth = min($toWidth, $this->width);
        $newHeight = min($toHeight, $this->height);

        $koef_w=$newWidth / $this->width;
        $koef_h=$newHeight / $this->height;

        if ($koef_w < $koef_h)
        {
            $newHeight = round($koef_w * $this->height);
        }
        else
        {
            $newWidth = round($koef_h * $this->width);
        }

        $posX = floor(($toWidth - $newWidth) / 2);
        $posY = floor(($toHeight - $newHeight) / 2);


        $newImage = imagecreatetruecolor($toWidth, $toHeight);

        $backgroundColor = imagecolorallocate($newImage, $backgroundColor[0], $backgroundColor[1], $backgroundColor[2]);
        imagefill($newImage, 0, 0, $backgroundColor);

        imagecopyresampled($newImage, $this->image, $posX, $posY, 0, 0, $newWidth, $newHeight, $this->width, $this->height);

        imagedestroy($this->image);

        $this->image = $newImage;
        $this->width = $toWidth;
        $this->height = $toHeight;

        return $this;
    }
Теперь преобразование размера зависит не только от того, вертикальная картинка или горизонтальная (предыдущий вариант преобразования):

Код: Выделить всё

        if ($this->width > $this->height)
        {
            $newHeight = round($newWidth / $this->width * $this->height);
        }
        else
        {
            $newWidth = round($newHeight / $this->height * $this->width);
        }
Теперь для преобразования вычисляются коэффициенты (исходя из соотношений сторон), и умножение производится на меньший коэффициент, т. е. картинка гарантированно полностью попадет в заданную область:

Код: Выделить всё

       $koef_w=$newWidth / $this->width;
        $koef_h=$newHeight / $this->height;

        if ($koef_w < $koef_h)
        {
            $newHeight = round($koef_w * $this->height);
        }
        else
        {
            $newWidth = round($koef_h * $this->width);
        }
Досконально не тестил, но вроде работает корректно

setrais
Сообщения: 1
Зарегистрирован: 2012.01.27, 15:45

Re: CImageHandler - работа с изображениями

Сообщение setrais » 2012.06.22, 11:59

Добрый день. А где его возможно скачать. Поделитесь ссылкой пожалуйста.

HotAlex
Сообщения: 7
Зарегистрирован: 2012.02.22, 20:33

Re: CImageHandler - работа с изображениями

Сообщение HotAlex » 2012.06.22, 12:44

setrais писал(а):Добрый день. А где его возможно скачать. Поделитесь ссылкой пожалуйста.
В начальных каментах к посту есть ссылки.

Аватара пользователя
Sc@M
Сообщения: 17
Зарегистрирован: 2012.06.08, 11:28

Re: CImageHandler - работа с изображениями

Сообщение Sc@M » 2012.06.22, 18:22

Автор, не кажется ли вам, что реализованный вами метод reload() уж слишком ресурсоёмкий?
Картинка каждый раз уничтожается в памяти! И снова распаковывается в память из файла!
Это ресурсоёмко! Решение помоему очевидно!
Пришлось немного изменить ваш класс.
1) Была произведена замена всего private на protected (дабы устранить проблемы наследования);
2) Вызов imagedestroy($this->image) в функциях был заменён на $this->freeImage(); - Это производит абсолютно тотже самый эффект, но в наследуемом классе изменена логика freeImage(), дабы убить сразу двух зайцев:
1) сохранить первоначальную логику работы вашего класса;
2) обеспечить корректную работу старых непереопределённых методов с новой логикой reload()! (не тестил, но проблем быть не должно)

Код: Выделить всё

<?php

class ImageHandler extends CImageHandler
{
  protected $oldImage;
  protected $oldWidth;
  protected $oldHeight;
  protected $trueColor=null;

  public function __destruct()
  {
    parent::__destruct();
    if(is_resource($this->oldImage))
      imagedestroy($this->oldImage);
  }

  protected function freeImage()
  {
    if($this->image!==$this->oldImage)
      parent::freeImage();
  }

  protected function createImage($width,$height,$trueColor=null)
  {
    $Image=null;
    if(is_null($trueColor)){
      if(function_exists('ImageIsTrueColor'))
        $createTrueColor=ImageIsTrueColor($this->image);
      else
        $createTrueColor=true;
    } else {
      $createTrueColor=$trueColor;
    }
    if($createTrueColor && function_exists('ImageCreateTrueColor'))
      $Image=@ImageCreateTrueColor($width, $height);
    if(is_null($Image)){
      $Image=ImageCreate($width,$height);
      imagepalettecopy($Image,$this->image);
      $color=imagecolortransparent($this->image);
      if ($color!=-1) {
        imagecolortransparent($Image,$color);
        imagefill($Image,0,0,$color);
      }
    }
    return $Image;
  }

  public function load($file)
  {
    if(!parent::load($file))
      return false;
    $this->oldImage=$this->image;
    $this->oldWidth=$this->width;
    $this->oldHeight=$this->height;
    return $this;
  }

  public function reload()
  {
    $this->freeImage();
    if(!is_resource($this->oldImage))
      throw new CException('Can\'t reload.');
    $this->image=$this->oldImage;
    $this->width=$this->oldWidth;
    $this->height=$this->oldHeight;
    return $this;
  }

  public function resize($toWidth,$toHeight,$proportional=true)
  {
    $this->checkLoaded();

    $toWidth = $toWidth !== false ? $toWidth : $this->width;
    $toHeight = $toHeight !== false ? $toHeight : $this->height;

    if($proportional)
    {
      $newHeight = $toHeight;
      $newWidth = round($newHeight / $this->height * $this->width);

      if($newWidth > $toWidth)
      {
        $newWidth = $toWidth;
        $newHeight = round($newWidth / $this->width * $this->height);
      }
    }
    else
    {
      $newWidth = $toWidth;
      $newHeight = $toHeight;
    }

    $newImage=$this->createImage($newWidth,$newHeight,$this->trueColor);
    $icrRes=null;
    if(function_exists('ImageCopyResampled'))
      $icrRes=ImageCopyResampled($newImage,$this->image,0,0,0,0,$newWidth,$newHeight,$this->width,$this->height);
    if(is_null($icrRes))
      ImageCopyResized($newImage,$this->image,0,0,0,0,$newWidth,$newHeight,$this->width,$this->height);

    $this->freeImage();

    $this->image=$newImage;
    $this->width=$newWidth;
    $this->height=$newHeight;

    return $this;
  }

  public function resizeCanvas($toWidth, $toHeight, $backgroundColor = array(255, 255, 255))
  {
    $this->checkLoaded();

    $newWidth = min($toWidth, $this->width);
    $newHeight = min($toHeight, $this->height);

    $c_w=$newWidth / $this->width;
    $c_h=$newHeight / $this->height;

    if ($c_w < $c_h)
    {
      $newHeight = round($c_w * $this->height);
    }
    else
    {
      $newWidth = round($c_h * $this->width);
    }

    $posX = floor(($toWidth - $newWidth) / 2);
    $posY = floor(($toHeight - $newHeight) / 2);

    $newImage=$this->createImage($toWidth,$toHeight,$this->trueColor);

    $backgroundColor = imagecolorallocate($newImage, $backgroundColor[0], $backgroundColor[1], $backgroundColor[2]);
    imagefill($newImage, 0, 0, $backgroundColor);

    imagecopyresampled($newImage, $this->image, $posX, $posY, 0, 0, $newWidth, $newHeight, $this->width, $this->height);

    $this->freeImage();

    $this->image = $newImage;
    $this->width = $toWidth;
    $this->height = $toHeight;

    return $this;
  }

  public function grayScale()
  {
    $newImage=$this->createImage($this->width,$this->height,$this->trueColor);
    imagecopy($newImage,$this->image,0,0,0,0,$this->width,$this->height);
    imagecopymergegray($newImage,$newImage,0,0,0,0,$this->width,$this->height,0);
    $this->freeImage();
    $this->image=$newImage;
    return $this;
  }
}
1) добавил 3 новых protected свойства с префиксом old, для хранения состояния первоначально загруженного изображения.
2) Переопределил методы
__destruct(),
freeImage(),
load(),
reload(),
resize(). (по сути мне был нужен только этот метод, его также использует thumb)
3) Добавил методы
createImage(). - корректно создает пустое рабочее изображение для дальнейших манипуляций.
resizeCanvas(). - код скопипастил из сообщения выше по теме.
grayScale(). - теперь изображение можно делать чёрно-белым.
Теперь в изображениях, которые были созданы из исходников c прозрачностью, нет артефактов (вложил пример, созданный из png с alpha-каналом)!!! (протестировано для методов thumb() и соответственно resize())
Вкладываю архив с файлами классов. Первоначальный класс немного изменён, но логика работы осталась нетронутой!
Не советую сливать всё в 1 класс, используйте лучше наследование, если вы не целиком понимаете, что вы делаете. Также вы всегда сможете вернуться к первоначальной реализации. Но для использования новых возможностей наследуемого класса, замена файла с исходным классом обязательна!
Вложения
CImageHandler.rar
(3.07 КБ) 191 скачивание
scam_normal.jpg
изображение без артефактов
scam_normal.jpg (6.07 КБ) 6097 просмотров
scam_artefacts.jpg
изображение с артефактами
scam_artefacts.jpg (6.22 КБ) 6097 просмотров

Аватара пользователя
Tokolist
Сообщения: 113
Зарегистрирован: 2010.03.01, 22:03

Re: CImageHandler - работа с изображениями

Сообщение Tokolist » 2012.06.24, 12:32

usualdesigner писал(а):Вот у автора для сорса изображения можно указать как полный серверный путь, так и URL. В чистом GD или ImageMagic можно делать также, или там нужно именно серверный путь скармливать сорсу?
Да в чистом GD можно напрямую (нужны также соотв. настройки PHP). Для ImageMagic через fopen http://php.net/manual/en/imagick.readimagefile.php
usualdesigner писал(а):1. Как залить фон у изображения с сохранением оригинального размера?
Такой функционал пока не предусмотрен. Очень не элегантный воркараунд это сделать resizeCanvas указав исходный размер изображения.
usualdesigner писал(а):2. При рендере исходного изображения (png) с прозрачным фоном получаю вместо прозрачного черный фон с какими то артефактами.

Код: Выделить всё

        Yii::app()->ih
            ->load($image->fullPath)
            ->show();
У самого GD есть проблемы с прозрачностью PNG. Для фикса создан метод preserveTransparency. Если показывать изображение без какой-либо обработки как в Вашем случае, то этот метод не вызывается.
phillip писал(а):Все хорошо, но качество полученных картинок очень плохое. С чем может быть связано, как исправить?
nidkor писал(а):Тоже с этим столкнулся, судя по всему это из-за jpeg. По умолчанию изображения сжимаются до 75% качества

Код: Выделить всё

public function save($file = false, $toFormat = false, $jpegQuality = 75, $touch = false)
Да, просто увеличите качество в соотв. параметре. Меня устраивало 75 по качеству/весу изображения для превюшек, поэтому оставил это значение по умолчанию.
cioxideru писал(а):Автор проделал хорошую работу, молодец!
Данное решение может быть полезно в случае когда imageMagic использовать нет возможности.
Спасибо!
alisherdavronov писал(а):спасибо за полезный код
ждем кеширование :)
Спасибо!
HotAlex писал(а):Здравствуйте!
Заметил, что resizeCanvas немного некорректно вычисляет новые размеры картинки, в результате чего картинки некоторых размеров оказываются обрезанными. Немного модернизировал метод:
Спасибо! Это у меня пофикшено в новой версии, которую все не дойдут руки привести в нормальный вид (добавил ссылку в первый пост).

Sc@M Спасибо за критику! Обещаю что на этой неделе внесу правки в код (пока добавил ссылку на Ваше сообщение в первый пост).

Ответить