Вход Регистрация
Файл: toolkit/AcImage.php
Строк: 679
<?php
/**
 * @package image
 *
 * @author Андрей Загорцев <freeron@ya.ru>
 * @author Антон Кургузенков <kurguzenkov@list.ru>
 *
 * @version 2.0.1
 * @since 2013-03-12
 */

require_once 'geometry/Rectangle.php';
require_once 
'geometry/exceptions.php';
require_once 
'AcColor.php';
require_once 
'AcImageJPG.php';
require_once 
'AcImageGIF.php';
require_once 
'AcImagePNG.php';

/**
 * Класс, описывающий изображение, и содержащий методы для работы с ним.
 */

class AcImage
{
    const 
PNG 'image/png';
    const 
JPEG 'image/jpeg';
    const 
GIF 'image/gif';

    const 
PROPORTION 'pr';
    const 
PIXELS 'px';
    const 
PERCENT '%';

    const 
TOP_LEFT 0;
    const 
TOP_RIGHT 1;
    const 
BOTTOM_RIGHT 2;
    const 
BOTTOM_LEFT 3;

    private static 
$correctCorners = array (0123);
    private static 
$cornerLogo 2// BOTTOM_RIGHT

    /**
     * Путь к файлу с изображением
     *
     * @var string
     */

    
private $filePath;

    
/**
     * Размер (высота и ширина) изображения
     *
     * @var Size
     */

    
private $size;

    
/**
     * Массив с информацией об изображении,
     * который возвращаыет функция getimagesize
     *
     * @var array
     */

    
private $imageInfo;

    
/**
     * Ресурс изображения
     */

    
private $resource;

    
/**
     * Цвет фона по умолчанию
     * @var int|AcColor
     */

    
private static $backgroundColor AcColor::WHITE;

    
/**
     * Качество по умолчанию
     *
     * @var int
     */

    
private static $quality 85;

    
/**
     * Вкл/откл прозрачность
     * @var boolean
     */

    
private static $transparency true;

    
/**
     * Информация о поддерживаемых типах изображений
     *
     * @var array
     */

    
private static $gdInfo;

    
/**
     * Разрешить перезаписывание существующих файлов
     * @var boolean
     */

    
private static $rewrite false;

    
/**
     * Какую часть максимальную часть лого может занимать от стороны исходного изображения
     * @var float
     */

    
private static $maxProportionLogo 0.1;
    private static 
$paddingProportionLogo 0.02;

    
/**
     * @param string путь к файлу с изображением
     */

    
protected function __construct($filePath)
    {
        if (!
self::isFileExists($filePath))
            throw new 
FileNotFoundException();

        
$this->filePath $filePath;

        
$imageInfo $this->getImageInfo();
        if (!
is_array($imageInfo))
            throw new 
InvalidFileException($filePath);

        
$this->setSize(new Size($imageInfo[0], $imageInfo[1]));
    }

    
/**
     * Cоздаёт экземпляры классов AcImageJPG, AcImageGIF, AcImagePNG
     * в зависимости от типа изображения.
     *
     * @param string путь к файлу с изображением
     * @return AcImageJPG|AcImagePNG|AcImageGIF
     */

    
public static function createImage($filePath)
    {
        
$image = new AcImage($filePath);

        if (!
self::isSupportedGD())
            throw new 
GDnotInstalledException();

        
$imageInfo $image->getImageInfo();
        if (!
is_array($imageInfo))
            throw new 
InvalidFileException($filePath);

        
$mimeType $imageInfo['mime'];

        switch (
$mimeType)
        {
            case 
self::JPEG :
                return new 
AcImageJPG($filePath);
            case 
self::PNG :
                return new 
AcImagePNG($filePath);
            case 
self::GIF :
                return new 
AcImageGIF($filePath);
            default:
                throw new 
InvalidFileException($filePath);
        }
    }

    
/**
     * Сохраняет изображение в формате jpg
     *
     * @param string путь, по которому сохранится изображение
     * @return AcImage
     *
     * @throws UnsupportedFormatException
     * @throws FileAlreadyExistsException
     * @throws FileNotSaveException
     */

    
public function saveAsJPG($path)
    {
        if(!
AcImageJPG::isSupport())
            throw new 
UnsupportedFormatException();

        if (!
self::getRewrite() && self::isFileExists($path))
            throw new 
FileAlreadyExistsException($path);

        
$this->putBackground(self::$backgroundColor);
        if(!
imagejpeg(self::getResource(), $pathself::getQuality()))
            throw new 
FileNotSaveException($path);

        return 
$this;
    }

    
/**
     * Сохраняет изображение в формате png
     *
     * @param string путь, по которому сохранится изображение
     * @return AcImage
     *
     * @throws UnsupportedFormatException
     * @throws FileAlreadyExistsException
     * @throws FileNotSaveException
     */

    
public function saveAsPNG($path)
    {
        if(!
AcImagePNG::isSupport())
            throw new 
UnsupportedFormatException('png');

        if (!
self::getRewrite() && self::isFileExists($path))
            throw new 
FileAlreadyExistsException($path);

        if (!
self::getTransparency())
            
$this->putBackground(self::$backgroundColor);
        
// php >= 5.1.2
        
if(!imagePng(self::getResource(), $pathAcImagePNG::getQuality()))
            throw new 
FileNotSaveException($path);

        return 
$this;
    }

 
/**
     * Сохраняет изображение в формате GIF
     *
     * @param string путь, по которому сохранится изображение
     * @return AcImage
     *
     * @throws UnsupportedFormatException
     * @throws FileAlreadyExistsException
     * @throws FileNotSaveException
     */

    
public function saveAsGIF($path)
    {
        if(!
AcImageGIF::isSupportedGD())
            throw new 
UnsupportedFormatException();

        if (!
self::getRewrite() && self::isFileExists($path))
            throw new 
FileAlreadyExistsException($path);;

        if(!
self::getTransparency())
            
$this->putBackground(self::$backgroundColor);

        if(!
imagegif(self::getResource(), $path))
            throw new 
FileNotSaveException($path);

        return 
$this;
    }

    
/**
     * Вписывает изображение в рамки.
     * Принимает размер (рамку) в которую вписывается изображение
     * или высоту и ширину этой рамки.
     *
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function resize() // Size $s || $width, $height
    
{
        
$args func_get_args();
        if (
count($args) == 2// $width, $height
        
{
            return 
$this->resize(new Size($args[0], $args[1]));
        }
        else if (
count($args) == && $args[0] instanceof Size)
        {
            
$size $args[0];
            
$imageSize $this->getSize()->getByFrame($size);

            
$newImageResource imagecreatetruecolor($imageSize->getWidth(), $imageSize->getHeight());
            
imageAlphaBlending($newImageResourcefalse);
            
imageSaveAlpha($newImageResourcetrue);
            
imagecopyresampled($newImageResource$this->getResource(), 0000$imageSize->getWidth(),
                
$imageSize->getHeight(), $this->getWidth(), $this->getHeight());
            
$this->setResource($newImageResource);
            
$this->setSize($imageSize);
            return 
$this;
        }
        throw new 
IllegalArgumentException();
    }

    
/**
     * Ужимает изображение по <i>ширине</i>.
     *
     * @param int ширина рамки
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function resizeByWidth($width)
    {
        if (!
is_int($width) || $width <= 0)
            throw new 
IllegalArgumentException();

        return 
$this->resize($width$this->getHeight());
    }

    
/**
     * Ужимает изображение по <i>высоте</i>.
     *
     * @param int высота рамки
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function resizeByHeight($height)
    {
        if (!
is_int($height) || $height <= 0)
            throw new 
IllegalArgumentException();

        return 
$this->resize($this->getWidth(), $height);
    }

    
/**
     * Производит кроп изображения, то есть
     * вырезает из него произвольную прямоугольную область.
     * Метод принимает либо вырезаемый прямоугольник, либо его параметры.
     *
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function crop() // Rectangle $rect || $x, $y, $w, $h
    
{
        
$a func_get_args();

        if (
count($a) == 4)
            
$rect = new Rectangle($a[0], $a[1], $a[2], $a[3]);
        else if (
count($a) == && $a[0] instanceof Rectangle)
            
$rect $a[0];
        
$rect $rect->getIntersectsWith(new Rectangle(new Point(00), $this->getSize()));

        if (!
$rect)
            throw new 
IllegalArgumentException();

        
$width $rect->getWidth();
        
$height $rect->getHeight();
        
$x $rect->getLeft();
        
$y $rect->getTop();

        if (
$width == || $height == 0)
            throw new 
IllegalArgumentException();

        
$newImageResource imagecreatetruecolor($width$height);
        
imageAlphaBlending($newImageResourcefalse);
        
imageSaveAlpha($newImageResourcetrue);
        
imagecopyresampled($newImageResource$this->getResource(), 00$x$y$width$height$width$height);
        
$this->setResource($newImageResource);
        
$this->setSize($rect->getSize());
        return 
$this;
    }

    
/**
     * Вырезает произвольный квадрат из изображения.
     * Метод может принимать вырезаемый прямоугольник, обязанный быть квадратом,
     * либо параметры для создания такого прямоугольника.
     *
     * @throws IllegalArgumentException
     * @return AcImage
     */

    
public function cropSquare() // Rectnagle $square || Point $p, $a || $x, $y, $a
    
{
        
$a func_get_args();
        if (
count($a) == && $a[0] instanceof Rectangle && $a[0]->isSquare())
        {
            
$square $a[0];
        }
        else if (
count($a) == && $a[0] instanceof Point && is_int($a[1]))
        {
            
$square = new Rectangle($a[0], new Size($a[1], $a[1]));
        }
        else if(
count($a) == 3)
        {
            
$square = new Rectangle(new Point($a[0], $a[1]), new Size($a[2], $a[2]));
        }
        else
        {
            throw new 
IllegalArgumentException();
        }

        if (!
$square->isInner(new Rectangle(new Point(00), $this->getSize())))
            throw new 
IllegalArgumentException();

        return 
$this->crop($square);
    }

    
/**
     * Вырезает центральную область изображения.
     * Принимает высоту и ширину вырезаемой области.
     *
     * @param int|string ширина вырезаемой области
     * @param int|string высота вырезаемой области
     *
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function cropCenter($width$height// int, int || string, string || int, string || string, int
    
{
        
$result self::parseCropCenterArg($width);
        
$widthUnits $result['units'];
        
$width $result['value'];

        
$result self::parseCropCenterArg($height);
        
$heightUnits $result['units'];
        
$height $result['value'];

        
// true тогда и только тогда если слева и справа от xor разные значения
        
if ($widthUnits == self::PROPORTION xor $heightUnits == self::PROPORTION)
            throw new 
IllegalArgumentException();

        if (
$widthUnits == self::PERCENT)
            
$width self::percentToPixels($width$this->getWidth());

        if (
$heightUnits == self::PERCENT)
            
$height self::percentToPixels($height$this->getHeight());

        if (
$widthUnits == self::PROPORTION)
        {
            
$size $this->getSizeByProportion($width$height);

            
$width $size->getWidth();
            
$height $size->getHeight();
        }

        
$width = (int)min($width$this->getWidth());
        
$height = (int)min($height$this->getHeight());

        
$imageRect = new Rectangle(00$this->getWidth(), $this->getHeight());
        
$cropRect = new Rectangle(00$width$height);
        
$cropRect $cropRect->center($imageRect);

        return 
$this->crop($cropRect);
    }

    
/**
     * @ignore
     */

    
private static function percentToPixels($value$imageSide)
    {
        return (int)
round(($imageSide 100 $value));
    }

    
/**
     * @ignore
     */

    
private function getSizeByProportion($width$height)
    {
        
$imageWidth $this->getWidth();
        
$imageHeight $this->getHeight();

        if(
$height $imageHeight $width $imageWidth)
        {
            return new 
Size((int)round($imageHeight $height $width), $imageHeight);
        }
        else
        {
            return new 
Size($imageWidth, (int)round($imageWidth $width $height));
        }
    }

    
/**
     * @ignore
     */

    
private static function parseCropCenterArg($arg)
    {
        
$pattern '/^(d+(.d+)*)(px|%|pr)$/'// in constants?

        
$matches = array();
        if (
is_int($arg))
        {
            
$units self::PIXELS;
            
$value $arg;
        }
        else if (
preg_match($pattern$arg$matches))
        {
            
$units $matches[3]; // (px|%|pr)
            
$value $matches[1]; // (d+(.d+)*)
        
}
        else
        {
            throw new 
IllegalArgumentException();
        }
        return array (
            
'units' => $units,
            
'value' => $value
        
);
    }

    
/**
     * "Умное" создание миниатюр.
     *
     * @param int ширина
     * @param int высота
     * @param float коэффициент превышения.
     * @throws IllegalArgumentException
     * @return AcImage
     */

    
public function thumbnail($width$height$c 2// $width, $height, [$c]
    
{
        if (
$c <= || !is_finite($c) || $width <= || $height <= 0)
            throw new 
IllegalArgumentException();

        
$size = new Size($width$height);

        if(
$this->getSize()->lessThen($size))
            
$size $this->getSize();

        
$imageSize $this->getSize();

        
$isRotate false;
        if(
$size->getWidth() / $imageSize->getWidth() <= $size->getHeight() / $imageSize->getHeight())
        {
            
$size->flip();
            
$imageSize->flip();
            
$isRotate true;
        }

        
$width $size->getWidth();
        
$height $size->getHeight();

        
$imageWidth $imageSize->getWidth();
        
$imageHeight $imageSize->getHeight();

        
$lim = (int)($c $height);
        
$newHeight = (int)($imageHeight $width $imageWidth);

        if (
$imageWidth $width)
        {
            if(
$newHeight <= $lim)
            {
                
$size = new Size($width$newHeight);
            }
            else
            {
                if(
$newHeight <= $lim)
                {
                    
$size = new Size((int)($imageWidth $lim $imageHeight), $lim);
                }
                else
                {
                    
$size = new Size((int)($width 2), (int)($imageHeight $width $imageWidth));
                }
            }
        }
        else
        {
            if(
$imageHeight <= $lim)
            {
                
$size $this->getSize();
            }
            else
            {
                if(
$imageHeight <= $lim)
                {
                    if(
$imageWidth $lim $imageHeight >= $width 2)
                    {
                        
$size = new Size((int)($imageWidth $lim $imageHeight), $lim);
                    }
                    else
                    {
                        
$size = new Size((int)($width 2), (int)($imageHeight $width / ($imageWidth 2)));
                    }
                }
                else
                {
                    
$size = new Size((int)($width 2), (int)($imageHeight $width / ($imageWidth 2)));
                }
            }
        }
        if (
$isRotate)
        {
            
$size->flip();
            
$imageSize->flip();
        }
        return 
$this->resize($size);
    }

    
/**
     * Наносит лого на изображение.
     *
     * @param mixed
     * @param int номер угла, в котором будет размещенно лого<br />
     * 0 1<br />
     * 2 3
     *
     * @see AcImage::TOP_LEFT
     * @see AcImage::TOP_RIGHT
     * @see AcImage::BOTTOM_LEFT
     * @see AcImage::BOTTOM_RIGHT
     *
     * @return AcImage
     * @throws IllegalArgumentException
     */

    
public function drawLogo($logo$corner null// string $logo [$corner] || AcImage $logo [$corner]
    
{
        if (
is_null($corner))
            
$corner self::$cornerLogo;

        if (!
AcImage::isCorrectCorner($corner))
            throw new 
IllegalArgumentException();

        if (
is_string($logo))
            
$logo AcImage::createImage($logo);

        if (!(
$logo instanceof AcImage))
            throw new 
IllegalArgumentException();

        
$maxWidthLogo = (int)($this->getWidth() * self::$maxProportionLogo);
        
$maxHeightLogo = (int)($this->getHeight() * self::$maxProportionLogo);

        
$logo->resize($maxWidthLogo$maxHeightLogo);

        if (!
self::getTransparency())
            
$logo->putBackground(self::$backgroundColor);

        
imagealphablending($this->getResource(), true);
        
$logoSize $logo->getSize();

        
$location $this->getLogoPosition($corner$logoSize->getWidth(), $logoSize->getHeight());
        
imagecopy($this->getResource(), $logo->getResource(), $location->getX(), $location->getY(), 00,
                        
$logoSize->getWidth(), $logoSize->getHeight());

        return 
$this;
    }

    
/**
     * @ignore
     */

    
private function getLogoPosition($corner$width$height)
    {
        
$paddingX $this->getWidth() * self::$paddingProportionLogo;
        
$paddingY $this->getHeight() * self::$paddingProportionLogo;


        if (
$corner == self::BOTTOM_RIGHT || $corner == self::BOTTOM_LEFT)
            
$y $this->getHeight() - $paddingY $height;
        else
            
$y $paddingY;

        if (
$corner == self::BOTTOM_RIGHT  || $corner == self::TOP_RIGHT)
            
$x $this->getWidth() - $paddingX $width;
        else
            
$x $paddingX;

        return new 
Point((int)$x, (int)$y);
    }

    
/**
     * @ignore
     */

    
private static function isCorrectCorner($corner)
    {
        return 
in_array($cornerself::$correctCorners);
    }

    
/**
     * Проверяет, существует ли файл.
     *
     * @param string путь к файлу
     * @return boolean
     */

    
public static function isFileExists($filePath)
    {
        if (@
file_exists($filePath))
            return 
true;

        if(!
preg_match("|^http(s)?|"$filePath))
            return 
false;

        
$headers = @get_headers($filePath);
        if(
preg_match("|200|"$headers[0]))
            return 
true;

        return 
false;
    }

    
/**
     * Проверяет, является ли файл изображением.
     *
     * @param string путь к файлу
     * @return boolean
     */

    
public static function isFileImage($filePath)
    {
        if (!
self::isFileExists($filePath))
            return 
false;

        
$imageInfo = @getimagesize($filePath);
        return 
is_array($imageInfo);
    }

    
/**
     * @ignore
     */

    
protected function putBackground()
    {
        
$newImageResource imagecreatetruecolor($this->getWidth(), $this->getHeight());
        
imagefill($newImageResource 00self::getBackgroundColor()->getCode());
        
imagecopyresampled($newImageResource $this->getResource(), 0000,
            
$this->getWidth(), $this->getHeight(), $this->getWidth(), $this->getHeight());
        
$this->setResource($newImageResource);
    }

    
/**
     * @param boolean
     * @throws IllegalArgumentException
     */

    
public static function setRewrite($mode)
    {
        if (!
is_bool($mode))
            throw new 
IllegalArgumentException();

        
self::$rewrite $mode;
    }

    public static function 
getRewrite()
    {
        return 
self::$rewrite;
    }

    public function 
getImageInfo()
    {
        if (!isset(
$this->imageInfo))
            
$this->imageInfo = @getimagesize($this->getFilePath());

        return 
$this->imageInfo;
    }

    
/**
     * Возвращает две первые цифры
     * версии php, разделённые точкой.
     * Например: 5.2, 5.3
     *
     * @since 2.0.1
     *
     * @return string
     */

    
public static function getShortPHPVersion()
    {
        
$matches = array();
        
preg_match("@^d.d@"phpversion(), $matches);
        return 
$matches[0];
    }

    public static function 
isSupportedGD()
    {
        return 
function_exists('gd_info');
    }

    
/**
     *
     * Возвращает результат работы функции gd_info()
     * или false если библиотека gd не доступна
     *
     * @return array|bool
     */

    
public static function getGDinfo()
    {
        if (!
self::isSupportedGD())
            return 
false;

        if (!isset(
self::$gdInfo))
            
self::$gdInfo gd_info();

        return 
self::$gdInfo;
    }

    public function 
getFilePath()
    {
        return 
$this->filePath;
    }

    private function 
setSize(Size $s)
    {
        
$this->size $s;
    }

    public function 
getSourceImage()
    {
        return 
$this->sourceImage;
    }

    public function 
getMimeType()
    {
        
$imageInfo $this->getImageInfo();
        return 
$imageInfo['mime'];
    }

    public function 
getSize()
    {
        return clone 
$this->size;
    }

    public function 
getWidth()
    {
        return 
$this->getSize()->getWidth();
    }

    public function 
getHeight()
    {
        return 
$this->getSize()->getHeight();
    }

    public function 
getResource()
    {
        return 
$this->resource;
    }

    
/**
     * @ignore
     */

    
protected function setResource($resource)
    {
        return 
$this->resource $resource;
    }

    
// static getters and setters

    /**
     *
     * @param int качество изображения от 0 до 100
     * @throws IllegalArgumentException
     */

    
public static function setQuality($q)
    {
        
$q = (int)$q;
        if (!
is_integer($q) || $q <= || $q 100)
            throw new 
IllegalArgumentException();

        
self::$quality $q;
    }

    public static function 
getQuality()
    {
        return 
self::$quality;
    }

    
/**
     *
     * @param boolean
     * @throws IllegalArgumentException
     */

    
public static function setTransparency($mode)
    {
        if(!
is_bool($mode))
            throw new 
IllegalArgumentException();

        
self::$transparency $mode;
    }

    public static function 
getTransparency()
    {
        return 
self::$transparency;
    }

    public static function 
setBackgroundColor() // $color || $r, $r, $b || $code
    
{
        
$a func_get_args();
        if (
count($a) == 1)
        {
            if (
$a[0] instanceof AcColor)
            {
                
self::$backgroundColor $a[0];
            }
            else
            {
                
self::$backgroundColor = new AcColor($a[0]);
            }
        }
        else if (
count($a) == 3)
        {
            
self::$backgroundColor = new AcColor($a[0], $a[1], $a[2]);
        }
        else
        {
            throw new 
IllegalArgumentException();
        }
    }

    public static function 
getBackgroundColor()
    {
        if (
is_integer(self::$backgroundColor))
            
self::$backgroundColor = new AcColor(self::$backgroundColor);

        return 
self::$backgroundColor;
    }

    public function 
getCornerLogo()
    {
        return 
self::$cornerLogo;
    }

    
/**
     *
     * @param int номер угла изображения<br />
     * 0 1<br />
     * 2 3
     *
     * @see AcImage::TOP_LEFT
     * @see AcImage::TOP_RIGHT
     * @see AcImage::BOTTOM_RIGHT
     * @see AcImage::BOTTOM_LEFT
     *
     * @throws IllegalArgumentException
     */

    
public function setCornerLogo($corner)
    {
        if(!
self::isCorrectCorner($corner))
            throw new 
IllegalArgumentException();

        
self::$cornerLogo $corner;
    }

    
/**
     *
     * @param float от 0 <= $maxPropotionsLogo < 1
     * @throws IllegalArgumentException
     */

    
public static function setMaxProportionLogo($maxPropotionsLogo)
    {
        if (!
is_float($maxPropotionsLogo) || $maxPropotionsLogo ||
                        
$maxPropotionsLogo <= 0)
            throw new 
IllegalArgumentException();

        
self::$maxProportionLogo $maxPropotionsLogo;
    }

    public static function 
getMaxProportionLogo()
    {
        return 
self::$maxProportionLogo;
    }

    
/**
     *
     * @param float от 0 <= $paddingProportionLogo < 1
     * @throws IllegalArgumentException
     */

    
public static function setPaddingProportionLogo($paddingProportionLogo)
    {
        if (!
is_float($paddingProportionLogo) || $paddingProportionLogo ||
                        
$paddingProportionLogo <= 0)
            throw new 
IllegalArgumentException();

        
self::$paddingProportionLogo $paddingProportionLogo;
    }

    public static function 
getPaddingProportionLogo()
    {
            return 
self::$paddingProportionLogo;
    }
}
?>
Онлайн: 3
Реклама