Файл: silawar.ru/protected/extensions/ImageHandler/CImageHandler.php
Строк: 340
<?php
/**
 * Image handler
 * @author Yaroslav Pelesh aka Tokolist http://tokolist.com
 * @link https://github.com/tokolist/yii-components
 * @version 1.2
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 */
class CImageHandler extends CApplicationComponent
{
    private $originalImage = null;
    private $image = null;
    private $format = 0;
    private $width = 0;
    private $height = 0;
    private $mimeType = '';
    private $fileName = '';
    public $transparencyColor = array(0, 0, 0);
    const IMG_GIF = 1;
    const IMG_JPEG = 2;
    const IMG_PNG = 3;
    const CORNER_LEFT_TOP = 1;
    const CORNER_RIGHT_TOP = 2;
    const CORNER_LEFT_BOTTOM = 3;
    const CORNER_RIGHT_BOTTOM = 4;
    const CORNER_CENTER = 5;
    const FLIP_HORIZONTAL = 1;
    const FLIP_VERTICAL = 2;
    const FLIP_BOTH = 3;
    public function getImage()
    {
        return $this->image;
    }
    public function getFormat()
    {
        return $this->format;
    }
    public function getWidth()
    {
        return $this->width;
    }
    public function getHeight()
    {
        return $this->height;
    }
    public function getMimeType()
    {
        return $this->mimeType;
    }
    public function __destruct()
    {
        $this->freeImage();
    }
    private function freeImage()
    {
        if(is_resource($this->image))
        {
            imagedestroy($this->image);
        }
        
        if($this->originalImage !== null)
        {
            if(is_resource($this->originalImage['image']))
            {
                imagedestroy($this->originalImage['image']);
            }
            $this->originalImage = null;
        }
    }
    private function checkLoaded()
    {
        if (!is_resource($this->image))
        {
            throw new Exception('Load image first');
        }
    }
    private function loadImage($file)
    {
        $result = array();
        if ($imageInfo = @getimagesize($file))
        {
            $result['width'] = $imageInfo[0];
            $result['height'] = $imageInfo[1];
            $result['mimeType'] = $imageInfo['mime'];
            switch ($result['format'] = $imageInfo[2])
            {
                case self::IMG_GIF:
                    if ($result['image'] = imagecreatefromgif($file))
                    {
                        return $result;
                    }
                    else
                    {
                        throw new Exception('Invalid image gif format');
                    }
                    break;
                case self::IMG_JPEG:
                    if ($result['image'] = imagecreatefromjpeg($file))
                    {
                        return $result;
                    }
                    else
                    {
                        throw new Exception('Invalid image jpeg format');
                    }
                    break;
                case self::IMG_PNG:
                    if ($result['image'] = imagecreatefrompng($file))
                    {
                        return $result;
                    }
                    else
                    {
                        throw new Exception('Invalid image png format');
                    }
                    break;
                  default:
                      throw new Exception('Not supported image format');
              }
          }
          else
          {
              throw new Exception('Invalid image file');
          }
    }
    
    protected function initImage($image = false)
    {
        if($image === false)
        {
            $image = $this->originalImage;
        }
        
        $this->width = $image['width'];
        $this->height = $image['height'];
        $this->mimeType = $image['mimeType'];
        $this->format = $image['format'];
        
        //Image
        if(is_resource($this->image))
            imagedestroy($this->image);
        
        $this->image = imagecreatetruecolor($this->width, $this->height);
        $this->preserveTransparency($this->image);
        imagecopy($this->image, $image['image'], 0, 0, 0, 0, $this->width, $this->height);
    }
    public function load($file)
    {
        $this->freeImage();
        if(($this->originalImage = $this->loadImage($file)))
        {
            $this->initImage();
            $this->fileName = $file;
            return $this;
        }
        else
        {
            return false;
        }
    }
    public function reload()
    {
        $this->checkLoaded();
        $this->initImage();
        return $this;
    }
    private function preserveTransparency($newImage)
    {
        switch($this->format)
        {
            case self::IMG_GIF:
                $color = imagecolorallocate(
                    $newImage,
                    $this->transparencyColor[0],
                    $this->transparencyColor[1],
                    $this->transparencyColor[2]
                );
                imagecolortransparent($newImage, $color);
                imagetruecolortopalette($newImage, false, 256);
                break;
            case self::IMG_PNG:
                imagealphablending($newImage, false);
                $color = imagecolorallocatealpha (
                    $newImage,
                    $this->transparencyColor[0],
                    $this->transparencyColor[1],
                    $this->transparencyColor[2],
                    0
                );
                
                imagefill($newImage, 0, 0, $color);
                imagesavealpha($newImage, true);
                break;
        }
    }
    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 = imagecreatetruecolor($newWidth, $newHeight);
        $this->preserveTransparency($newImage);
        imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newWidth, $newHeight, $this->width, $this->height);
        imagedestroy($this->image);
        $this->image = $newImage;
        $this->width = $newWidth;
        $this->height = $newHeight;
        return $this;
    }
    public function thumb($toWidth, $toHeight, $proportional = true)
    {
        $this->checkLoaded();
        if($toWidth !== false)
            $toWidth = min($toWidth, $this->width);
        
        if($toHeight !== false)
            $toHeight = min($toHeight, $this->height);
        $this->resize($toWidth, $toHeight, $proportional);
        return $this;
    }
    public function watermark($watermarkFile, $offsetX, $offsetY, $corner = self::CORNER_RIGHT_BOTTOM, $zoom = false)
    {
        $this->checkLoaded();
        if ($wImg = $this->loadImage($watermarkFile))
        {
            $posX = 0;
            $posY = 0;
                        
            $watermarkWidth = $wImg['width'];
            $watermarkHeight = $wImg['height'];
            if($zoom !== false)
            {
                $dimension = round(max($this->width, $this->height) * $zoom);
                $watermarkHeight = $dimension;
                $watermarkWidth = round($watermarkHeight / $wImg['height'] * $wImg['width']);
                if($watermarkWidth > $dimension)
                {
                    $watermarkWidth = $dimension;
                    $watermarkHeight = round($watermarkWidth / $wImg['width'] * $wImg['height']);
                }
            }
            switch ($corner)
            {
                case self::CORNER_LEFT_TOP:
                    $posX = $offsetX;
                    $posY = $offsetY;
                    break;
                case self::CORNER_RIGHT_TOP:
                    $posX = $this->width - $watermarkWidth - $offsetX;
                    $posY = $offsetY;
                    break;
                case self::CORNER_LEFT_BOTTOM:
                    $posX = $offsetX;
                    $posY = $this->height - $watermarkHeight - $offsetY;
                    break;
                case self::CORNER_RIGHT_BOTTOM:
                    $posX = $this->width - $watermarkWidth - $offsetX;
                    $posY = $this->height - $watermarkHeight - $offsetY;
                    break;
                case self::CORNER_CENTER:
                    $posX = floor(($this->width - $watermarkWidth) / 2);
                    $posY = floor(($this->height - $watermarkHeight) / 2);
                    break;
                default:
                    throw new Exception('Invalid $corner value');
            }
            imagecopyresampled(
                $this->image,
                $wImg['image'],
                $posX,
                $posY,
                0,
                0,
                $watermarkWidth,
                $watermarkHeight,
                $wImg['width'],
                $wImg['height']
            );
            imagedestroy($wImg['image']);
            return $this;
        }
        else
        {
            return false;
        }
    }
    public function flip($mode)
    {
        $this->checkLoaded();
        $srcX = 0;
        $srcY = 0;
        $srcWidth = $this->width;
        $srcHeight = $this->height;
        switch ($mode)
        {
            case self::FLIP_HORIZONTAL:
                $srcX = $this->width - 1;
                $srcWidth = -$this->width;
                break;
            case self::FLIP_VERTICAL:
                $srcY = $this->height - 1;
                $srcHeight = -$this->height;
                break;
            case self::FLIP_BOTH:
                $srcX = $this->width - 1;
                $srcY = $this->height - 1;
                $srcWidth = -$this->width;
                $srcHeight = -$this->height;
                break;
            default:
                throw new Exception('Invalid $mode value');
        }
        $newImage = imagecreatetruecolor($this->width, $this->height);
        $this->preserveTransparency($newImage);
        imagecopyresampled($newImage, $this->image, 0, 0, $srcX, $srcY, $this->width, $this->height, $srcWidth, $srcHeight);
        imagedestroy($this->image);
        $this->image = $newImage;
        //dimensions not changed
        return $this;
    }
    public function rotate($degrees)
    {
        $this->checkLoaded();
        $degrees = (int) $degrees;
        $this->image = imagerotate($this->image, $degrees, 0);
        $this->width = imagesx($this->image);
        $this->height = imagesy($this->image);
        return $this;
    }
    public function crop($width, $height, $startX = false, $startY = false)
    {
        $this->checkLoaded();
        $width = (int) $width;
        $height = (int) $height;
        //Centered crop
         $startX = $startX === false ? floor(($this->width - $width) / 2) : intval($startX);
        $startY = $startY === false ? floor(($this->height - $height) / 2) : intval($startY);
        //Check dimensions
        $startX = max(0, min($this->width, $startX));
        $startY = max(0, min($this->height, $startY));
        $width = min($width, $this->width - $startX);
        $height = min($height, $this->height - $startY);
        $newImage = imagecreatetruecolor($width, $height);
        $this->preserveTransparency($newImage);
        imagecopyresampled($newImage, $this->image, 0, 0, $startX, $startY, $width, $height, $width, $height);
        imagedestroy($this->image);
        $this->image = $newImage;
        $this->width = $width;
        $this->height = $height;
        return $this;
    }
    public function text($text, $fontFile, $size=12, $color=array(0, 0, 0),
        $corner=self::CORNER_LEFT_TOP, $offsetX=0, $offsetY=0, $angle=0)
    {
        $this->checkLoaded();
        $bBox = imagettfbbox($size, $angle, $fontFile, $text);
        $textHeight = $bBox[1] - $bBox[7];
        $textWidth = $bBox[2] - $bBox[0];
        $color = imagecolorallocate($this->image, $color[0], $color[1], $color[2]);
        switch ($corner)
        {
            case self::CORNER_LEFT_TOP:
                $posX = $offsetX;
                $posY = $offsetY;
                break;
            case self::CORNER_RIGHT_TOP:
                $posX = $this->width - $textWidth - $offsetX;
                $posY = $offsetY;
                break;
            case self::CORNER_LEFT_BOTTOM:
                $posX = $offsetX;
                $posY = $this->height - $textHeight - $offsetY;
                break;
            case self::CORNER_RIGHT_BOTTOM:
                $posX = $this->width - $textWidth - $offsetX;
                $posY = $this->height - $textHeight - $offsetY;
                break;
            case self::CORNER_CENTER:
                $posX = floor(($this->width - $textWidth) / 2);
                $posY = floor(($this->height - $textHeight) / 2);
                break;
            default:
                throw new Exception('Invalid $corner value');
        }
        imagettftext($this->image, $size, $angle, $posX, $posY + $textHeight, $color, $fontFile, $text);
        return $this;
    }
    public function adaptiveThumb($width, $height)
    {
        $this->checkLoaded();
        $width = intval($width);
        $height = intval($height);
        $widthProportion = $width / $this->width;
        $heightProportion = $height / $this->height;
        if ($widthProportion > $heightProportion)
        {
            $newWidth = $width;
            $newHeight = round($newWidth / $this->width * $this->height);
        }
        else
        {
            $newHeight = $height;
            $newWidth = round($newHeight / $this->height * $this->width);
        }
        $this->resize($newWidth, $newHeight);
        $this->crop($width, $height);
        return $this;
    }
    public function resizeCanvas($toWidth, $toHeight, $backgroundColor = array(255, 255, 255))
    {
        $this->checkLoaded();
        $newWidth = min($toWidth, $this->width);
        $newHeight = min($toHeight, $this->height);
        $widthProportion = $newWidth / $this->width;
        $heightProportion = $newHeight / $this->height;
        if($widthProportion < $heightProportion)
        {
            $newHeight = round($widthProportion * $this->height);
        }
        else
        {
            $newWidth = round($heightProportion * $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;
    }
    
    public function grayscale()
    {
        $newImage = imagecreatetruecolor($this->width, $this->height);
        imagecopy($newImage, $this->image, 0, 0, 0, 0, $this->width, $this->height);
        imagecopymergegray($newImage, $newImage, 0, 0, 0, 0, $this->width, $this->height, 0);
        imagedestroy($this->image);
        
        $this->image = $newImage;
        
        return $this;
    }
    public function show($inFormat = false, $jpegQuality = 75)
    {
        $this->checkLoaded();
        if (!$inFormat)
        {
            $inFormat = $this->format;
        }
        switch ($inFormat)
        {
            case self::IMG_GIF:
                header('Content-type: image/gif');
                imagegif($this->image);
                break;
            case self::IMG_JPEG:
                header('Content-type: image/jpeg');
                imagejpeg($this->image, null, $jpegQuality);
                break;
            case self::IMG_PNG:
                header('Content-type: image/png');
                imagepng($this->image);
                break;
            default:
                throw new Exception('Invalid image format for putput');
        }
        return $this;
    }
    public function save($file = false, $toFormat = false, $jpegQuality = 75, $touch = false)
    {
        if (empty($file))
        {
            $file = $this->fileName;
        }
        $this->checkLoaded();
        if (!$toFormat)
        {
            $toFormat = $this->format;
        }
        switch ($toFormat)
        {
            case self::IMG_GIF:
                if (!imagegif($this->image, $file))
                {
                    throw new Exception('Can't save gif file');
                }
                break;
            case self::IMG_JPEG:
                if (!imagejpeg($this->image, $file, $jpegQuality))
                {
                    throw new Exception('Can't save jpeg file');
                }
                break;
            case self::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');
        }
        if ($touch && $file != $this->fileName)
        {
            touch($file, filemtime($this->fileName));
        }
        return $this;
    }
}