You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
9.8 KiB
327 lines
9.8 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yii\imagine; |
|
|
|
use Imagine\Exception\InvalidArgumentException; |
|
use Imagine\Image\Box; |
|
use Imagine\Image\Color; |
|
use Imagine\Image\ManipulatorInterface; |
|
use Imagine\Image\Point; |
|
use yii\base\Component; |
|
use yii\base\InvalidConfigException; |
|
use yii\helpers\ArrayHelper; |
|
|
|
/** |
|
* Image implements most common image manipulation functions using Imagine library. |
|
* |
|
* To use Image, you should configure it in the application configuration like the following, |
|
* |
|
* ~~~ |
|
* 'components' => [ |
|
* ... |
|
* 'image' => [ |
|
* 'class' => 'yii\imagine\Image', |
|
* 'driver' => \yii\imagine\Image::DRIVER_GD2, |
|
* ], |
|
* ... |
|
* ], |
|
* ~~~ |
|
* |
|
* But you can also use it directly, |
|
* |
|
* ~~~ |
|
* use yii\imagine\Image; |
|
* |
|
* $img = new Image(); |
|
* ~~~ |
|
* |
|
* Example of use: |
|
* |
|
* ~~~ |
|
* // thumb - saved on runtime path |
|
* $imagePath = Yii::$app->getBasePath() . '/web/img/test-image.jpg'; |
|
* $runtimePath = Yii::$app->getRuntimePath(); |
|
* Yii::$app->image |
|
* ->thumb($imagePath, 120, 120) |
|
* ->save($runtime . '/thumb-test-image.jpg', ['quality' => 50]); |
|
* ~~~ |
|
* |
|
* |
|
* @see http://imagine.readthedocs.org/ |
|
* |
|
* @author Antonio Ramirez <amigo.cobos@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
class Image extends Component |
|
{ |
|
/** |
|
* GD2 driver definition for Imagine implementation using the GD library. |
|
*/ |
|
const DRIVER_GD2 = 'gd2'; |
|
/** |
|
* imagick driver definition. |
|
*/ |
|
const DRIVER_IMAGICK = 'imagick'; |
|
/** |
|
* gmagick driver definition. |
|
*/ |
|
const DRIVER_GMAGICK = 'gmagick'; |
|
/** |
|
* @var \Imagine\Image\ImagineInterface instance. |
|
*/ |
|
private $_imagine; |
|
/** |
|
* @var string the driver to use. These can be: |
|
* - [[DRIVER_GD2]] |
|
* - [[DRIVER_IMAGICK]] |
|
* - [[DRIVER_GMAGICK]] |
|
*/ |
|
private $_driver = self::DRIVER_GD2; |
|
|
|
/** |
|
* Sets the driver. |
|
* @param $driver |
|
* @throws \yii\base\InvalidConfigException |
|
*/ |
|
public function setDriver($driver) |
|
{ |
|
if (!is_string($driver) || !in_array($driver, $this->getAvailableDrivers(), true)) { |
|
throw new InvalidConfigException( |
|
strtr('"{class}::driver" should be string of these possible options "{drivers}", "{driver}" given.', [ |
|
'{class}' => get_class($this), |
|
'{drivers}' => implode('", "', $this->getAvailableDrivers()), |
|
'{driver}' => $driver |
|
])); |
|
} |
|
$this->_driver = $driver; |
|
} |
|
|
|
/** |
|
* Returns the driver which is going to be used for \Imagine\Image\ImagineInterface instance creation. |
|
* @return string the driver used. |
|
*/ |
|
public function getDriver() |
|
{ |
|
return $this->_driver; |
|
} |
|
|
|
/** |
|
* @return array of available drivers. |
|
*/ |
|
public function getAvailableDrivers() |
|
{ |
|
static $drivers; |
|
if ($drivers === null) { |
|
$drivers = [static::DRIVER_GD2, static::DRIVER_GMAGICK, static::DRIVER_IMAGICK]; |
|
} |
|
return $drivers; |
|
} |
|
|
|
/** |
|
* @return \Imagine\Image\ImagineInterface instance |
|
*/ |
|
public function getImagine() |
|
{ |
|
if ($this->_imagine === null) { |
|
switch ($this->_driver) { |
|
case static::DRIVER_GD2: |
|
$this->_imagine = new \Imagine\Gd\Imagine(); |
|
break; |
|
case static::DRIVER_IMAGICK: |
|
$this->_imagine = new \Imagine\Imagick\Imagine(); |
|
break; |
|
case static::DRIVER_GMAGICK: |
|
$this->_imagine = new \Imagine\Gmagick\Imagine(); |
|
break; |
|
} |
|
} |
|
return $this->_imagine; |
|
} |
|
|
|
/** |
|
* Crops an image |
|
* @param string $filename the full path to the image file |
|
* @param integer $width the crop width |
|
* @param integer $height the crop height |
|
* @param mixed $point. This argument can be both an array or an \Imagine\Image\Point type class, containing both |
|
* `x` and `y` coordinates. For example: |
|
* ~~~ |
|
* // as array |
|
* $obj->crop('path\to\image.jpg', 200, 200, [5, 5]); |
|
* // as \Imagine\Image\Point |
|
* $point = new \Imagine\Image\Point(5, 5); |
|
* $obj->crop('path\to\image.jpg', 200, 200, $point); |
|
* ~~~ |
|
* If null, it will crop from 0,0 pixel position |
|
* @return \Imagine\Image\ManipulatorInterface |
|
* @throws \InvalidArgumentException |
|
*/ |
|
public function crop($filename, $width, $height, $point = null) |
|
{ |
|
if(is_array($point)) { |
|
list($x, $y) = $point; |
|
$point = new Point($x, $y); |
|
} elseif ($point === null) { |
|
$point = new Point(0, 0); |
|
} elseif (!$point instanceof Point ) { |
|
throw new \InvalidArgumentException( |
|
strtr('"{class}::crop()" "$point" if not null, should be an "array" or a "{type}" class type, containing both "x" and "y" coordinates.', [ |
|
'{class}' => get_class($this), |
|
'{type}' => 'Imagine\\Image\\Point' |
|
])); |
|
} |
|
return $this->getImagine() |
|
->open($filename) |
|
->copy() |
|
->crop($point, new Box($width, $height)); |
|
} |
|
|
|
/** |
|
* Creates a thumbnail image. The function differs from [[\Imagine\Image\ImageInterface::thumbnail()]] function that |
|
* it keeps the aspect ratio of the image. |
|
* @param string $filename the full path to the image file |
|
* @param integer $width the width to create the thumbnail |
|
* @param integer $height the height in pixels to create the thumbnail |
|
* @param string $mode |
|
* @return \Imagine\Image\ImageInterface|ManipulatorInterface |
|
*/ |
|
public function thumbnail($filename, $width, $height, $mode = ManipulatorInterface::THUMBNAIL_OUTBOUND) |
|
{ |
|
$box = new Box($width, $height); |
|
$img = $this->getImagine() |
|
->open($filename); |
|
|
|
if(($img->getSize()->getWidth() <= $box->getWidth() && $img->getSize()->getHeight() <= $box->getHeight()) |
|
|| (!$box->getWidth() && !$box->getHeight())) { |
|
return $img->copy(); |
|
} |
|
$img = $img->thumbnail($box, $mode); |
|
|
|
// create empty image to preserve aspect ratio of thumbnail |
|
$thumb = $this->getImagine() |
|
->create($box); |
|
|
|
// calculate points |
|
$size = $img->getSize(); |
|
|
|
$startX = 0; |
|
$startY = 0; |
|
if ($size->getWidth() < $width) { |
|
$startX = ceil($width - $size->getWidth()) / 2; |
|
} |
|
if ($size->getHeight() < $height) { |
|
$startY = ceil($height - $size->getHeight()) / 2; |
|
} |
|
|
|
$thumb->paste($img, new Point($startX, $startY)); |
|
|
|
return $thumb; |
|
} |
|
|
|
/** |
|
* Paste a watermark image onto another. |
|
* Note: If any of `$x` or `$y` parameters are null, bottom right position will be default. |
|
* @param string $filename the full path to the image file to apply the watermark to |
|
* @param string $watermarkFilename the full path to the image file to apply as watermark |
|
* @param mixed $point. This argument can be both an array or an \Imagine\Image\Point type class, containing both |
|
* `x` and `y` coordinates. For example: |
|
* ~~~ |
|
* // as array |
|
* $obj->watermark('path\to\image.jpg', 'path\to\watermark.jpg', [5, 5]); |
|
* // as \Imagine\Image\Point |
|
* $point = new \Imagine\Image\Point(5, 5); |
|
* $obj->watermark('path\to\image.jpg', 'path\to\watermark.jpg', $point); |
|
* ~~~ |
|
* @return ManipulatorInterface |
|
* @throws \InvalidArgumentException |
|
*/ |
|
public function watermark($filename, $watermarkFilename, $point = null) |
|
{ |
|
$img = $this->getImagine()->open($filename); |
|
$watermark = $this->getImagine()->open($watermarkFilename); |
|
|
|
$size = $img->getSize(); |
|
$wSize = $watermark->getSize(); |
|
|
|
// if x or y position was not given, set its bottom right by default |
|
if(is_array($point)) { |
|
list($x, $y) = $point; |
|
$point = new Point($x, $y); |
|
} elseif ($point === null) { |
|
$x = $size->getWidth() - $wSize->getWidth(); |
|
$y = $size->getHeight() - $wSize->getHeight(); |
|
$point = new Point($x, $y); |
|
} elseif (!$point instanceof Point) { |
|
throw new \InvalidArgumentException( |
|
strtr('"{class}::watermark()" "$point" if not null, should be an "array" or a "{type}" class type, containing both "x" and "y" coordinates.', [ |
|
'{class}' => get_class($this), |
|
'{type}' => 'Imagine\\Image\\Point' |
|
])); |
|
} |
|
|
|
return $img->paste($watermark, $point); |
|
} |
|
|
|
/** |
|
* Draws text to an image. |
|
* @param string $filename the full path to the image file |
|
* @param string $text the text to write to the image |
|
* @param array $fontConfig the font configuration. The font configuration holds the following keys: |
|
* - font: The path to the font file to use to style the text. Required parameter. |
|
* - size: The font size. Defaults to 12. |
|
* - posX: The X position to write the text. Defaults to 5. |
|
* - posY: The Y position to write the text. Defaults to 5. |
|
* - angle: The angle to use to write the text. Defaults to 0. |
|
* @return \Imagine\Image\ImageInterface |
|
* @throws \Imagine\Exception\InvalidArgumentException |
|
*/ |
|
public function text($filename, $text, array $fontConfig) |
|
{ |
|
$img = $this->getImagine()->open($filename); |
|
|
|
$font = ArrayHelper::getValue($fontConfig, 'font'); |
|
if ($font === null) { |
|
throw new InvalidArgumentException('"' . get_class($this) . |
|
'::text()" "$fontConfig" parameter should contain a "font" key with the path to the font file to use.'); |
|
} |
|
$fontSize = ArrayHelper::getValue($fontConfig, 'size', 12); |
|
$fontColor = ArrayHelper::getValue($fontConfig, 'color', 'fff'); |
|
$fontPosX = ArrayHelper::getValue($fontConfig, 'posX', 5); |
|
$fontPosY = ArrayHelper::getValue($fontConfig, 'posY', 5); |
|
$fontAngle = ArrayHelper::getValue($fontConfig, 'angle', 0); |
|
|
|
$font = $this->getImagine()->font($font, $fontSize, new Color($fontColor)); |
|
$img->draw()->text($text, $font, new Point($fontPosX, $fontPosY), $fontAngle); |
|
return $img; |
|
} |
|
|
|
/** |
|
* Adds a frame around of the image. Please note that the image will increase `$margin` x 2. |
|
* @param string $filename the full path to the image file |
|
* @param integer $margin the frame size to add around the image |
|
* @param string $color the frame color |
|
* @param integer $alpha |
|
* @return \Imagine\Image\ImageInterface |
|
*/ |
|
public function frame($filename, $margin, $color='000', $alpha = 100) |
|
{ |
|
$img = $this->getImagine()->open($filename); |
|
|
|
$size = $img->getSize(); |
|
|
|
$pasteTo = new Point($margin, $margin); |
|
$padColor = new Color($color, $alpha); |
|
|
|
$box = new Box($size->getWidth() + ceil($margin * 2), $size->getHeight() + ceil($margin * 2)); |
|
|
|
$image = $this->getImagine()->create( $box, $padColor); |
|
$image->paste($img, $pasteTo); |
|
|
|
return $image; |
|
} |
|
} |