2012-10-25 00:28:39 +02:00
|
|
|
<?php
|
2012-11-11 03:13:36 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @package framework
|
|
|
|
* @subpackage filesystem
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(class_exists('Imagick')) {
|
2012-10-25 00:28:39 +02:00
|
|
|
class ImagickBackend extends Imagick implements Image_Backend {
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-11-11 03:13:36 +01:00
|
|
|
/**
|
2013-03-21 19:48:54 +01:00
|
|
|
* @config
|
2012-11-11 03:13:36 +01:00
|
|
|
* @var int
|
|
|
|
*/
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $default_quality = 75;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* __construct
|
|
|
|
*
|
|
|
|
* @param string $filename = null
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function __construct($filename = null) {
|
|
|
|
if(is_string($filename)) {
|
|
|
|
parent::__construct($filename);
|
|
|
|
} else {
|
2013-03-21 19:48:54 +01:00
|
|
|
self::setImageCompressionQuality($this->config()->default_quality);
|
2012-10-25 00:28:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* writeTo
|
|
|
|
*
|
|
|
|
* @param string $path
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function writeTo($path) {
|
|
|
|
Filesystem::makeFolder(dirname($path));
|
|
|
|
if(is_dir(dirname($path)))
|
|
|
|
self::writeImage($path);
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* set_default_quality
|
|
|
|
*
|
2013-03-21 19:48:54 +01:00
|
|
|
* @deprecated 3.2 Use the "IMagickBackend.default_quality" config setting instead
|
2012-10-25 00:28:39 +02:00
|
|
|
* @param int $quality
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function set_default_quality($quality) {
|
2013-03-21 19:48:54 +01:00
|
|
|
Deprecation::notice('3.2', 'Use the "IMagickBackend.default_quality" config setting instead');
|
|
|
|
if(is_numeric($quality) && (int) $quality >= 0 && (int) $quality <= 100) {
|
2013-03-26 00:02:46 +01:00
|
|
|
config::inst()->update('IMagickBackend', 'default_quality', (int) $quality);
|
2013-03-21 19:48:54 +01:00
|
|
|
}
|
2012-10-25 00:28:39 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* setQuality
|
|
|
|
*
|
|
|
|
* @param int $quality
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function setQuality($quality) {
|
|
|
|
self::setImageCompressionQuality($quality);
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* setImageResource
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-25 00:28:39 +02:00
|
|
|
* Set the backend-specific resource handling the manipulations. Replaces Image::setGD()
|
|
|
|
*
|
|
|
|
* @param mixed $resource
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function setImageResource($resource) {
|
|
|
|
trigger_error("Imagick::setImageResource is not supported", E_USER_ERROR);
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* getImageResource
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-25 00:28:39 +02:00
|
|
|
* Get the backend-specific resource handling the manipulations. Replaces Image::getGD()
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function getImageResource() {
|
|
|
|
return $this;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* hasImageResource
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function hasImageResource() {
|
|
|
|
return true; // $this is the resource, necessarily
|
|
|
|
}
|
|
|
|
|
2014-01-02 16:59:34 +01:00
|
|
|
/**
|
|
|
|
* @todo Implement memory checking for Imagick? See {@link GD}
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2014-01-02 16:59:34 +01:00
|
|
|
* @param string $filename
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function imageAvailable($filename) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* resize
|
|
|
|
*
|
|
|
|
* @param int $width
|
|
|
|
* @param int $height
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
|
|
|
public function resize($width, $height) {
|
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$width = round($width);
|
|
|
|
$height = round($height);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$geometry = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
// Check that a resize is actually necessary.
|
|
|
|
if ($width == $geometry["width"] && $height == $geometry["height"]) {
|
|
|
|
return $this;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
if(!$width && !$height) user_error("No dimensions given", E_USER_ERROR);
|
|
|
|
if(!$width) user_error("Width not given", E_USER_ERROR);
|
|
|
|
if(!$height) user_error("Height not given", E_USER_ERROR);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$new = clone $this;
|
|
|
|
$new->resizeImage($width, $height, self::FILTER_LANCZOS, 1);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
return $new;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* resizeRatio
|
|
|
|
*
|
|
|
|
* @param int $width
|
|
|
|
* @param int $height
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
|
|
|
public function resizeRatio($maxWidth, $maxHeight, $useAsMinimum = false) {
|
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$geometry = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$widthRatio = $maxWidth / $geometry["width"];
|
|
|
|
$heightRatio = $maxHeight / $geometry["height"];
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
if( $widthRatio < $heightRatio )
|
|
|
|
return $useAsMinimum ? $this->resizeByHeight( $maxHeight ) : $this->resizeByWidth( $maxWidth );
|
|
|
|
else
|
|
|
|
return $useAsMinimum ? $this->resizeByWidth( $maxWidth ) : $this->resizeByHeight( $maxHeight );
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* resizeByWidth
|
|
|
|
*
|
|
|
|
* @param int $width
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
|
|
|
public function resizeByWidth($width) {
|
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$geometry = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$heightScale = $width / $geometry["width"];
|
|
|
|
return $this->resize( $width, $heightScale * $geometry["height"] );
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* resizeByHeight
|
|
|
|
*
|
|
|
|
* @param int $height
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
|
|
|
public function resizeByHeight($height) {
|
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$geometry = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$scale = $height / $geometry["height"];
|
|
|
|
return $this->resize( $scale * $geometry["width"], $height );
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* paddedResize
|
|
|
|
*
|
|
|
|
* @param int $width
|
|
|
|
* @param int $height
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
2013-08-25 01:37:00 +02:00
|
|
|
public function paddedResize($width, $height, $backgroundColor = "#FFFFFF00") {
|
2012-10-25 00:28:39 +02:00
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$width = round($width);
|
|
|
|
$height = round($height);
|
|
|
|
$geometry = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
// Check that a resize is actually necessary.
|
|
|
|
if ($width == $geometry["width"] && $height == $geometry["height"]) {
|
|
|
|
return $this;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$new = clone $this;
|
|
|
|
$new->setBackgroundColor($backgroundColor);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$destAR = $width / $height;
|
|
|
|
if ($geometry["width"] > 0 && $geometry["height"] > 0) {
|
|
|
|
// We can't divide by zero theres something wrong.
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$srcAR = $geometry["width"] / $geometry["height"];
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
// Destination narrower than the source
|
|
|
|
if($destAR > $srcAR) {
|
|
|
|
$destY = 0;
|
|
|
|
$destHeight = $height;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$destWidth = round( $height * $srcAR );
|
|
|
|
$destX = round( ($width - $destWidth) / 2 );
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
// Destination shorter than the source
|
|
|
|
} else {
|
|
|
|
$destX = 0;
|
|
|
|
$destWidth = $width;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$destHeight = round( $width / $srcAR );
|
|
|
|
$destY = round( ($height - $destHeight) / 2 );
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$new->extentImage($width, $height, $destX, $destY);
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
return $new;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
/**
|
|
|
|
* croppedResize
|
|
|
|
*
|
|
|
|
* @param int $width
|
|
|
|
* @param int $height
|
|
|
|
* @return Image_Backend
|
|
|
|
*/
|
|
|
|
public function croppedResize($width, $height) {
|
|
|
|
if(!$this->valid()) return;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$width = round($width);
|
|
|
|
$height = round($height);
|
2013-05-07 17:07:58 +02:00
|
|
|
$geo = $this->getImageGeometry();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
// Check that a resize is actually necessary.
|
2013-05-07 17:07:58 +02:00
|
|
|
if ($width == $geo["width"] && $height == $geo["height"]) {
|
2012-10-25 00:28:39 +02:00
|
|
|
return $this;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2013-05-07 17:07:58 +02:00
|
|
|
if(!$backgroundColor){
|
|
|
|
$backgroundColor = new ImagickPixel('transparent');
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-25 00:28:39 +02:00
|
|
|
$new = clone $this;
|
|
|
|
$new->setBackgroundColor($backgroundColor);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2013-05-07 17:07:58 +02:00
|
|
|
if(($geo['width']/$width) < ($geo['height']/$height)){
|
2013-08-21 08:54:05 +02:00
|
|
|
$new->cropImage($geo['width'], floor($height*$geo['width']/$width),
|
|
|
|
0, (($geo['height']-($height*$geo['width']/$width))/2));
|
2013-05-07 17:07:58 +02:00
|
|
|
}else{
|
2013-08-21 08:54:05 +02:00
|
|
|
$new->cropImage(ceil($width*$geo['height']/$height), $geo['height'],
|
|
|
|
(($geo['width']-($width*$geo['height']/$height))/2), 0);
|
2012-10-25 00:28:39 +02:00
|
|
|
}
|
2013-05-07 17:07:58 +02:00
|
|
|
$new->ThumbnailImage($width,$height,true);
|
2012-10-25 00:28:39 +02:00
|
|
|
return $new;
|
|
|
|
}
|
2014-01-02 16:59:34 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Image $frontend
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onBeforeDelete($frontend) {
|
|
|
|
// Not in use
|
|
|
|
}
|
2012-10-25 00:28:39 +02:00
|
|
|
}
|
2013-08-21 08:54:05 +02:00
|
|
|
}
|