2012-04-25 15:49:09 +02:00
< ? php
/**
2014-02-12 14:45:25 +01:00
* Resize and crop images on the fly , store generated images in a cache .
2012-04-25 15:49:09 +02:00
*
2015-01-27 22:40:28 +01:00
* @ author Mikael Roos mos @ dbwebb . se
2014-02-12 14:45:25 +01:00
* @ example http :// dbwebb . se / opensource / cimage
2015-01-27 22:40:28 +01:00
* @ link https :// github . com / mosbth / cimage
2012-04-25 15:49:09 +02:00
*/
2014-08-31 23:57:34 +02:00
class CImage
2014-02-12 14:45:25 +01:00
{
/**
* Constants type of PNG image
*/
const PNG_GREYSCALE = 0 ;
const PNG_RGB = 2 ;
const PNG_RGB_PALETTE = 3 ;
const PNG_GREYSCALE_ALPHA = 4 ;
const PNG_RGB_ALPHA = 6 ;
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
/**
* Constant for default image quality when not set
*/
const JPEG_QUALITY_DEFAULT = 60 ;
/**
* Quality level for JPEG images .
*/
private $quality ;
2014-12-13 00:12:39 +01:00
/**
* Is the quality level set from external use ( true ) or is it default ( false ) ?
*/
private $useQuality = false ;
2014-02-12 14:45:25 +01:00
/**
* Constant for default image quality when not set
*/
const PNG_COMPRESSION_DEFAULT = - 1 ;
/**
* Compression level for PNG images .
*/
private $compress ;
2014-12-13 00:12:39 +01:00
/**
* Is the compress level set from external use ( true ) or is it default ( false ) ?
*/
private $useCompress = false ;
2015-10-21 01:12:10 +02:00
/**
* Add HTTP headers for outputing image .
*/
private $HTTPHeader = array ();
2014-12-03 15:23:50 +01:00
/**
* Default background color , red , green , blue , alpha .
2014-12-03 15:42:49 +01:00
*
* @ todo remake when upgrading to PHP 5.5
2014-12-03 15:23:50 +01:00
*/
2014-12-03 15:42:49 +01:00
/*
2014-12-03 15:23:50 +01:00
const BACKGROUND_COLOR = array (
'red' => 0 ,
'green' => 0 ,
'blue' => 0 ,
'alpha' => null ,
2014-12-03 15:42:49 +01:00
); */
2014-12-03 15:23:50 +01:00
/**
* Default background color to use .
2014-12-03 15:42:49 +01:00
*
* @ todo remake when upgrading to PHP 5.5
2014-12-03 15:23:50 +01:00
*/
2014-12-03 15:42:49 +01:00
//private $bgColorDefault = self::BACKGROUND_COLOR;
private $bgColorDefault = array (
'red' => 0 ,
'green' => 0 ,
'blue' => 0 ,
'alpha' => null ,
);
2014-12-03 15:23:50 +01:00
/**
* Background color to use , specified as part of options .
*/
private $bgColor ;
2014-02-12 14:45:25 +01:00
/**
* Where to save the target file .
*/
private $saveFolder ;
/**
* The working image object .
*/
private $image ;
/**
* Image filename , may include subdirectory , relative from $imageFolder
*/
private $imageSrc ;
/**
* Actual path to the image , $imageFolder . '/' . $imageSrc
*/
private $pathToImage ;
/**
2015-03-06 13:00:21 +01:00
* File type for source image , as provided by getimagesize ()
2014-02-12 14:45:25 +01:00
*/
2015-03-06 13:00:21 +01:00
private $fileType ;
2014-02-12 14:45:25 +01:00
/**
2014-11-21 21:01:22 +01:00
* File extension to use when saving image .
2014-02-12 14:45:25 +01:00
*/
private $extension ;
2014-11-21 22:20:30 +01:00
/**
* Output format , supports null ( image ) or json .
*/
private $outputFormat = null ;
2014-02-12 14:45:25 +01:00
/**
* Verbose mode to print out a trace and display the created image
*/
private $verbose = false ;
/**
* Keep a log / trace on what happens
*/
2014-08-31 23:57:34 +02:00
private $log = array ();
2014-02-12 14:45:25 +01:00
/**
* Handle image as palette image
*/
private $palette ;
/**
* Target filename , with path , to save resulting image in .
*/
private $cacheFileName ;
/**
* Set a format to save image as , or null to use original format .
*/
private $saveAs ;
/**
* Path to command for filter optimize , for example optipng or null .
*/
private $pngFilter ;
2015-09-17 11:22:50 +02:00
private $pngFilterCmd ;
2014-02-12 14:45:25 +01:00
/**
* Path to command for deflate optimize , for example pngout or null .
*/
private $pngDeflate ;
2015-09-17 11:22:50 +02:00
private $pngDeflateCmd ;
2014-02-12 14:45:25 +01:00
/**
* Path to command to optimize jpeg images , for example jpegtran or null .
*/
2015-12-07 16:01:47 +01:00
private $jpegOptimize ;
private $jpegOptimizeCmd ;
2015-09-17 11:22:50 +02:00
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
/**
* Image dimensions , calculated from loaded image .
*/
private $width ; // Calculated from source image
private $height ; // Calculated from source image
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
/**
* New image dimensions , incoming as argument or calculated .
*/
private $newWidth ;
private $newWidthOrig ; // Save original value
private $newHeight ;
private $newHeightOrig ; // Save original value
2014-02-12 14:45:25 +01:00
2015-01-10 20:17:12 +01:00
2014-11-21 23:44:19 +01:00
/**
2014-11-24 07:41:32 +01:00
* Change target height & width when different dpr , dpr 2 means double image dimensions .
2014-11-21 23:44:19 +01:00
*/
2014-11-24 07:41:32 +01:00
private $dpr = 1 ;
2014-11-21 23:44:19 +01:00
2012-04-25 15:49:09 +02:00
2014-12-15 15:41:51 +01:00
/**
* Always upscale images , even if they are smaller than target image .
*/
2014-12-15 17:14:06 +01:00
const UPSCALE_DEFAULT = true ;
2014-12-15 15:41:51 +01:00
private $upscale = self :: UPSCALE_DEFAULT ;
2014-09-01 00:38:26 +02:00
/**
* Array with details on how to crop , incoming as argument and calculated .
*/
public $crop ;
public $cropOrig ; // Save original value
2014-11-24 09:27:47 +01:00
/**
2014-11-27 22:04:41 +01:00
* String with details on how to do image convolution . String
* should map a key in the $convolvs array or be a string of
* 11 float values separated by comma . The first nine builds
2015-01-10 20:17:12 +01:00
* up the matrix , then divisor and last offset .
2014-11-24 09:27:47 +01:00
*/
private $convolve ;
2014-08-31 23:57:34 +02:00
/**
2015-01-10 20:17:12 +01:00
* Custom convolution expressions , matrix 3 x3 , divisor and offset .
2014-11-27 22:04:41 +01:00
*/
private $convolves = array (
2014-12-06 14:33:23 +01:00
'lighten' => '0,0,0, 0,12,0, 0,0,0, 9, 0' ,
'darken' => '0,0,0, 0,6,0, 0,0,0, 9, 0' ,
'sharpen' => '-1,-1,-1, -1,16,-1, -1,-1,-1, 8, 0' ,
'sharpen-alt' => '0,-1,0, -1,5,-1, 0,-1,0, 1, 0' ,
'emboss' => '1,1,-1, 1,3,-1, 1,-1,-1, 3, 0' ,
'emboss-alt' => '-2,-1,0, -1,1,1, 0,1,2, 1, 0' ,
'blur' => '1,1,1, 1,15,1, 1,1,1, 23, 0' ,
'gblur' => '1,2,1, 2,4,2, 1,2,1, 16, 0' ,
'edge' => '-1,-1,-1, -1,8,-1, -1,-1,-1, 9, 0' ,
'edge-alt' => '0,1,0, 1,-4,1, 0,1,0, 1, 0' ,
'draw' => '0,-1,0, -1,5,-1, 0,-1,0, 0, 0' ,
'mean' => '1,1,1, 1,1,1, 1,1,1, 9, 0' ,
'motion' => '1,0,0, 0,1,0, 0,0,1, 3, 0' ,
2014-11-27 22:04:41 +01:00
);
2014-12-03 15:23:50 +01:00
/**
2015-01-10 20:17:12 +01:00
* Resize strategy to fill extra area with background color .
2014-12-03 15:23:50 +01:00
* True or false .
*/
private $fillToFit ;
2015-09-17 11:22:50 +02:00
/**
* To store value for option scale .
*/
private $scale ;
/**
* To store value for option .
*/
private $rotateBefore ;
/**
* To store value for option .
*/
private $rotateAfter ;
/**
* To store value for option .
*/
private $autoRotate ;
/**
* To store value for option .
*/
private $sharpen ;
/**
* To store value for option .
*/
private $emboss ;
/**
* To store value for option .
*/
private $blur ;
2014-11-27 22:04:41 +01:00
/**
2015-01-10 20:17:12 +01:00
* Used with option area to set which parts of the image to use .
2014-08-31 23:57:34 +02:00
*/
private $offset ;
2013-10-03 18:16:33 +02:00
2014-12-03 16:15:32 +01:00
2014-12-14 17:04:51 +01:00
/**
2015-12-07 16:01:47 +01:00
* Calculate target dimension for image when using fill - to - fit resize strategy .
*/
2014-12-14 17:04:51 +01:00
private $fillWidth ;
private $fillHeight ;
2015-01-10 20:17:12 +01:00
/**
2015-12-07 16:01:47 +01:00
* Allow remote file download , default is to disallow remote file download .
*/
2015-01-10 20:17:12 +01:00
private $allowRemote = false ;
2015-12-07 16:01:47 +01:00
/**
* Path to cache for remote download .
*/
private $remoteCache ;
2015-01-10 20:17:12 +01:00
/**
* Pattern to recognize a remote file .
*/
2015-01-14 19:28:52 +01:00
//private $remotePattern = '#^[http|https]://#';
private $remotePattern = '#^https?://#' ;
2015-01-10 20:17:12 +01:00
/**
* Use the cache if true , set to false to ignore the cached file .
*/
private $useCache = true ;
2015-07-25 22:21:12 +02:00
/*
* Set whitelist for valid hostnames from where remote source can be
* downloaded .
*/
private $remoteHostWhitelist = null ;
/*
* Do verbose logging to file by setting this to a filename .
*/
private $verboseFileName = null ;
2015-09-01 16:45:10 +02:00
/*
2015-10-20 13:46:01 +02:00
* Output to ascii can take som options as an array .
2015-09-01 16:45:10 +02:00
*/
private $asciiOptions = array ();
2015-10-20 13:46:01 +02:00
/*
* Image copy strategy , defaults to RESAMPLE .
*/
const RESIZE = 1 ;
const RESAMPLE = 2 ;
2015-12-07 16:01:47 +01:00
private $copyStrategy = NULL ;
2015-10-20 13:46:01 +02:00
2014-12-03 16:15:32 +01:00
/**
* Properties , the class is mutable and the method setOptions ()
2015-01-10 20:17:12 +01:00
* decides ( partly ) what properties are created .
2014-12-03 16:15:32 +01:00
*
* @ todo Clean up these and check if and how they are used
*/
2014-12-06 14:33:23 +01:00
public $keepRatio ;
public $cropToFit ;
private $cropWidth ;
private $cropHeight ;
public $crop_x ;
public $crop_y ;
public $filters ;
private $attr ; // Calculated from source image
2013-10-03 18:16:33 +02:00
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
* Constructor , can take arguments to init the object .
*
* @ param string $imageSrc filename which may contain subdirectory .
* @ param string $imageFolder path to root folder for images .
* @ param string $saveFolder path to folder where to save the new file or null to skip saving .
* @ param string $saveName name of target file when saveing .
*/
2014-08-31 23:57:34 +02:00
public function __construct ( $imageSrc = null , $imageFolder = null , $saveFolder = null , $saveName = null )
2014-02-12 14:45:25 +01:00
{
$this -> setSource ( $imageSrc , $imageFolder );
$this -> setTarget ( $saveFolder , $saveName );
}
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
* Set verbose mode .
*
2015-01-10 20:17:12 +01:00
* @ param boolean $mode true or false to enable and disable verbose mode ,
* default is true .
2014-02-12 14:45:25 +01:00
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function setVerbose ( $mode = true )
2014-02-12 14:45:25 +01:00
{
$this -> verbose = $mode ;
return $this ;
}
2015-01-10 20:17:12 +01:00
/**
* Set save folder , base folder for saving cache files .
*
* @ todo clean up how $this -> saveFolder is used in other methods .
*
* @ param string $path where to store cached files .
*
* @ return $this
*/
public function setSaveFolder ( $path )
{
$this -> saveFolder = $path ;
return $this ;
}
/**
* Use cache or not .
*
2015-09-17 11:22:50 +02:00
* @ param boolean $use true or false to use cache .
2015-01-10 20:17:12 +01:00
*
* @ return $this
*/
public function useCache ( $use = true )
{
$this -> useCache = $use ;
return $this ;
}
2015-09-16 09:51:04 +02:00
/**
2015-09-17 11:22:50 +02:00
* Create and save a dummy image . Use dimensions as stated in
* $this -> newWidth , or $width or default to 100 ( same for height .
2015-09-16 09:51:04 +02:00
*
2015-09-17 11:22:50 +02:00
* @ param integer $width use specified width for image dimension .
* @ param integer $height use specified width for image dimension .
2015-09-16 09:51:04 +02:00
*
* @ return $this
*/
2015-09-17 11:22:50 +02:00
public function createDummyImage ( $width = null , $height = null )
2015-09-16 09:51:04 +02:00
{
2015-09-17 11:22:50 +02:00
$this -> newWidth = $this -> newWidth ? : $width ? : 100 ;
$this -> newHeight = $this -> newHeight ? : $height ? : 100 ;
2015-09-16 09:51:04 +02:00
2015-09-17 11:22:50 +02:00
$this -> image = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
2015-09-16 09:51:04 +02:00
return $this ;
}
2015-01-10 20:17:12 +01:00
/**
* Allow or disallow remote image download .
*
* @ param boolean $allow true or false to enable and disable .
2015-12-07 15:12:20 +01:00
* @ param string $cache path to cache dir .
2015-01-10 20:17:12 +01:00
* @ param string $pattern to use to detect if its a remote file .
*
* @ return $this
*/
2015-12-07 15:12:20 +01:00
public function setRemoteDownload ( $allow , $cache , $pattern = null )
2015-01-10 20:17:12 +01:00
{
$this -> allowRemote = $allow ;
2015-12-07 15:12:20 +01:00
$this -> remoteCache = $cache ;
2015-03-04 11:29:10 +01:00
$this -> remotePattern = is_null ( $pattern ) ? $this -> remotePattern : $pattern ;
2015-01-10 20:17:12 +01:00
2015-07-25 22:21:12 +02:00
$this -> log (
" Set remote download to: "
2015-01-10 20:17:12 +01:00
. ( $this -> allowRemote ? " true " : " false " )
. " using pattern "
2015-07-25 22:21:12 +02:00
. $this -> remotePattern
);
2015-01-10 20:17:12 +01:00
return $this ;
}
/**
* Check if the image resource is a remote file or not .
*
* @ param string $src check if src is remote .
*
* @ return boolean true if $src is a remote file , else false .
*/
public function isRemoteSource ( $src )
{
2015-01-14 19:28:52 +01:00
$remote = preg_match ( $this -> remotePattern , $src );
2015-01-10 20:17:12 +01:00
$this -> log ( " Detected remote image: " . ( $remote ? " true " : " false " ));
2015-03-04 11:29:10 +01:00
return !! $remote ;
}
/**
2015-07-23 11:32:19 +02:00
* Set whitelist for valid hostnames from where remote source can be
2015-03-04 11:29:10 +01:00
* downloaded .
*
* @ param array $whitelist with regexp hostnames to allow download from .
*
* @ return $this
*/
public function setRemoteHostWhitelist ( $whitelist = null )
{
$this -> remoteHostWhitelist = $whitelist ;
2015-07-25 22:21:12 +02:00
$this -> log (
" Setting remote host whitelist to: "
. ( is_null ( $whitelist ) ? " null " : print_r ( $whitelist , 1 ))
);
2015-03-04 11:29:10 +01:00
return $this ;
}
/**
2015-07-23 11:32:19 +02:00
* Check if the hostname for the remote image , is on a whitelist ,
2015-03-04 11:29:10 +01:00
* if the whitelist is defined .
*
* @ param string $src the remote source .
*
* @ return boolean true if hostname on $src is in the whitelist , else false .
*/
public function isRemoteSourceOnWhitelist ( $src )
{
if ( is_null ( $this -> remoteHostWhitelist )) {
2015-07-25 22:21:12 +02:00
$this -> log ( " Remote host on whitelist not configured - allowing. " );
return true ;
2015-03-04 11:29:10 +01:00
}
2015-07-25 22:21:12 +02:00
$whitelist = new CWhitelist ();
$hostname = parse_url ( $src , PHP_URL_HOST );
$allow = $whitelist -> check ( $hostname , $this -> remoteHostWhitelist );
$this -> log (
" Remote host is on whitelist: "
. ( $allow ? " true " : " false " )
);
2015-03-04 11:29:10 +01:00
return $allow ;
2015-01-10 20:17:12 +01:00
}
2014-02-12 14:45:25 +01:00
/**
* Check if file extension is valid as a file extension .
*
* @ param string $extension of image file .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
private function checkFileExtension ( $extension )
2014-02-12 14:45:25 +01:00
{
$valid = array ( 'jpg' , 'jpeg' , 'png' , 'gif' );
2014-11-21 21:01:22 +01:00
in_array ( strtolower ( $extension ), $valid )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Not a valid file extension.' );
return $this ;
2013-10-03 18:16:33 +02:00
}
2015-01-10 20:17:12 +01:00
2015-10-20 10:26:09 +02:00
/**
* Normalize the file extension .
*
* @ param string $extension of image file or skip to use internal .
*
* @ return string $extension as a normalized file extension .
*/
private function normalizeFileExtension ( $extension = null )
{
$extension = strtolower ( $extension ? $extension : $this -> extension );
2015-12-06 12:26:20 +01:00
2015-10-20 10:26:09 +02:00
if ( $extension == 'jpeg' ) {
$extension = 'jpg' ;
2015-12-07 16:01:47 +01:00
}
2015-10-20 10:26:09 +02:00
return $extension ;
}
2015-01-14 19:28:52 +01:00
/**
* Download a remote image and return path to its local copy .
*
* @ param string $src remote path to image .
*
* @ return string as path to downloaded remote source .
*/
public function downloadRemoteSource ( $src )
{
2015-03-04 11:29:10 +01:00
if ( ! $this -> isRemoteSourceOnWhitelist ( $src )) {
throw new Exception ( " Hostname is not on whitelist for remote sources. " );
}
2015-12-06 12:26:20 +01:00
2015-01-14 19:28:52 +01:00
$remote = new CRemoteImage ();
2015-01-14 21:00:08 +01:00
2015-12-07 15:12:20 +01:00
if ( ! is_writable ( $this -> remoteCache )) {
2015-01-14 19:28:52 +01:00
$this -> log ( " The remote cache is not writable. " );
}
2015-12-07 15:12:20 +01:00
$remote -> setCache ( $this -> remoteCache );
2015-01-14 19:28:52 +01:00
$remote -> useCache ( $this -> useCache );
$src = $remote -> download ( $src );
$this -> log ( " Remote HTTP status: " . $remote -> getStatus ());
2015-03-16 15:36:06 +01:00
$this -> log ( " Remote item is in local cache: $src " );
2015-01-14 19:28:52 +01:00
$this -> log ( " Remote details on cache: " . print_r ( $remote -> getDetails (), true ));
return $src ;
}
2014-02-12 14:45:25 +01:00
/**
2015-09-16 08:21:32 +02:00
* Set source file to use as image source .
2014-02-12 14:45:25 +01:00
*
* @ param string $src of image .
2015-09-16 08:21:32 +02:00
* @ param string $dir as optional base directory where images are .
2014-02-12 14:45:25 +01:00
*
* @ return $this
*/
2014-12-15 09:19:23 +01:00
public function setSource ( $src , $dir = null )
2014-02-12 14:45:25 +01:00
{
2014-12-15 09:19:23 +01:00
if ( ! isset ( $src )) {
2015-09-16 08:26:28 +02:00
$this -> imageSrc = null ;
$this -> pathToImage = null ;
2014-02-12 14:45:25 +01:00
return $this ;
2015-01-10 20:17:12 +01:00
}
2015-01-14 19:28:52 +01:00
if ( $this -> allowRemote && $this -> isRemoteSource ( $src )) {
$src = $this -> downloadRemoteSource ( $src );
2015-01-10 20:17:12 +01:00
$dir = null ;
}
if ( ! isset ( $dir )) {
2014-12-15 09:19:23 +01:00
$dir = dirname ( $src );
$src = basename ( $src );
2013-10-03 18:16:33 +02:00
}
2015-09-16 08:21:32 +02:00
$this -> imageSrc = ltrim ( $src , '/' );
$imageFolder = rtrim ( $dir , '/' );
$this -> pathToImage = $imageFolder . '/' . $this -> imageSrc ;
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
return $this ;
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
/**
* Set target file .
*
* @ param string $src of target image .
2015-09-17 11:22:50 +02:00
* @ param string $dir as optional base directory where images are stored .
* Uses $this -> saveFolder if null .
2014-02-12 14:45:25 +01:00
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function setTarget ( $src = null , $dir = null )
2014-02-12 14:45:25 +01:00
{
2015-09-17 11:22:50 +02:00
if ( ! isset ( $src )) {
$this -> cacheFileName = null ;
2014-02-12 14:45:25 +01:00
return $this ;
2012-05-09 17:57:48 +02:00
}
2013-10-03 18:16:33 +02:00
2015-09-17 11:22:50 +02:00
if ( isset ( $dir )) {
$this -> saveFolder = rtrim ( $dir , '/' );
}
$this -> cacheFileName = $this -> saveFolder . '/' . $src ;
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Sanitize filename
$this -> cacheFileName = preg_replace ( '/^a-zA-Z0-9\.-_/' , '' , $this -> cacheFileName );
$this -> log ( " The cache file name is: " . $this -> cacheFileName );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
return $this ;
}
2015-01-10 20:17:12 +01:00
2015-09-17 11:22:50 +02:00
/**
* Get filename of target file .
*
* @ return Boolean | String as filename of target or false if not set .
*/
public function getTarget ()
{
return $this -> cacheFileName ;
}
2014-02-12 14:45:25 +01:00
/**
* Set options to use when processing image .
*
* @ param array $args used when processing image .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function setOptions ( $args )
2014-02-12 14:45:25 +01:00
{
2014-08-31 23:57:34 +02:00
$this -> log ( " Set new options for processing image. " );
2014-02-12 14:45:25 +01:00
$defaults = array (
// Options for calculate dimensions
'newWidth' => null ,
'newHeight' => null ,
'aspectRatio' => null ,
'keepRatio' => true ,
'cropToFit' => false ,
2014-12-03 15:23:50 +01:00
'fillToFit' => null ,
2014-08-31 23:57:34 +02:00
'crop' => null , //array('width'=>null, 'height'=>null, 'start_x'=>0, 'start_y'=>0),
2014-02-12 14:45:25 +01:00
'area' => null , //'0,0,0,0',
2014-12-15 15:41:51 +01:00
'upscale' => self :: UPSCALE_DEFAULT ,
2014-02-12 14:45:25 +01:00
// Options for caching or using original
'useCache' => true ,
2014-08-31 23:57:34 +02:00
'useOriginal' => true ,
2014-02-12 14:45:25 +01:00
// Pre-processing, before resizing is done
2014-08-31 23:57:34 +02:00
'scale' => null ,
'rotateBefore' => null ,
2014-12-06 14:33:23 +01:00
'autoRotate' => false ,
2014-08-31 23:57:34 +02:00
// General options
2014-12-03 15:23:50 +01:00
'bgColor' => null ,
2014-02-12 14:45:25 +01:00
// Post-processing, after resizing is done
'palette' => null ,
'filters' => null ,
'sharpen' => null ,
'emboss' => null ,
'blur' => null ,
2014-11-27 22:04:41 +01:00
'convolve' => null ,
2014-08-31 23:57:34 +02:00
'rotateAfter' => null ,
2014-02-12 14:45:25 +01:00
2014-11-21 22:20:30 +01:00
// Output format
'outputFormat' => null ,
2014-11-24 07:41:32 +01:00
'dpr' => 1 ,
2014-02-12 14:45:25 +01:00
);
2014-08-15 02:07:07 -04:00
// Convert crop settings from string to array
2014-02-12 14:45:25 +01:00
if ( isset ( $args [ 'crop' ]) && ! is_array ( $args [ 'crop' ])) {
$pices = explode ( ',' , $args [ 'crop' ]);
$args [ 'crop' ] = array (
'width' => $pices [ 0 ],
'height' => $pices [ 1 ],
'start_x' => $pices [ 2 ],
'start_y' => $pices [ 3 ],
);
}
2013-10-03 18:16:33 +02:00
2014-08-15 02:07:07 -04:00
// Convert area settings from string to array
2014-02-12 14:45:25 +01:00
if ( isset ( $args [ 'area' ]) && ! is_array ( $args [ 'area' ])) {
$pices = explode ( ',' , $args [ 'area' ]);
$args [ 'area' ] = array (
'top' => $pices [ 0 ],
'right' => $pices [ 1 ],
'bottom' => $pices [ 2 ],
'left' => $pices [ 3 ],
);
}
2013-10-07 23:50:53 +02:00
2014-08-15 02:07:07 -04:00
// Convert filter settings from array of string to array of array
2014-02-12 14:45:25 +01:00
if ( isset ( $args [ 'filters' ]) && is_array ( $args [ 'filters' ])) {
foreach ( $args [ 'filters' ] as $key => $filterStr ) {
$parts = explode ( ',' , $filterStr );
$filter = $this -> mapFilter ( $parts [ 0 ]);
$filter [ 'str' ] = $filterStr ;
2014-08-31 23:57:34 +02:00
for ( $i = 1 ; $i <= $filter [ 'argc' ]; $i ++ ) {
2014-02-12 14:45:25 +01:00
if ( isset ( $parts [ $i ])) {
$filter [ " arg { $i } " ] = $parts [ $i ];
} else {
2014-11-24 09:27:47 +01:00
throw new Exception (
2015-01-10 20:17:12 +01:00
' Missing arg to filter , review how many arguments are needed at
2014-11-24 09:27:47 +01:00
http :// php . net / manual / en / function . imagefilter . php '
);
2014-02-12 14:45:25 +01:00
}
}
$args [ 'filters' ][ $key ] = $filter ;
}
}
2013-10-07 23:50:53 +02:00
2014-02-12 14:45:25 +01:00
// Merge default arguments with incoming and set properties.
//$args = array_merge_recursive($defaults, $args);
$args = array_merge ( $defaults , $args );
2014-08-31 23:57:34 +02:00
foreach ( $defaults as $key => $val ) {
2014-02-12 14:45:25 +01:00
$this -> { $key } = $args [ $key ];
2013-10-07 23:50:53 +02:00
}
2014-02-12 14:45:25 +01:00
2014-12-03 15:23:50 +01:00
if ( $this -> bgColor ) {
$this -> setDefaultBackgroundColor ( $this -> bgColor );
}
2014-09-01 00:38:26 +02:00
// Save original values to enable re-calculating
2014-08-31 23:57:34 +02:00
$this -> newWidthOrig = $this -> newWidth ;
$this -> newHeightOrig = $this -> newHeight ;
2014-09-01 00:38:26 +02:00
$this -> cropOrig = $this -> crop ;
2014-08-31 23:57:34 +02:00
2014-02-12 14:45:25 +01:00
return $this ;
}
/**
* Map filter name to PHP filter and id .
*
* @ param string $name the name of the filter .
*
* @ return array with filter settings
2015-01-10 20:17:12 +01:00
* @ throws Exception
2014-02-12 14:45:25 +01:00
*/
2014-08-31 23:57:34 +02:00
private function mapFilter ( $name )
2014-02-12 14:45:25 +01:00
{
$map = array (
2014-08-31 23:57:34 +02:00
'negate' => array ( 'id' => 0 , 'argc' => 0 , 'type' => IMG_FILTER_NEGATE ),
2014-02-12 14:45:25 +01:00
'grayscale' => array ( 'id' => 1 , 'argc' => 0 , 'type' => IMG_FILTER_GRAYSCALE ),
'brightness' => array ( 'id' => 2 , 'argc' => 1 , 'type' => IMG_FILTER_BRIGHTNESS ),
'contrast' => array ( 'id' => 3 , 'argc' => 1 , 'type' => IMG_FILTER_CONTRAST ),
'colorize' => array ( 'id' => 4 , 'argc' => 4 , 'type' => IMG_FILTER_COLORIZE ),
'edgedetect' => array ( 'id' => 5 , 'argc' => 0 , 'type' => IMG_FILTER_EDGEDETECT ),
'emboss' => array ( 'id' => 6 , 'argc' => 0 , 'type' => IMG_FILTER_EMBOSS ),
'gaussian_blur' => array ( 'id' => 7 , 'argc' => 0 , 'type' => IMG_FILTER_GAUSSIAN_BLUR ),
'selective_blur' => array ( 'id' => 8 , 'argc' => 0 , 'type' => IMG_FILTER_SELECTIVE_BLUR ),
'mean_removal' => array ( 'id' => 9 , 'argc' => 0 , 'type' => IMG_FILTER_MEAN_REMOVAL ),
'smooth' => array ( 'id' => 10 , 'argc' => 1 , 'type' => IMG_FILTER_SMOOTH ),
'pixelate' => array ( 'id' => 11 , 'argc' => 2 , 'type' => IMG_FILTER_PIXELATE ),
);
2014-08-31 23:57:34 +02:00
if ( isset ( $map [ $name ])) {
2014-02-12 14:45:25 +01:00
return $map [ $name ];
2014-08-31 23:57:34 +02:00
} else {
2014-02-12 14:45:25 +01:00
throw new Exception ( 'No such filter.' );
2013-10-07 23:50:53 +02:00
}
}
2015-01-10 20:17:12 +01:00
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
2014-08-31 23:57:34 +02:00
* Load image details from original image file .
2014-02-12 14:45:25 +01:00
*
2014-12-13 00:12:39 +01:00
* @ param string $file the file to load or null to use $this -> pathToImage .
*
2014-02-12 14:45:25 +01:00
* @ return $this
* @ throws Exception
*/
2014-12-13 00:12:39 +01:00
public function loadImageDetails ( $file = null )
2014-02-12 14:45:25 +01:00
{
2014-12-13 00:12:39 +01:00
$file = $file ? $file : $this -> pathToImage ;
is_readable ( $file )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Image file does not exist.' );
// Get details on image
2015-03-06 13:00:21 +01:00
$info = list ( $this -> width , $this -> height , $this -> fileType , $this -> attr ) = getimagesize ( $file );
if ( empty ( $info )) {
throw new Exception ( " The file doesn't seem to be a valid image. " );
2015-07-23 11:32:19 +02:00
}
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
2015-03-06 13:00:21 +01:00
$this -> log ( " Loading image details for: { $file } " );
$this -> log ( " Image width x height (type): { $this -> width } x { $this -> height } ( { $this -> fileType } ). " );
$this -> log ( " Image filesize: " . filesize ( $file ) . " bytes. " );
$this -> log ( " Image mimetype: " . image_type_to_mime_type ( $this -> fileType ));
2014-02-12 14:45:25 +01:00
}
2014-08-31 23:57:34 +02:00
return $this ;
}
/**
2015-01-10 20:17:12 +01:00
* Init new width and height and do some sanity checks on constraints , before any
* processing can be done .
2014-08-31 23:57:34 +02:00
*
* @ return $this
* @ throws Exception
*/
public function initDimensions ()
{
2014-12-14 17:04:51 +01:00
$this -> log ( " Init dimension (before) newWidth x newHeight is { $this -> newWidth } x { $this -> newHeight } . " );
2014-02-12 14:45:25 +01:00
// width as %
if ( $this -> newWidth [ strlen ( $this -> newWidth ) - 1 ] == '%' ) {
$this -> newWidth = $this -> width * substr ( $this -> newWidth , 0 , - 1 ) / 100 ;
$this -> log ( " Setting new width based on % to { $this -> newWidth } " );
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// height as %
if ( $this -> newHeight [ strlen ( $this -> newHeight ) - 1 ] == '%' ) {
$this -> newHeight = $this -> height * substr ( $this -> newHeight , 0 , - 1 ) / 100 ;
$this -> log ( " Setting new height based on % to { $this -> newHeight } " );
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
is_null ( $this -> aspectRatio ) or is_numeric ( $this -> aspectRatio ) or $this -> raiseError ( 'Aspect ratio out of range' );
2013-10-14 09:22:21 +02:00
2014-02-12 14:45:25 +01:00
// width & height from aspect ratio
if ( $this -> aspectRatio && is_null ( $this -> newWidth ) && is_null ( $this -> newHeight )) {
if ( $this -> aspectRatio >= 1 ) {
$this -> newWidth = $this -> width ;
$this -> newHeight = $this -> width / $this -> aspectRatio ;
$this -> log ( " Setting new width & height based on width & aspect ratio (>=1) to (w x h) { $this -> newWidth } x { $this -> newHeight } " );
} else {
$this -> newHeight = $this -> height ;
$this -> newWidth = $this -> height * $this -> aspectRatio ;
$this -> log ( " Setting new width & height based on width & aspect ratio (<1) to (w x h) { $this -> newWidth } x { $this -> newHeight } " );
}
} elseif ( $this -> aspectRatio && is_null ( $this -> newWidth )) {
$this -> newWidth = $this -> newHeight * $this -> aspectRatio ;
$this -> log ( " Setting new width based on aspect ratio to { $this -> newWidth } " );
} elseif ( $this -> aspectRatio && is_null ( $this -> newHeight )) {
$this -> newHeight = $this -> newWidth / $this -> aspectRatio ;
$this -> log ( " Setting new height based on aspect ratio to { $this -> newHeight } " );
}
2014-11-24 09:27:47 +01:00
// Change width & height based on dpr
2014-11-24 07:41:32 +01:00
if ( $this -> dpr != 1 ) {
2014-11-21 23:44:19 +01:00
if ( ! is_null ( $this -> newWidth )) {
2014-11-24 07:41:32 +01:00
$this -> newWidth = round ( $this -> newWidth * $this -> dpr );
$this -> log ( " Setting new width based on dpr= { $this -> dpr } - w= { $this -> newWidth } " );
2014-11-21 23:44:19 +01:00
}
if ( ! is_null ( $this -> newHeight )) {
2014-11-24 07:41:32 +01:00
$this -> newHeight = round ( $this -> newHeight * $this -> dpr );
$this -> log ( " Setting new height based on dpr= { $this -> dpr } - h= { $this -> newHeight } " );
2014-11-21 23:44:19 +01:00
}
}
2014-02-12 14:45:25 +01:00
// Check values to be within domain
2014-08-31 23:57:34 +02:00
is_null ( $this -> newWidth )
or is_numeric ( $this -> newWidth )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Width not numeric' );
2014-08-31 23:57:34 +02:00
is_null ( $this -> newHeight )
or is_numeric ( $this -> newHeight )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Height not numeric' );
2013-10-03 18:16:33 +02:00
2014-12-14 17:04:51 +01:00
$this -> log ( " Init dimension (after) newWidth x newHeight is { $this -> newWidth } x { $this -> newHeight } . " );
2014-02-12 14:45:25 +01:00
return $this ;
2012-04-25 15:49:09 +02:00
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Calculate new width and height of image , based on settings .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function calculateNewWidthAndHeight ()
2014-02-12 14:45:25 +01:00
{
// Crop, use cropped width and height as base for calulations
$this -> log ( " Calculate new width and height. " );
$this -> log ( " Original width x height is { $this -> width } x { $this -> height } . " );
2014-12-14 17:04:51 +01:00
$this -> log ( " Target dimension (before calculating) newWidth x newHeight is { $this -> newWidth } x { $this -> newHeight } . " );
2014-02-12 14:45:25 +01:00
2014-12-14 17:04:51 +01:00
// Check if there is an area to crop off
2014-02-12 14:45:25 +01:00
if ( isset ( $this -> area )) {
$this -> offset [ 'top' ] = round ( $this -> area [ 'top' ] / 100 * $this -> height );
$this -> offset [ 'right' ] = round ( $this -> area [ 'right' ] / 100 * $this -> width );
$this -> offset [ 'bottom' ] = round ( $this -> area [ 'bottom' ] / 100 * $this -> height );
$this -> offset [ 'left' ] = round ( $this -> area [ 'left' ] / 100 * $this -> width );
$this -> offset [ 'width' ] = $this -> width - $this -> offset [ 'left' ] - $this -> offset [ 'right' ];
$this -> offset [ 'height' ] = $this -> height - $this -> offset [ 'top' ] - $this -> offset [ 'bottom' ];
$this -> width = $this -> offset [ 'width' ];
$this -> height = $this -> offset [ 'height' ];
$this -> log ( " The offset for the area to use is top { $this -> area [ 'top' ] } %, right { $this -> area [ 'right' ] } %, bottom { $this -> area [ 'bottom' ] } %, left { $this -> area [ 'left' ] } %. " );
$this -> log ( " The offset for the area to use is top { $this -> offset [ 'top' ] } px, right { $this -> offset [ 'right' ] } px, bottom { $this -> offset [ 'bottom' ] } px, left { $this -> offset [ 'left' ] } px, width { $this -> offset [ 'width' ] } px, height { $this -> offset [ 'height' ] } px. " );
}
$width = $this -> width ;
$height = $this -> height ;
2014-12-14 17:04:51 +01:00
// Check if crop is set
2014-02-12 14:45:25 +01:00
if ( $this -> crop ) {
$width = $this -> crop [ 'width' ] = $this -> crop [ 'width' ] <= 0 ? $this -> width + $this -> crop [ 'width' ] : $this -> crop [ 'width' ];
$height = $this -> crop [ 'height' ] = $this -> crop [ 'height' ] <= 0 ? $this -> height + $this -> crop [ 'height' ] : $this -> crop [ 'height' ];
if ( $this -> crop [ 'start_x' ] == 'left' ) {
$this -> crop [ 'start_x' ] = 0 ;
} elseif ( $this -> crop [ 'start_x' ] == 'right' ) {
$this -> crop [ 'start_x' ] = $this -> width - $width ;
} elseif ( $this -> crop [ 'start_x' ] == 'center' ) {
$this -> crop [ 'start_x' ] = round ( $this -> width / 2 ) - round ( $width / 2 );
2014-08-31 23:57:34 +02:00
}
2014-02-12 14:45:25 +01:00
if ( $this -> crop [ 'start_y' ] == 'top' ) {
$this -> crop [ 'start_y' ] = 0 ;
} elseif ( $this -> crop [ 'start_y' ] == 'bottom' ) {
$this -> crop [ 'start_y' ] = $this -> height - $height ;
} elseif ( $this -> crop [ 'start_y' ] == 'center' ) {
$this -> crop [ 'start_y' ] = round ( $this -> height / 2 ) - round ( $height / 2 );
2014-08-31 23:57:34 +02:00
}
2014-02-12 14:45:25 +01:00
$this -> log ( " Crop area is width { $width } px, height { $height } px, start_x { $this -> crop [ 'start_x' ] } px, start_y { $this -> crop [ 'start_y' ] } px. " );
}
2013-10-03 18:16:33 +02:00
2014-08-31 23:57:34 +02:00
// Calculate new width and height if keeping aspect-ratio.
2014-02-12 14:45:25 +01:00
if ( $this -> keepRatio ) {
2014-08-31 23:57:34 +02:00
$this -> log ( " Keep aspect ratio. " );
2014-02-12 14:45:25 +01:00
// Crop-to-fit and both new width and height are set.
2014-12-14 17:04:51 +01:00
if (( $this -> cropToFit || $this -> fillToFit ) && isset ( $this -> newWidth ) && isset ( $this -> newHeight )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Use newWidth and newHeigh as width/height, image should fit in box.
2014-08-31 23:57:34 +02:00
$this -> log ( " Use newWidth and newHeigh as width/height, image should fit in box. " );
2014-02-12 14:45:25 +01:00
} elseif ( isset ( $this -> newWidth ) && isset ( $this -> newHeight )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Both new width and height are set.
// Use newWidth and newHeigh as max width/height, image should not be larger.
$ratioWidth = $width / $this -> newWidth ;
$ratioHeight = $height / $this -> newHeight ;
$ratio = ( $ratioWidth > $ratioHeight ) ? $ratioWidth : $ratioHeight ;
$this -> newWidth = round ( $width / $ratio );
$this -> newHeight = round ( $height / $ratio );
2014-08-31 23:57:34 +02:00
$this -> log ( " New width and height was set. " );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
} elseif ( isset ( $this -> newWidth )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Use new width as max-width
$factor = ( float ) $this -> newWidth / ( float ) $width ;
$this -> newHeight = round ( $factor * $height );
2014-08-31 23:57:34 +02:00
$this -> log ( " New width was set. " );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
} elseif ( isset ( $this -> newHeight )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Use new height as max-hight
$factor = ( float ) $this -> newHeight / ( float ) $height ;
$this -> newWidth = round ( $factor * $width );
2014-08-31 23:57:34 +02:00
$this -> log ( " New height was set. " );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
}
2015-01-10 20:17:12 +01:00
2014-12-14 17:04:51 +01:00
// Get image dimensions for pre-resize image.
if ( $this -> cropToFit || $this -> fillToFit ) {
// Get relations of original & target image
2014-02-12 14:45:25 +01:00
$ratioWidth = $width / $this -> newWidth ;
$ratioHeight = $height / $this -> newHeight ;
2014-12-14 17:04:51 +01:00
if ( $this -> cropToFit ) {
2015-01-10 20:17:12 +01:00
2014-12-14 17:04:51 +01:00
// Use newWidth and newHeigh as defined width/height,
// image should fit the area.
$this -> log ( " Crop to fit. " );
$ratio = ( $ratioWidth < $ratioHeight ) ? $ratioWidth : $ratioHeight ;
$this -> cropWidth = round ( $width / $ratio );
$this -> cropHeight = round ( $height / $ratio );
$this -> log ( " Crop width, height, ratio: $this->cropWidth x $this->cropHeight ( $ratio ). " );
2015-01-10 20:17:12 +01:00
2015-07-23 11:32:19 +02:00
} elseif ( $this -> fillToFit ) {
2015-01-10 20:17:12 +01:00
2014-12-14 17:04:51 +01:00
// Use newWidth and newHeigh as defined width/height,
// image should fit the area.
$this -> log ( " Fill to fit. " );
$ratio = ( $ratioWidth < $ratioHeight ) ? $ratioHeight : $ratioWidth ;
$this -> fillWidth = round ( $width / $ratio );
$this -> fillHeight = round ( $height / $ratio );
$this -> log ( " Fill width, height, ratio: $this->fillWidth x $this->fillHeight ( $ratio ). " );
}
2014-08-31 23:57:34 +02:00
}
2014-02-12 14:45:25 +01:00
}
// Crop, ensure to set new width and height
if ( $this -> crop ) {
2014-08-31 23:57:34 +02:00
$this -> log ( " Crop. " );
2014-02-12 14:45:25 +01:00
$this -> newWidth = round ( isset ( $this -> newWidth ) ? $this -> newWidth : $this -> crop [ 'width' ]);
2014-08-31 23:57:34 +02:00
$this -> newHeight = round ( isset ( $this -> newHeight ) ? $this -> newHeight : $this -> crop [ 'height' ]);
2014-02-12 14:45:25 +01:00
}
2014-12-14 17:04:51 +01:00
// Fill to fit, ensure to set new width and height
/* if ( $this -> fillToFit ) {
$this -> log ( " FillToFit. " );
$this -> newWidth = round ( isset ( $this -> newWidth ) ? $this -> newWidth : $this -> crop [ 'width' ]);
$this -> newHeight = round ( isset ( $this -> newHeight ) ? $this -> newHeight : $this -> crop [ 'height' ]);
} */
2014-02-12 14:45:25 +01:00
// No new height or width is set, use existing measures.
$this -> newWidth = round ( isset ( $this -> newWidth ) ? $this -> newWidth : $this -> width );
2014-08-31 23:57:34 +02:00
$this -> newHeight = round ( isset ( $this -> newHeight ) ? $this -> newHeight : $this -> height );
2014-02-12 14:45:25 +01:00
$this -> log ( " Calculated new width x height as { $this -> newWidth } x { $this -> newHeight } . " );
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-08-31 23:57:34 +02:00
/**
* Re - calculate image dimensions when original image dimension has changed .
*
2015-01-10 20:17:12 +01:00
* @ return $this
2014-08-31 23:57:34 +02:00
*/
public function reCalculateDimensions ()
{
$this -> log ( " Re-calculate image dimensions, newWidth x newHeigh was: " . $this -> newWidth . " x " . $this -> newHeight );
$this -> newWidth = $this -> newWidthOrig ;
$this -> newHeight = $this -> newHeightOrig ;
2014-09-01 00:38:26 +02:00
$this -> crop = $this -> cropOrig ;
2014-08-31 23:57:34 +02:00
$this -> initDimensions ()
-> calculateNewWidthAndHeight ();
return $this ;
}
2014-02-12 14:45:25 +01:00
/**
* Set extension for filename to save as .
*
* @ param string $saveas extension to save image as
*
2015-01-10 20:17:12 +01:00
* @ return $this
2014-02-12 14:45:25 +01:00
*/
2014-08-31 23:57:34 +02:00
public function setSaveAsExtension ( $saveAs = null )
2014-02-12 14:45:25 +01:00
{
if ( isset ( $saveAs )) {
2014-11-21 21:01:22 +01:00
$saveAs = strtolower ( $saveAs );
2014-02-12 14:45:25 +01:00
$this -> checkFileExtension ( $saveAs );
$this -> saveAs = $saveAs ;
$this -> extension = $saveAs ;
}
2015-03-06 13:00:21 +01:00
$this -> log ( " Prepare to save image as: " . $this -> extension );
2014-02-12 14:45:25 +01:00
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Set JPEG quality to use when saving image
*
* @ param int $quality as the quality to set .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return $this
*/
public function setJpegQuality ( $quality = null )
{
2014-12-13 00:12:39 +01:00
if ( $quality ) {
$this -> useQuality = true ;
}
2014-02-12 14:45:25 +01:00
$this -> quality = isset ( $quality )
? $quality
: self :: JPEG_QUALITY_DEFAULT ;
2014-08-31 23:57:34 +02:00
( is_numeric ( $this -> quality ) and $this -> quality > 0 and $this -> quality <= 100 )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Quality not in range.' );
$this -> log ( " Setting JPEG quality to { $this -> quality } . " );
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Set PNG compressen algorithm to use when saving image
*
* @ param int $compress as the algorithm to use .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return $this
*/
public function setPngCompression ( $compress = null )
{
2014-12-13 00:12:39 +01:00
if ( $compress ) {
$this -> useCompress = true ;
}
2014-02-12 14:45:25 +01:00
$this -> compress = isset ( $compress )
? $compress
: self :: PNG_COMPRESSION_DEFAULT ;
2014-08-31 23:57:34 +02:00
( is_numeric ( $this -> compress ) and $this -> compress >= - 1 and $this -> compress <= 9 )
2014-02-12 14:45:25 +01:00
or $this -> raiseError ( 'Quality not in range.' );
$this -> log ( " Setting PNG compression level to { $this -> compress } . " );
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
2014-08-06 19:02:55 -04:00
* Use original image if possible , check options which affects image processing .
2014-02-12 14:45:25 +01:00
*
* @ param boolean $useOrig default is to use original if possible , else set to false .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function useOriginalIfPossible ( $useOrig = true )
2014-02-12 14:45:25 +01:00
{
2014-08-31 23:57:34 +02:00
if ( $useOrig
&& ( $this -> newWidth == $this -> width )
&& ( $this -> newHeight == $this -> height )
&& ! $this -> area
&& ! $this -> crop
2014-12-03 15:23:50 +01:00
&& ! $this -> cropToFit
&& ! $this -> fillToFit
2014-08-31 23:57:34 +02:00
&& ! $this -> filters
&& ! $this -> sharpen
&& ! $this -> emboss
&& ! $this -> blur
2014-11-24 09:27:47 +01:00
&& ! $this -> convolve
2014-02-12 14:45:25 +01:00
&& ! $this -> palette
2014-12-13 00:12:39 +01:00
&& ! $this -> useQuality
&& ! $this -> useCompress
2014-08-31 23:57:34 +02:00
&& ! $this -> saveAs
&& ! $this -> rotateBefore
&& ! $this -> rotateAfter
&& ! $this -> autoRotate
&& ! $this -> bgColor
2014-12-15 15:41:51 +01:00
&& ( $this -> upscale === self :: UPSCALE_DEFAULT )
2014-02-12 14:45:25 +01:00
) {
$this -> log ( " Using original image. " );
$this -> output ( $this -> pathToImage );
2013-10-03 18:16:33 +02:00
}
2014-12-13 00:12:39 +01:00
2014-02-12 14:45:25 +01:00
return $this ;
2013-10-03 18:16:33 +02:00
}
2015-01-10 20:17:12 +01:00
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Generate filename to save file in cache .
*
2015-09-17 11:22:50 +02:00
* @ param string $base as optional basepath for storing file .
* @ param boolean $useSubdir use or skip the subdir part when creating the
* filename .
2015-10-24 16:42:59 +02:00
* @ param string $prefix to add as part of filename
2014-02-12 14:45:25 +01:00
*
* @ return $this
*/
2015-10-24 16:42:59 +02:00
public function generateFilename ( $base = null , $useSubdir = true , $prefix = null )
2014-02-12 14:45:25 +01:00
{
2015-09-17 11:22:50 +02:00
$filename = basename ( $this -> pathToImage );
2014-08-31 23:57:34 +02:00
$cropToFit = $this -> cropToFit ? '_cf' : null ;
2014-12-03 15:23:50 +01:00
$fillToFit = $this -> fillToFit ? '_ff' : null ;
2014-08-31 23:57:34 +02:00
$crop_x = $this -> crop_x ? " _x { $this -> crop_x } " : null ;
$crop_y = $this -> crop_y ? " _y { $this -> crop_y } " : null ;
$scale = $this -> scale ? " _s { $this -> scale } " : null ;
$bgColor = $this -> bgColor ? " _bgc { $this -> bgColor } " : null ;
$quality = $this -> quality ? " _q { $this -> quality } " : null ;
$compress = $this -> compress ? " _co { $this -> compress } " : null ;
$rotateBefore = $this -> rotateBefore ? " _rb { $this -> rotateBefore } " : null ;
$rotateAfter = $this -> rotateAfter ? " _ra { $this -> rotateAfter } " : null ;
2015-10-20 10:26:09 +02:00
$saveAs = $this -> normalizeFileExtension ();
$saveAs = $saveAs ? " _ $saveAs " : null ;
2015-10-20 13:46:01 +02:00
$copyStrat = null ;
if ( $this -> copyStrategy === self :: RESIZE ) {
$copyStrat = " _rs " ;
}
2015-12-06 12:26:20 +01:00
2015-10-23 14:19:46 +02:00
$width = $this -> newWidth ? '_' . $this -> newWidth : null ;
$height = $this -> newHeight ? '_' . $this -> newHeight : null ;
2014-12-03 15:23:50 +01:00
2014-08-31 23:57:34 +02:00
$offset = isset ( $this -> offset )
? '_o' . $this -> offset [ 'top' ] . '-' . $this -> offset [ 'right' ] . '-' . $this -> offset [ 'bottom' ] . '-' . $this -> offset [ 'left' ]
2014-02-12 14:45:25 +01:00
: null ;
2014-08-31 23:57:34 +02:00
$crop = $this -> crop
2014-02-12 14:45:25 +01:00
? '_c' . $this -> crop [ 'width' ] . '-' . $this -> crop [ 'height' ] . '-' . $this -> crop [ 'start_x' ] . '-' . $this -> crop [ 'start_y' ]
: null ;
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
$filters = null ;
if ( isset ( $this -> filters )) {
foreach ( $this -> filters as $filter ) {
if ( is_array ( $filter )) {
$filters .= " _f { $filter [ 'id' ] } " ;
2014-08-31 23:57:34 +02:00
for ( $i = 1 ; $i <= $filter [ 'argc' ]; $i ++ ) {
2015-09-15 17:23:22 +02:00
$filters .= " - " . $filter [ " arg { $i } " ];
2014-02-12 14:45:25 +01:00
}
}
}
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
$sharpen = $this -> sharpen ? 's' : null ;
$emboss = $this -> emboss ? 'e' : null ;
$blur = $this -> blur ? 'b' : null ;
$palette = $this -> palette ? 'p' : null ;
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
$autoRotate = $this -> autoRotate ? 'ar' : null ;
2014-02-12 14:45:25 +01:00
2015-03-06 13:00:21 +01:00
$optimize = $this -> jpegOptimize ? 'o' : null ;
$optimize .= $this -> pngFilter ? 'f' : null ;
$optimize .= $this -> pngDeflate ? 'd' : null ;
2013-10-03 18:16:33 +02:00
2014-11-24 09:27:47 +01:00
$convolve = null ;
if ( $this -> convolve ) {
2014-12-15 17:14:06 +01:00
$convolve = '_conv' . preg_replace ( '/[^a-zA-Z0-9]/' , '' , $this -> convolve );
2014-11-24 09:27:47 +01:00
}
2014-12-15 15:41:51 +01:00
$upscale = null ;
if ( $this -> upscale !== self :: UPSCALE_DEFAULT ) {
2014-12-15 17:14:06 +01:00
$upscale = '_nu' ;
2014-12-15 15:41:51 +01:00
}
2015-09-17 11:22:50 +02:00
$subdir = null ;
if ( $useSubdir === true ) {
$subdir = str_replace ( '/' , '-' , dirname ( $this -> imageSrc ));
$subdir = ( $subdir == '.' ) ? '_.' : $subdir ;
$subdir .= '_' ;
}
2015-12-06 12:26:20 +01:00
$file = $prefix . $subdir . $filename . $width . $height
2015-10-23 14:19:46 +02:00
. $offset . $crop . $cropToFit . $fillToFit
2014-12-15 15:41:51 +01:00
. $crop_x . $crop_y . $upscale
2015-09-16 09:51:04 +02:00
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
2015-10-20 13:46:01 +02:00
. $convolve . $copyStrat . $saveAs ;
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
return $this -> setTarget ( $file , $base );
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Use cached version of image , if possible .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ param boolean $useCache is default true , set to false to avoid using cached object .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function useCacheIfPossible ( $useCache = true )
2014-02-12 14:45:25 +01:00
{
if ( $useCache && is_readable ( $this -> cacheFileName )) {
$fileTime = filemtime ( $this -> pathToImage );
$cacheTime = filemtime ( $this -> cacheFileName );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
if ( $fileTime <= $cacheTime ) {
if ( $this -> useCache ) {
if ( $this -> verbose ) {
$this -> log ( " Use cached file. " );
2014-08-31 23:57:34 +02:00
$this -> log ( " Cached image filesize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
2014-02-12 14:45:25 +01:00
}
2014-11-21 22:20:30 +01:00
$this -> output ( $this -> cacheFileName , $this -> outputFormat );
2014-02-12 14:45:25 +01:00
} else {
$this -> log ( " Cache is valid but ignoring it by intention. " );
}
} else {
$this -> log ( " Original file is modified, ignoring cache. " );
}
} else {
$this -> log ( " Cachefile does not exists or ignoring it. " );
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
return $this ;
2012-10-02 22:49:43 +02:00
}
2014-02-12 14:45:25 +01:00
2015-01-10 20:17:12 +01:00
2014-08-21 02:21:32 +02:00
/**
2015-07-23 11:32:19 +02:00
* Load image from disk . Try to load image without verbose error message ,
2015-03-06 13:00:21 +01:00
* if fail , load again and display error messages .
2014-02-12 14:45:25 +01:00
*
* @ param string $src of image .
* @ param string $dir as base directory where images are .
*
* @ return $this
*
*/
2014-08-21 02:21:32 +02:00
public function load ( $src = null , $dir = null )
2014-02-12 14:45:25 +01:00
{
if ( isset ( $src )) {
$this -> setSource ( $src , $dir );
}
2015-03-06 13:00:21 +01:00
$this -> loadImageDetails ( $this -> pathToImage );
2015-01-10 20:17:12 +01:00
2015-03-06 13:00:21 +01:00
$this -> image = imagecreatefromstring ( file_get_contents ( $this -> pathToImage ));
if ( $this -> image === false ) {
throw new Exception ( " Could not load image. " );
}
2015-12-06 12:26:20 +01:00
2015-10-21 00:05:14 +02:00
/* Removed v0 . 7.7
2015-03-06 13:00:21 +01:00
if ( image_type_to_mime_type ( $this -> fileType ) == 'image/png' ) {
$type = $this -> getPngType ();
$hasFewColors = imagecolorstotal ( $this -> image );
2015-01-10 20:17:12 +01:00
2015-03-06 13:00:21 +01:00
if ( $type == self :: PNG_RGB_PALETTE || ( $hasFewColors > 0 && $hasFewColors <= 256 )) {
if ( $this -> verbose ) {
$this -> log ( " Handle this image as a palette image. " );
2014-02-12 14:45:25 +01:00
}
2015-03-06 13:00:21 +01:00
$this -> palette = true ;
}
2014-02-12 14:45:25 +01:00
}
2015-10-21 00:05:14 +02:00
*/
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
2015-10-20 13:46:01 +02:00
$this -> log ( " ### Image successfully loaded from file. " );
2015-03-06 13:00:21 +01:00
$this -> log ( " imageistruecolor() : " . ( imageistruecolor ( $this -> image ) ? 'true' : 'false' ));
$this -> log ( " imagecolorstotal() : " . imagecolorstotal ( $this -> image ));
$this -> log ( " Number of colors in image = " . $this -> colorsTotal ( $this -> image ));
2015-02-09 00:40:55 +01:00
$index = imagecolortransparent ( $this -> image );
2015-10-20 13:46:01 +02:00
$this -> log ( " Detected transparent color = " . ( $index >= 0 ? implode ( " , " , imagecolorsforindex ( $this -> image , $index )) : " NONE " ) . " at index = $index " );
2014-02-12 14:45:25 +01:00
}
return $this ;
2012-10-02 22:49:43 +02:00
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Get the type of PNG image .
*
2015-10-20 10:04:37 +02:00
* @ param string $filename to use instead of default .
*
2014-02-12 14:45:25 +01:00
* @ return int as the type of the png - image
*
*/
2015-10-20 10:04:37 +02:00
public function getPngType ( $filename = null )
2014-02-12 14:45:25 +01:00
{
2015-10-20 10:04:37 +02:00
$filename = $filename ? $filename : $this -> pathToImage ;
2015-12-06 12:26:20 +01:00
2015-10-20 10:04:37 +02:00
$pngType = ord ( file_get_contents ( $filename , false , null , 25 , 1 ));
if ( $this -> verbose ) {
$this -> log ( " Checking png type of: " . $filename );
$this -> log ( $this -> getPngTypeAsString ( $pngType ));
}
2015-12-06 12:26:20 +01:00
2015-10-20 10:04:37 +02:00
return $pngType ;
}
/**
* Get the type of PNG image as a verbose string .
*
* @ param integer $type to use , default is to check the type .
* @ param string $filename to use instead of default .
*
* @ return int as the type of the png - image
*
*/
private function getPngTypeAsString ( $pngType = null , $filename = null )
{
if ( $filename || ! $pngType ) {
$pngType = $this -> getPngType ( $filename );
}
2014-02-12 14:45:25 +01:00
2015-10-20 13:46:01 +02:00
$index = imagecolortransparent ( $this -> image );
$transparent = null ;
if ( $index != - 1 ) {
2015-12-06 12:26:20 +01:00
$transparent = " (transparent) " ;
2015-10-20 13:46:01 +02:00
}
2014-02-12 14:45:25 +01:00
switch ( $pngType ) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
case self :: PNG_GREYSCALE :
2015-10-20 13:46:01 +02:00
$text = " PNG is type 0, Greyscale $transparent " ;
2014-02-12 14:45:25 +01:00
break ;
2014-08-31 23:57:34 +02:00
case self :: PNG_RGB :
2015-10-20 13:46:01 +02:00
$text = " PNG is type 2, RGB $transparent " ;
2014-02-12 14:45:25 +01:00
break ;
2014-08-31 23:57:34 +02:00
case self :: PNG_RGB_PALETTE :
2015-10-20 13:46:01 +02:00
$text = " PNG is type 3, RGB with palette $transparent " ;
2014-02-12 14:45:25 +01:00
break ;
case self :: PNG_GREYSCALE_ALPHA :
2015-10-20 10:04:37 +02:00
$text = " PNG is type 4, Greyscale with alpha channel " ;
2014-02-12 14:45:25 +01:00
break ;
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
case self :: PNG_RGB_ALPHA :
2015-10-20 10:04:37 +02:00
$text = " PNG is type 6, RGB with alpha channel (PNG 32-bit) " ;
2014-02-12 14:45:25 +01:00
break ;
default :
2015-10-20 10:04:37 +02:00
$text = " PNG is UNKNOWN type, is it really a PNG image? " ;
2014-02-12 14:45:25 +01:00
}
2015-10-20 10:04:37 +02:00
return $text ;
2014-02-12 14:45:25 +01:00
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
2015-10-20 10:04:37 +02:00
2015-01-10 20:17:12 +01:00
/**
2014-02-12 14:45:25 +01:00
* Calculate number of colors in an image .
*
* @ param resource $im the image .
*
2015-01-10 20:17:12 +01:00
* @ return int
2014-02-12 14:45:25 +01:00
*/
2014-08-31 23:57:34 +02:00
private function colorsTotal ( $im )
2014-02-12 14:45:25 +01:00
{
if ( imageistruecolor ( $im )) {
2014-12-15 09:19:23 +01:00
$this -> log ( " Colors as true color. " );
2014-02-12 14:45:25 +01:00
$h = imagesy ( $im );
$w = imagesx ( $im );
$c = array ();
for ( $x = 0 ; $x < $w ; $x ++ ) {
for ( $y = 0 ; $y < $h ; $y ++ ) {
@ $c [ 'c' . imagecolorat ( $im , $x , $y )] ++ ;
}
}
return count ( $c );
} else {
2014-12-15 09:19:23 +01:00
$this -> log ( " Colors as palette. " );
2014-02-12 14:45:25 +01:00
return imagecolorstotal ( $im );
}
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Preprocess image before rezising it .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function preResize ()
2014-02-12 14:45:25 +01:00
{
2015-10-20 13:46:01 +02:00
$this -> log ( " ### Pre-process before resizing " );
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
// Rotate image
if ( $this -> rotateBefore ) {
$this -> log ( " Rotating image. " );
$this -> rotate ( $this -> rotateBefore , $this -> bgColor )
-> reCalculateDimensions ();
}
// Auto-rotate image
if ( $this -> autoRotate ) {
$this -> log ( " Auto rotating image. " );
$this -> rotateExif ()
-> reCalculateDimensions ();
}
2014-02-12 14:45:25 +01:00
// Scale the original image before starting
if ( isset ( $this -> scale )) {
$this -> log ( " Scale by { $this -> scale } % " );
$newWidth = $this -> width * $this -> scale / 100 ;
$newHeight = $this -> height * $this -> scale / 100 ;
$img = $this -> CreateImageKeepTransparency ( $newWidth , $newHeight );
imagecopyresampled ( $img , $this -> image , 0 , 0 , 0 , 0 , $newWidth , $newHeight , $this -> width , $this -> height );
$this -> image = $img ;
$this -> width = $newWidth ;
$this -> height = $newHeight ;
2014-08-31 23:57:34 +02:00
}
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
2015-10-20 13:46:01 +02:00
/**
* Resize or resample the image while resizing .
*
* @ param int $strategy as CImage :: RESIZE or CImage :: RESAMPLE
*
* @ return $this
*/
2015-12-07 16:01:47 +01:00
public function setCopyResizeStrategy ( $strategy )
{
$this -> copyStrategy = $strategy ;
return $this ;
}
2015-10-20 13:46:01 +02:00
/**
* Resize and or crop the image .
*
* @ return void
*/
public function imageCopyResampled ( $dst_image , $src_image , $dst_x , $dst_y , $src_x , $src_y , $dst_w , $dst_h , $src_w , $src_h )
{
2015-12-07 16:01:47 +01:00
if ( $this -> copyStrategy == self :: RESIZE ) {
2015-10-20 13:46:01 +02:00
$this -> log ( " Copy by resize " );
imagecopyresized ( $dst_image , $src_image , $dst_x , $dst_y , $src_x , $src_y , $dst_w , $dst_h , $src_w , $src_h );
} else {
$this -> log ( " Copy by resample " );
imagecopyresampled ( $dst_image , $src_image , $dst_x , $dst_y , $src_x , $src_y , $dst_w , $dst_h , $src_w , $src_h );
}
}
2014-02-12 14:45:25 +01:00
/**
* Resize and or crop the image .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function resize ()
2014-02-12 14:45:25 +01:00
{
2015-10-20 13:46:01 +02:00
$this -> log ( " ### Starting to Resize() " );
2014-12-15 15:41:51 +01:00
$this -> log ( " Upscale = ' $this->upscale ' " );
2014-02-12 14:45:25 +01:00
// Only use a specified area of the image, $this->offset is defining the area to use
if ( isset ( $this -> offset )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
$this -> log ( " Offset for area to use, cropping it width= { $this -> offset [ 'width' ] } , height= { $this -> offset [ 'height' ] } , start_x= { $this -> offset [ 'left' ] } , start_y= { $this -> offset [ 'top' ] } " );
$img = $this -> CreateImageKeepTransparency ( $this -> offset [ 'width' ], $this -> offset [ 'height' ]);
imagecopy ( $img , $this -> image , 0 , 0 , $this -> offset [ 'left' ], $this -> offset [ 'top' ], $this -> offset [ 'width' ], $this -> offset [ 'height' ]);
$this -> image = $img ;
$this -> width = $this -> offset [ 'width' ];
$this -> height = $this -> offset [ 'height' ];
2014-08-31 23:57:34 +02:00
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
if ( $this -> crop ) {
2013-10-03 18:16:33 +02:00
2014-12-03 15:23:50 +01:00
// Do as crop, take only part of image
2014-02-12 14:45:25 +01:00
$this -> log ( " Cropping area width= { $this -> crop [ 'width' ] } , height= { $this -> crop [ 'height' ] } , start_x= { $this -> crop [ 'start_x' ] } , start_y= { $this -> crop [ 'start_y' ] } " );
$img = $this -> CreateImageKeepTransparency ( $this -> crop [ 'width' ], $this -> crop [ 'height' ]);
2014-12-15 09:41:11 +01:00
imagecopy ( $img , $this -> image , 0 , 0 , $this -> crop [ 'start_x' ], $this -> crop [ 'start_y' ], $this -> crop [ 'width' ], $this -> crop [ 'height' ]);
2014-02-12 14:45:25 +01:00
$this -> image = $img ;
$this -> width = $this -> crop [ 'width' ];
$this -> height = $this -> crop [ 'height' ];
2014-08-31 23:57:34 +02:00
}
2014-12-15 17:45:21 +01:00
if ( ! $this -> upscale ) {
// Consider rewriting the no-upscale code to fit within this if-statement,
// likely to be more readable code.
// The code is more or leass equal in below crop-to-fit, fill-to-fit and stretch
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
if ( $this -> cropToFit ) {
2015-01-10 20:17:12 +01:00
2014-12-03 15:23:50 +01:00
// Resize by crop to fit
2014-12-15 15:41:51 +01:00
$this -> log ( " Resizing using strategy - Crop to fit " );
if ( ! $this -> upscale && ( $this -> width < $this -> newWidth || $this -> height < $this -> newHeight )) {
$this -> log ( " Resizing - smaller image, do not upscale. " );
2015-01-10 20:17:12 +01:00
2014-12-15 17:14:06 +01:00
$cropX = round (( $this -> cropWidth / 2 ) - ( $this -> newWidth / 2 ));
$cropY = round (( $this -> cropHeight / 2 ) - ( $this -> newHeight / 2 ));
$posX = 0 ;
$posY = 0 ;
if ( $this -> newWidth > $this -> width ) {
$posX = round (( $this -> newWidth - $this -> width ) / 2 );
}
2015-01-10 20:17:12 +01:00
2014-12-15 17:14:06 +01:00
if ( $this -> newHeight > $this -> height ) {
$posY = round (( $this -> newHeight - $this -> height ) / 2 );
}
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
imagecopy ( $imageResized , $this -> image , $posX , $posY , $cropX , $cropY , $this -> newWidth , $this -> newHeight );
2014-12-15 15:41:51 +01:00
} else {
$cropX = round (( $this -> cropWidth / 2 ) - ( $this -> newWidth / 2 ));
$cropY = round (( $this -> cropHeight / 2 ) - ( $this -> newHeight / 2 ));
$imgPreCrop = $this -> CreateImageKeepTransparency ( $this -> cropWidth , $this -> cropHeight );
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
2015-10-20 13:46:01 +02:00
$this -> imageCopyResampled ( $imgPreCrop , $this -> image , 0 , 0 , 0 , 0 , $this -> cropWidth , $this -> cropHeight , $this -> width , $this -> height );
2014-12-15 15:41:51 +01:00
imagecopy ( $imageResized , $imgPreCrop , 0 , 0 , $cropX , $cropY , $this -> newWidth , $this -> newHeight );
}
2014-12-15 17:14:06 +01:00
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
2015-01-10 20:17:12 +01:00
2015-07-23 11:32:19 +02:00
} elseif ( $this -> fillToFit ) {
2015-01-10 20:17:12 +01:00
2014-12-03 15:23:50 +01:00
// Resize by fill to fit
2014-12-15 15:41:51 +01:00
$this -> log ( " Resizing using strategy - Fill to fit " );
2014-12-03 15:23:50 +01:00
$posX = 0 ;
$posY = 0 ;
2014-12-14 17:04:51 +01:00
$ratioOrig = $this -> width / $this -> height ;
$ratioNew = $this -> newWidth / $this -> newHeight ;
// Check ratio for landscape or portrait
if ( $ratioOrig < $ratioNew ) {
$posX = round (( $this -> newWidth - $this -> fillWidth ) / 2 );
2014-12-03 15:23:50 +01:00
} else {
2014-12-14 17:04:51 +01:00
$posY = round (( $this -> newHeight - $this -> fillHeight ) / 2 );
2014-12-03 15:23:50 +01:00
}
2014-12-15 17:14:06 +01:00
if ( ! $this -> upscale
&& ( $this -> width < $this -> newWidth || $this -> height < $this -> newHeight )
) {
2015-01-10 20:17:12 +01:00
2014-12-15 15:41:51 +01:00
$this -> log ( " Resizing - smaller image, do not upscale. " );
$posX = round (( $this -> fillWidth - $this -> width ) / 2 );
$posY = round (( $this -> fillHeight - $this -> height ) / 2 );
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
imagecopy ( $imageResized , $this -> image , $posX , $posY , 0 , 0 , $this -> fillWidth , $this -> fillHeight );
2015-01-10 20:17:12 +01:00
2014-12-15 15:41:51 +01:00
} else {
$imgPreFill = $this -> CreateImageKeepTransparency ( $this -> fillWidth , $this -> fillHeight );
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
2015-10-20 13:46:01 +02:00
$this -> imageCopyResampled ( $imgPreFill , $this -> image , 0 , 0 , 0 , 0 , $this -> fillWidth , $this -> fillHeight , $this -> width , $this -> height );
2014-12-15 15:41:51 +01:00
imagecopy ( $imageResized , $imgPreFill , $posX , $posY , 0 , 0 , $this -> fillWidth , $this -> fillHeight );
}
2014-12-15 17:14:06 +01:00
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
2015-01-10 20:17:12 +01:00
2015-07-23 11:32:19 +02:00
} elseif ( ! ( $this -> newWidth == $this -> width && $this -> newHeight == $this -> height )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Resize it
$this -> log ( " Resizing, new height and/or width " );
2014-12-15 15:41:51 +01:00
2014-12-15 17:14:06 +01:00
if ( ! $this -> upscale
&& ( $this -> width < $this -> newWidth || $this -> height < $this -> newHeight )
) {
2014-12-15 15:41:51 +01:00
$this -> log ( " Resizing - smaller image, do not upscale. " );
2014-12-15 17:14:06 +01:00
if ( ! $this -> keepRatio ) {
$this -> log ( " Resizing - stretch to fit selected. " );
$posX = 0 ;
$posY = 0 ;
$cropX = 0 ;
$cropY = 0 ;
if ( $this -> newWidth > $this -> width && $this -> newHeight > $this -> height ) {
$posX = round (( $this -> newWidth - $this -> width ) / 2 );
$posY = round (( $this -> newHeight - $this -> height ) / 2 );
2015-07-23 11:32:19 +02:00
} elseif ( $this -> newWidth > $this -> width ) {
2014-12-15 17:14:06 +01:00
$posX = round (( $this -> newWidth - $this -> width ) / 2 );
$cropY = round (( $this -> height - $this -> newHeight ) / 2 );
2015-07-23 11:32:19 +02:00
} elseif ( $this -> newHeight > $this -> height ) {
2014-12-15 17:14:06 +01:00
$posY = round (( $this -> newHeight - $this -> height ) / 2 );
$cropX = round (( $this -> width - $this -> newWidth ) / 2 );
}
//$this->log("posX=$posX, posY=$posY, cropX=$cropX, cropY=$cropY.");
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
imagecopy ( $imageResized , $this -> image , $posX , $posY , $cropX , $cropY , $this -> newWidth , $this -> newHeight );
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
}
2014-12-15 15:41:51 +01:00
} else {
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
2015-10-20 13:46:01 +02:00
$this -> imageCopyResampled ( $imageResized , $this -> image , 0 , 0 , 0 , 0 , $this -> newWidth , $this -> newHeight , $this -> width , $this -> height );
2014-12-15 15:41:51 +01:00
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
}
2014-02-12 14:45:25 +01:00
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
return $this ;
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Postprocess image after rezising image .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function postResize ()
2014-02-12 14:45:25 +01:00
{
2015-10-20 13:46:01 +02:00
$this -> log ( " ### Post-process after resizing " );
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
// Rotate image
if ( $this -> rotateAfter ) {
$this -> log ( " Rotating image. " );
$this -> rotate ( $this -> rotateAfter , $this -> bgColor );
}
2014-02-12 14:45:25 +01:00
// Apply filters
if ( isset ( $this -> filters ) && is_array ( $this -> filters )) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
foreach ( $this -> filters as $filter ) {
2014-11-28 16:22:24 +01:00
$this -> log ( " Applying filter { $filter [ 'type' ] } . " );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
switch ( $filter [ 'argc' ]) {
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
case 0 :
imagefilter ( $this -> image , $filter [ 'type' ]);
2014-02-12 14:45:25 +01:00
break ;
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
case 1 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ]);
2014-02-12 14:45:25 +01:00
break ;
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
case 2 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ]);
2014-02-12 14:45:25 +01:00
break ;
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
case 3 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ], $filter [ 'arg3' ]);
2014-02-12 14:45:25 +01:00
break ;
2014-08-31 23:57:34 +02:00
case 4 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ], $filter [ 'arg3' ], $filter [ 'arg4' ]);
2014-02-12 14:45:25 +01:00
break ;
}
}
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Convert to palette image
2014-08-31 23:57:34 +02:00
if ( $this -> palette ) {
2014-02-12 14:45:25 +01:00
$this -> log ( " Converting to palette image. " );
$this -> trueColorToPalette ();
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Blur the image
2014-08-31 23:57:34 +02:00
if ( $this -> blur ) {
2014-02-12 14:45:25 +01:00
$this -> log ( " Blur. " );
$this -> blurImage ();
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Emboss the image
2014-08-31 23:57:34 +02:00
if ( $this -> emboss ) {
2014-02-12 14:45:25 +01:00
$this -> log ( " Emboss. " );
$this -> embossImage ();
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Sharpen the image
2014-08-31 23:57:34 +02:00
if ( $this -> sharpen ) {
2014-02-12 14:45:25 +01:00
$this -> log ( " Sharpen. " );
$this -> sharpenImage ();
2012-05-09 17:57:48 +02:00
}
2013-10-07 23:50:53 +02:00
2014-11-24 09:27:47 +01:00
// Custom convolution
if ( $this -> convolve ) {
2014-11-27 22:04:41 +01:00
//$this->log("Convolve: " . $this->convolve);
2014-11-24 09:27:47 +01:00
$this -> imageConvolution ();
}
2014-08-31 23:57:34 +02:00
return $this ;
}
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
/**
* Rotate image using angle .
2015-01-10 20:17:12 +01:00
*
2014-08-31 23:57:34 +02:00
* @ param float $angle to rotate image .
* @ param int $anglebgColor to fill image with if needed .
*
* @ return $this
*/
public function rotate ( $angle , $bgColor )
{
2014-12-03 15:23:50 +01:00
$this -> log ( " Rotate image " . $angle . " degrees with filler color. " );
2014-08-31 23:57:34 +02:00
2014-12-03 15:23:50 +01:00
$color = $this -> getBackgroundColor ();
$this -> image = imagerotate ( $this -> image , $angle , $color );
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
$this -> width = imagesx ( $this -> image );
$this -> height = imagesy ( $this -> image );
$this -> log ( " New image dimension width x height: " . $this -> width . " x " . $this -> height );
return $this ;
}
/**
* Rotate image using information in EXIF .
2015-01-10 20:17:12 +01:00
*
2014-08-31 23:57:34 +02:00
* @ return $this
*/
public function rotateExif ()
{
2015-03-06 13:00:21 +01:00
if ( ! in_array ( $this -> fileType , array ( IMAGETYPE_JPEG , IMAGETYPE_TIFF_II , IMAGETYPE_TIFF_MM ))) {
2014-08-31 23:57:34 +02:00
$this -> log ( " Autorotate ignored, EXIF not supported by this filetype. " );
return $this ;
}
$exif = exif_read_data ( $this -> pathToImage );
if ( ! empty ( $exif [ 'Orientation' ])) {
switch ( $exif [ 'Orientation' ]) {
case 3 :
$this -> log ( " Autorotate 180. " );
$this -> rotate ( 180 , $this -> bgColor );
break ;
case 6 :
$this -> log ( " Autorotate -90. " );
$this -> rotate ( - 90 , $this -> bgColor );
break ;
case 8 :
$this -> log ( " Autorotate 90. " );
$this -> rotate ( 90 , $this -> bgColor );
break ;
default :
$this -> log ( " Autorotate ignored, unknown value as orientation. " );
}
} else {
$this -> log ( " Autorotate ignored, no orientation in EXIF. " );
}
2015-01-10 20:17:12 +01:00
2014-08-31 23:57:34 +02:00
return $this ;
2012-05-09 17:57:48 +02:00
}
2012-04-25 15:49:09 +02:00
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Convert true color image to palette image , keeping alpha .
* http :// stackoverflow . com / questions / 5752514 / how - to - convert - png - to - 8 - bit - png - using - php - gd - library
*
* @ return void
*/
2014-08-31 23:57:34 +02:00
public function trueColorToPalette ()
2014-02-12 14:45:25 +01:00
{
$img = imagecreatetruecolor ( $this -> width , $this -> height );
$bga = imagecolorallocatealpha ( $img , 0 , 0 , 0 , 127 );
imagecolortransparent ( $img , $bga );
imagefill ( $img , 0 , 0 , $bga );
imagecopy ( $img , $this -> image , 0 , 0 , 0 , 0 , $this -> width , $this -> height );
imagetruecolortopalette ( $img , false , 255 );
imagesavealpha ( $img , true );
if ( imageistruecolor ( $this -> image )) {
$this -> log ( " Matching colors with true color image. " );
imagecolormatch ( $this -> image , $img );
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
$this -> image = $img ;
}
2013-10-03 18:16:33 +02:00
2012-10-02 22:49:43 +02:00
2014-02-12 14:45:25 +01:00
/**
2014-11-27 22:04:41 +01:00
* Sharpen image using image convolution .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function sharpenImage ()
2014-02-12 14:45:25 +01:00
{
2014-11-27 22:04:41 +01:00
$this -> imageConvolution ( 'sharpen' );
2014-02-12 14:45:25 +01:00
return $this ;
}
2012-10-02 22:49:43 +02:00
2013-10-07 23:50:53 +02:00
2014-02-12 14:45:25 +01:00
/**
2014-11-27 22:04:41 +01:00
* Emboss image using image convolution .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function embossImage ()
2014-02-12 14:45:25 +01:00
{
2014-11-27 22:04:41 +01:00
$this -> imageConvolution ( 'emboss' );
2014-02-12 14:45:25 +01:00
return $this ;
2013-10-03 18:16:33 +02:00
}
2012-10-02 22:49:43 +02:00
2014-02-12 14:45:25 +01:00
/**
2014-11-27 22:04:41 +01:00
* Blur image using image convolution .
2015-01-10 20:17:12 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function blurImage ()
2014-02-12 14:45:25 +01:00
{
2014-11-27 22:04:41 +01:00
$this -> imageConvolution ( 'blur' );
return $this ;
}
/**
* Create convolve expression and return arguments for image convolution .
2015-01-10 20:17:12 +01:00
*
2014-11-27 22:04:41 +01:00
* @ param string $expression constant string which evaluates to a list of
* 11 numbers separated by komma or such a list .
*
* @ return array as $matrix ( 3 x3 ), $divisor and $offset
*/
public function createConvolveArguments ( $expression )
{
// Check of matching constant
if ( isset ( $this -> convolves [ $expression ])) {
$expression = $this -> convolves [ $expression ];
}
$part = explode ( ',' , $expression );
$this -> log ( " Creating convolution expressen: $expression " );
// Expect list of 11 numbers, split by , and build up arguments
if ( count ( $part ) != 11 ) {
throw new Exception (
2015-01-10 20:17:12 +01:00
" Missmatch in argument convolve. Expected comma-separated string with
2014-11-27 22:04:41 +01:00
11 float values . Got $expression . "
);
}
2015-01-10 20:17:12 +01:00
2014-11-27 22:04:41 +01:00
array_walk ( $part , function ( $item , $key ) {
if ( ! is_numeric ( $item )) {
throw new Exception ( " Argument to convolve expression should be float but is not. " );
}
});
2015-01-10 20:17:12 +01:00
2014-11-27 22:04:41 +01:00
return array (
array (
array ( $part [ 0 ], $part [ 1 ], $part [ 2 ]),
array ( $part [ 3 ], $part [ 4 ], $part [ 5 ]),
array ( $part [ 6 ], $part [ 7 ], $part [ 8 ]),
),
$part [ 9 ],
$part [ 10 ],
2014-02-12 14:45:25 +01:00
);
2014-11-27 22:04:41 +01:00
}
/**
* Add custom expressions ( or overwrite existing ) for image convolution .
2015-01-10 20:17:12 +01:00
*
2014-11-27 22:04:41 +01:00
* @ param array $options Key value array with strings to be converted
* to convolution expressions .
*
* @ return $this
*/
public function addConvolveExpressions ( $options )
{
$this -> convolves = array_merge ( $this -> convolves , $options );
2014-02-12 14:45:25 +01:00
return $this ;
2012-05-09 17:57:48 +02:00
}
2013-10-03 18:16:33 +02:00
2014-11-24 09:27:47 +01:00
/**
* Image convolution .
2015-01-10 20:17:12 +01:00
*
2014-11-27 22:04:41 +01:00
* @ param string $options A string with 11 float separated by comma .
2014-11-24 09:27:47 +01:00
*
* @ return $this
*/
2014-11-27 22:04:41 +01:00
public function imageConvolution ( $options = null )
2014-11-24 09:27:47 +01:00
{
2014-11-27 22:04:41 +01:00
// Use incoming options or use $this.
$options = $options ? $options : $this -> convolve ;
2014-11-24 09:27:47 +01:00
2014-11-27 22:04:41 +01:00
// Treat incoming as string, split by +
$this -> log ( " Convolution with ' $options ' " );
$options = explode ( " : " , $options );
// Check each option if it matches constant value
2014-12-03 15:23:50 +01:00
foreach ( $options as $option ) {
2014-11-27 22:04:41 +01:00
list ( $matrix , $divisor , $offset ) = $this -> createConvolveArguments ( $option );
imageconvolution ( $this -> image , $matrix , $divisor , $offset );
}
2015-01-10 20:17:12 +01:00
2014-11-24 09:27:47 +01:00
return $this ;
}
2014-12-03 15:23:50 +01:00
/**
* Set default background color between 000000 - FFFFFF or if using
* alpha 00000000 - FFFFFF7F .
*
* @ param string $color as hex value .
*
* @ return $this
*/
public function setDefaultBackgroundColor ( $color )
{
$this -> log ( " Setting default background color to ' $color '. " );
if ( ! ( strlen ( $color ) == 6 || strlen ( $color ) == 8 )) {
throw new Exception (
" Background color needs a hex value of 6 or 8
digits . 000000 - FFFFFF or 00000000 - FFFFFF7F .
Current value was : '$color' . "
);
}
$red = hexdec ( substr ( $color , 0 , 2 ));
$green = hexdec ( substr ( $color , 2 , 2 ));
$blue = hexdec ( substr ( $color , 4 , 2 ));
$alpha = ( strlen ( $color ) == 8 )
? hexdec ( substr ( $color , 6 , 2 ))
: null ;
if (( $red < 0 || $red > 255 )
|| ( $green < 0 || $green > 255 )
|| ( $blue < 0 || $blue > 255 )
|| ( $alpha < 0 || $alpha > 127 )
) {
throw new Exception (
" Background color out of range. Red, green blue
should be 00 - FF and alpha should be 00 - 7 F .
Current value was : '$color' . "
);
}
$this -> bgColor = strtolower ( $color );
$this -> bgColorDefault = array (
'red' => $red ,
'green' => $green ,
'blue' => $blue ,
'alpha' => $alpha
);
return $this ;
}
/**
* Get the background color .
*
* @ param resource $img the image to work with or null if using $this -> image .
*
* @ return color value or null if no background color is set .
*/
private function getBackgroundColor ( $img = null )
{
$img = isset ( $img ) ? $img : $this -> image ;
if ( $this -> bgColorDefault ) {
$red = $this -> bgColorDefault [ 'red' ];
$green = $this -> bgColorDefault [ 'green' ];
$blue = $this -> bgColorDefault [ 'blue' ];
$alpha = $this -> bgColorDefault [ 'alpha' ];
if ( $alpha ) {
$color = imagecolorallocatealpha ( $img , $red , $green , $blue , $alpha );
} else {
$color = imagecolorallocate ( $img , $red , $green , $blue );
}
return $color ;
} else {
return 0 ;
}
}
2015-01-10 20:17:12 +01:00
2014-12-03 15:23:50 +01:00
2014-02-12 14:45:25 +01:00
/**
* Create a image and keep transparency for png and gifs .
*
* @ param int $width of the new image .
* @ param int $height of the new image .
2014-12-03 15:23:50 +01:00
*
2014-02-12 14:45:25 +01:00
* @ return image resource .
*/
2014-08-31 23:57:34 +02:00
private function createImageKeepTransparency ( $width , $height )
2014-02-12 14:45:25 +01:00
{
$this -> log ( " Creating a new working image width= { $width } px, height= { $height } px. " );
$img = imagecreatetruecolor ( $width , $height );
imagealphablending ( $img , false );
2014-08-31 23:57:34 +02:00
imagesavealpha ( $img , true );
2014-02-12 14:45:25 +01:00
2015-09-17 11:22:50 +02:00
$index = $this -> image
? imagecolortransparent ( $this -> image )
: - 1 ;
2015-12-06 12:26:20 +01:00
2015-02-09 00:40:55 +01:00
if ( $index != - 1 ) {
imagealphablending ( $img , true );
$transparent = imagecolorsforindex ( $this -> image , $index );
$color = imagecolorallocatealpha ( $img , $transparent [ 'red' ], $transparent [ 'green' ], $transparent [ 'blue' ], $transparent [ 'alpha' ]);
imagefill ( $img , 0 , 0 , $color );
$index = imagecolortransparent ( $img , $color );
$this -> Log ( " Detected transparent color = " . implode ( " , " , $transparent ) . " at index = $index " );
} elseif ( $this -> bgColorDefault ) {
2014-12-03 15:23:50 +01:00
$color = $this -> getBackgroundColor ( $img );
imagefill ( $img , 0 , 0 , $color );
$this -> Log ( " Filling image with background color. " );
}
2014-02-12 14:45:25 +01:00
return $img ;
2013-10-03 18:16:33 +02:00
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
/**
2015-01-10 20:17:12 +01:00
* Set optimizing and post - processing options .
2014-02-12 14:45:25 +01:00
*
* @ param array $options with config for postprocessing with external tools .
*
* @ return $this
*/
2014-08-31 23:57:34 +02:00
public function setPostProcessingOptions ( $options )
2014-02-12 14:45:25 +01:00
{
if ( isset ( $options [ 'jpeg_optimize' ]) && $options [ 'jpeg_optimize' ]) {
$this -> jpegOptimizeCmd = $options [ 'jpeg_optimize_cmd' ];
2014-04-01 08:11:49 +02:00
} else {
2014-08-31 23:57:34 +02:00
$this -> jpegOptimizeCmd = null ;
2014-02-12 14:45:25 +01:00
}
if ( isset ( $options [ 'png_filter' ]) && $options [ 'png_filter' ]) {
$this -> pngFilterCmd = $options [ 'png_filter_cmd' ];
2014-04-01 08:11:49 +02:00
} else {
$this -> pngFilterCmd = null ;
2014-02-12 14:45:25 +01:00
}
if ( isset ( $options [ 'png_deflate' ]) && $options [ 'png_deflate' ]) {
$this -> pngDeflateCmd = $options [ 'png_deflate_cmd' ];
2014-04-01 08:11:49 +02:00
} else {
$this -> pngDeflateCmd = null ;
2014-02-12 14:45:25 +01:00
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
return $this ;
2013-10-03 18:16:33 +02:00
}
2015-03-06 13:00:21 +01:00
/**
* Find out the type ( file extension ) for the image to be saved .
*
* @ return string as image extension .
*/
protected function getTargetImageExtension ()
{
2015-10-21 00:05:14 +02:00
// switch on mimetype
2015-03-06 13:00:21 +01:00
if ( isset ( $this -> extension )) {
return strtolower ( $this -> extension );
} else {
2015-10-21 00:05:14 +02:00
return substr ( image_type_to_extension ( $this -> fileType ), 1 );
2015-03-06 13:00:21 +01:00
}
}
2015-12-06 12:26:20 +01:00
2015-03-06 13:00:21 +01:00
2014-02-12 14:45:25 +01:00
/**
* Save image .
*
2015-09-17 11:22:50 +02:00
* @ param string $src as target filename .
* @ param string $base as base directory where to store images .
* @ param boolean $overwrite or not , default to always overwrite file .
2014-02-12 14:45:25 +01:00
*
* @ return $this or false if no folder is set .
*/
2015-09-17 11:22:50 +02:00
public function save ( $src = null , $base = null , $overwrite = true )
2014-02-12 14:45:25 +01:00
{
if ( isset ( $src )) {
$this -> setTarget ( $src , $base );
}
2013-10-03 18:16:33 +02:00
2015-09-17 11:22:50 +02:00
if ( $overwrite === false && is_file ( $this -> cacheFileName )) {
$this -> Log ( " Not overwriting file since its already exists and \$ overwrite if false. " );
return ;
}
2014-11-21 22:31:04 +01:00
is_writable ( $this -> saveFolder )
or $this -> raiseError ( 'Target directory is not writable.' );
2015-10-21 00:05:14 +02:00
$type = $this -> getTargetImageExtension ();
$this -> Log ( " Saving image as " . $type );
2015-12-07 16:01:47 +01:00
switch ( $type ) {
2015-01-10 20:17:12 +01:00
2014-08-21 02:02:50 +02:00
case 'jpeg' :
case 'jpg' :
2014-02-12 14:45:25 +01:00
$this -> Log ( " Saving image as JPEG to cache using quality = { $this -> quality } . " );
imagejpeg ( $this -> image , $this -> cacheFileName , $this -> quality );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Use JPEG optimize if defined
2014-02-12 15:09:29 +01:00
if ( $this -> jpegOptimizeCmd ) {
2014-08-31 23:57:34 +02:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> log ( " Filesize before optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
2014-02-12 14:45:25 +01:00
}
$res = array ();
2014-02-12 15:09:29 +01:00
$cmd = $this -> jpegOptimizeCmd . " -outfile $this->cacheFileName $this->cacheFileName " ;
2014-02-12 14:45:25 +01:00
exec ( $cmd , $res );
$this -> log ( $cmd );
$this -> log ( $res );
}
2014-08-31 23:57:34 +02:00
break ;
2014-02-12 14:45:25 +01:00
case 'gif' :
2015-01-10 20:17:12 +01:00
$this -> Log ( " Saving image as GIF to cache. " );
imagegif ( $this -> image , $this -> cacheFileName );
2014-08-31 23:57:34 +02:00
break ;
2014-02-12 14:45:25 +01:00
2014-08-31 23:57:34 +02:00
case 'png' :
2015-03-06 13:00:21 +01:00
default :
2014-02-12 14:45:25 +01:00
$this -> Log ( " Saving image as PNG to cache using compression = { $this -> compress } . " );
// Turn off alpha blending and set alpha flag
imagealphablending ( $this -> image , false );
imagesavealpha ( $this -> image , true );
2014-08-31 23:57:34 +02:00
imagepng ( $this -> image , $this -> cacheFileName , $this -> compress );
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
// Use external program to filter PNG, if defined
2014-02-12 15:09:29 +01:00
if ( $this -> pngFilterCmd ) {
2014-08-31 23:57:34 +02:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> Log ( " Filesize before filter optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
2014-02-12 14:45:25 +01:00
}
$res = array ();
2014-02-12 15:09:29 +01:00
$cmd = $this -> pngFilterCmd . " $this->cacheFileName " ;
2014-02-12 14:45:25 +01:00
exec ( $cmd , $res );
$this -> Log ( $cmd );
$this -> Log ( $res );
}
// Use external program to deflate PNG, if defined
2014-02-12 15:09:29 +01:00
if ( $this -> pngDeflateCmd ) {
2014-08-31 23:57:34 +02:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> Log ( " Filesize before deflate optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
2014-02-12 14:45:25 +01:00
}
$res = array ();
2014-02-12 15:09:29 +01:00
$cmd = $this -> pngDeflateCmd . " $this->cacheFileName " ;
2014-02-12 14:45:25 +01:00
exec ( $cmd , $res );
$this -> Log ( $cmd );
$this -> Log ( $res );
}
2014-08-31 23:57:34 +02:00
break ;
}
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
clearstatcache ();
2015-03-06 13:00:21 +01:00
$this -> log ( " Saved image to cache. " );
$this -> log ( " Cached image filesize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
$this -> log ( " imageistruecolor() : " . ( imageistruecolor ( $this -> image ) ? 'true' : 'false' ));
$this -> log ( " imagecolorstotal() : " . imagecolorstotal ( $this -> image ));
$this -> log ( " Number of colors in image = " . $this -> ColorsTotal ( $this -> image ));
2015-02-09 00:40:55 +01:00
$index = imagecolortransparent ( $this -> image );
2015-03-06 13:00:21 +01:00
$this -> log ( " Detected transparent color = " . ( $index > 0 ? implode ( " , " , imagecolorsforindex ( $this -> image , $index )) : " NONE " ) . " at index = $index " );
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
return $this ;
}
2015-10-23 14:19:46 +02:00
/**
* Convert image from one colorpsace / color profile to sRGB without
* color profile .
*
* @ param string $src of image .
* @ param string $dir as base directory where images are .
* @ param string $cache as base directory where to store images .
2015-10-24 15:43:56 +02:00
* @ param string $iccFile filename of colorprofile .
2015-10-23 14:19:46 +02:00
* @ param boolean $useCache or not , default to always use cache .
*
* @ return string | boolean false if no conversion else the converted
* filename .
*/
2015-10-24 15:43:56 +02:00
public function convert2sRGBColorSpace ( $src , $dir , $cache , $iccFile , $useCache = true )
2015-10-23 14:19:46 +02:00
{
if ( $this -> verbose ) {
$this -> log ( " # Converting image to sRGB colorspace. " );
}
if ( ! class_exists ( " Imagick " )) {
$this -> log ( " Ignoring since Imagemagick is not installed. " );
return false ;
}
// Prepare
$this -> setSaveFolder ( $cache )
-> setSource ( $src , $dir )
2015-10-24 16:42:59 +02:00
-> generateFilename ( null , false , 'srgb_' );
2015-10-23 14:19:46 +02:00
// Check if the cached version is accurate.
if ( $useCache && is_readable ( $this -> cacheFileName )) {
$fileTime = filemtime ( $this -> pathToImage );
$cacheTime = filemtime ( $this -> cacheFileName );
if ( $fileTime <= $cacheTime ) {
$this -> log ( " Using cached version: " . $this -> cacheFileName );
return $this -> cacheFileName ;
}
}
// Only covert if cachedir is writable
if ( is_writable ( $this -> saveFolder )) {
// Load file and check if conversion is needed
$image = new Imagick ( $this -> pathToImage );
$colorspace = $image -> getImageColorspace ();
$this -> log ( " Current colorspace: " . $colorspace );
2015-12-06 12:26:20 +01:00
$profiles = $image -> getImageProfiles ( '*' , false );
2015-10-23 14:19:46 +02:00
$hasICCProfile = ( array_search ( 'icc' , $profiles ) !== false );
$this -> log ( " Has ICC color profile: " . ( $hasICCProfile ? " YES " : " NO " ));
if ( $colorspace != Imagick :: COLORSPACE_SRGB || $hasICCProfile ) {
$this -> log ( " Converting to sRGB. " );
2015-10-24 15:43:56 +02:00
$sRGBicc = file_get_contents ( $iccFile );
$image -> profileImage ( 'icc' , $sRGBicc );
2015-12-06 12:26:20 +01:00
2015-10-23 14:19:46 +02:00
$image -> transformImageColorspace ( Imagick :: COLORSPACE_SRGB );
$image -> writeImage ( $this -> cacheFileName );
return $this -> cacheFileName ;
}
}
2015-12-06 12:26:20 +01:00
2015-10-23 14:19:46 +02:00
return false ;
}
2015-01-15 23:29:18 +01:00
/**
* Create a hard link , as an alias , to the cached file .
*
2015-01-17 19:15:18 +01:00
* @ param string $alias where to store the link ,
* filename without extension .
2015-01-15 23:29:18 +01:00
*
* @ return $this
*/
public function linkToCacheFile ( $alias )
{
if ( $alias === null ) {
$this -> log ( " Ignore creating alias. " );
return $this ;
}
if ( is_readable ( $alias )) {
unlink ( $alias );
}
$res = link ( $this -> cacheFileName , $alias );
if ( $res ) {
2015-01-19 00:00:54 +01:00
$this -> log ( " Created an alias as: $alias " );
2015-01-15 23:29:18 +01:00
} else {
$this -> log ( " Failed to create the alias: $alias " );
}
return $this ;
}
2015-10-21 01:12:10 +02:00
/**
* Add HTTP header for putputting together with image .
*
* @ param string $type the header type such as " Cache-Control "
* @ param string $value the value to use
*
* @ return void
*/
public function addHTTPHeader ( $type , $value )
{
$this -> HTTPHeader [ $type ] = $value ;
}
2014-02-12 14:45:25 +01:00
/**
* Output image to browser using caching .
*
2015-10-21 01:12:10 +02:00
* @ param string $file to read and output , default is to
* use $this -> cacheFileName
* @ param string $format set to json to output file as json
* object with details
2014-02-12 14:45:25 +01:00
*
* @ return void
*/
2014-11-21 22:20:30 +01:00
public function output ( $file = null , $format = null )
2014-02-12 14:45:25 +01:00
{
if ( is_null ( $file )) {
$file = $this -> cacheFileName ;
2013-10-03 18:16:33 +02:00
}
2014-11-21 22:20:30 +01:00
if ( is_null ( $format )) {
$format = $this -> outputFormat ;
}
$this -> log ( " Output format is: $format " );
if ( ! $this -> verbose && $format == 'json' ) {
header ( 'Content-type: application/json' );
echo $this -> json ( $file );
exit ;
2015-09-01 16:45:10 +02:00
} elseif ( $format == 'ascii' ) {
header ( 'Content-type: text/plain' );
echo $this -> ascii ( $file );
exit ;
2014-11-21 22:20:30 +01:00
}
2014-02-12 14:45:25 +01:00
$this -> log ( " Outputting image: $file " );
2013-10-03 18:16:33 +02:00
2014-11-21 20:20:35 +01:00
// Get image modification time
clearstatcache ();
2014-05-20 00:55:43 +02:00
$lastModified = filemtime ( $file );
2014-02-12 14:45:25 +01:00
$gmdate = gmdate ( " D, d M Y H:i:s " , $lastModified );
2014-05-20 00:55:43 +02:00
if ( ! $this -> verbose ) {
header ( 'Last-Modified: ' . $gmdate . " GMT " );
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
2015-12-07 16:01:47 +01:00
foreach ( $this -> HTTPHeader as $key => $val ) {
2015-10-21 01:12:10 +02:00
header ( " $key : $val " );
}
2014-02-12 14:45:25 +01:00
if ( isset ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) && strtotime ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) == $lastModified ) {
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
$this -> log ( " 304 not modified " );
$this -> verboseOutput ();
exit ;
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
header ( " HTTP/1.0 304 Not Modified " );
2015-01-10 20:17:12 +01:00
2014-05-20 00:55:43 +02:00
} else {
2015-01-10 20:17:12 +01:00
2015-10-18 18:34:42 +02:00
// Get details on image
$info = getimagesize ( $file );
! empty ( $info ) or $this -> raiseError ( " The file doesn't seem to be an image. " );
$mime = $info [ 'mime' ];
$size = filesize ( $file );
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
2015-10-18 18:34:42 +02:00
$this -> log ( " Last-Modified: " . $gmdate . " GMT " );
$this -> log ( " Content-type: " . $mime );
$this -> log ( " Content-length: " . $size );
2014-02-12 14:45:25 +01:00
$this -> verboseOutput ();
2015-12-06 12:26:20 +01:00
2015-07-25 22:21:12 +02:00
if ( is_null ( $this -> verboseFileName )) {
exit ;
}
2014-02-12 14:45:25 +01:00
}
2015-10-18 18:34:42 +02:00
header ( " Content-type: $mime " );
header ( " Content-length: $size " );
2014-02-12 14:45:25 +01:00
readfile ( $file );
}
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
exit ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
2014-11-21 22:20:30 +01:00
/**
* Create a JSON object from the image details .
*
2014-12-13 00:12:39 +01:00
* @ param string $file the file to output .
*
2014-11-21 22:20:30 +01:00
* @ return string json - encoded representation of the image .
*/
2014-12-13 00:12:39 +01:00
public function json ( $file = null )
2014-11-21 22:20:30 +01:00
{
2014-12-13 00:12:39 +01:00
$file = $file ? $file : $this -> cacheFileName ;
2014-11-21 22:20:30 +01:00
$details = array ();
clearstatcache ();
2015-03-06 13:00:21 +01:00
$details [ 'src' ] = $this -> imageSrc ;
$lastModified = filemtime ( $this -> pathToImage );
2014-11-24 10:46:50 +01:00
$details [ 'srcGmdate' ] = gmdate ( " D, d M Y H:i:s " , $lastModified );
2014-11-21 22:20:30 +01:00
2015-03-06 13:00:21 +01:00
$details [ 'cache' ] = basename ( $this -> cacheFileName );
$lastModified = filemtime ( $this -> cacheFileName );
2014-11-24 10:46:50 +01:00
$details [ 'cacheGmdate' ] = gmdate ( " D, d M Y H:i:s " , $lastModified );
2014-11-21 22:20:30 +01:00
2015-03-06 13:00:21 +01:00
$this -> load ( $file );
2014-12-13 00:12:39 +01:00
2015-03-06 13:00:21 +01:00
$details [ 'filename' ] = basename ( $file );
$details [ 'mimeType' ] = image_type_to_mime_type ( $this -> fileType );
$details [ 'width' ] = $this -> width ;
$details [ 'height' ] = $this -> height ;
2014-11-24 10:46:50 +01:00
$details [ 'aspectRatio' ] = round ( $this -> width / $this -> height , 3 );
2015-03-06 13:00:21 +01:00
$details [ 'size' ] = filesize ( $file );
2014-12-15 09:19:23 +01:00
$details [ 'colors' ] = $this -> colorsTotal ( $this -> image );
2015-10-20 10:04:37 +02:00
$details [ 'includedFiles' ] = count ( get_included_files ());
2015-10-21 00:05:14 +02:00
$details [ 'memoryPeek' ] = round ( memory_get_peak_usage () / 1024 / 1024 , 3 ) . " MB " ;
2015-10-20 10:04:37 +02:00
$details [ 'memoryCurrent' ] = round ( memory_get_usage () / 1024 / 1024 , 3 ) . " MB " ;
2015-10-21 00:05:14 +02:00
$details [ 'memoryLimit' ] = ini_get ( 'memory_limit' );
2015-12-06 12:26:20 +01:00
2015-10-21 00:05:14 +02:00
if ( isset ( $_SERVER [ 'REQUEST_TIME_FLOAT' ])) {
$details [ 'loadTime' ] = ( string ) round (( microtime ( true ) - $_SERVER [ 'REQUEST_TIME_FLOAT' ]), 3 ) . " s " ;
}
2015-10-20 10:04:37 +02:00
if ( $details [ 'mimeType' ] == 'image/png' ) {
2015-10-20 13:46:01 +02:00
$details [ 'pngType' ] = $this -> getPngTypeAsString ( null , $file );
2015-10-20 10:04:37 +02:00
}
2014-12-15 09:19:23 +01:00
2014-11-26 14:45:38 +01:00
$options = null ;
if ( defined ( " JSON_PRETTY_PRINT " ) && defined ( " JSON_UNESCAPED_SLASHES " )) {
$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ;
}
2015-01-10 20:17:12 +01:00
2014-11-26 14:45:38 +01:00
return json_encode ( $details , $options );
2014-11-21 22:20:30 +01:00
}
2015-09-01 16:45:10 +02:00
/**
* Set options for creating ascii version of image .
*
* @ param array $options empty to use default or set options to change .
*
* @ return void .
*/
public function setAsciiOptions ( $options = array ())
{
$this -> asciiOptions = $options ;
}
/**
* Create an ASCII version from the image details .
*
* @ param string $file the file to output .
*
* @ return string ASCII representation of the image .
*/
public function ascii ( $file = null )
{
$file = $file ? $file : $this -> cacheFileName ;
$asciiArt = new CAsciiArt ();
$asciiArt -> setOptions ( $this -> asciiOptions );
return $asciiArt -> createFromFile ( $file );
}
2014-02-12 14:45:25 +01:00
/**
* Log an event if verbose mode .
*
* @ param string $message to log .
*
2014-05-20 00:55:43 +02:00
* @ return this
2014-02-12 14:45:25 +01:00
*/
2014-05-20 00:55:43 +02:00
public function log ( $message )
2014-02-12 14:45:25 +01:00
{
if ( $this -> verbose ) {
2014-05-20 00:55:43 +02:00
$this -> log [] = $message ;
2014-02-12 14:45:25 +01:00
}
2014-05-20 00:55:43 +02:00
return $this ;
2014-02-12 14:45:25 +01:00
}
2015-01-10 20:17:12 +01:00
2015-07-25 22:21:12 +02:00
/**
* Do verbose output to a file .
*
* @ param string $fileName where to write the verbose output .
*
* @ return void
*/
public function setVerboseToFile ( $fileName )
{
$this -> log ( " Setting verbose output to file. " );
$this -> verboseFileName = $fileName ;
}
2014-02-12 14:45:25 +01:00
/**
* Do verbose output and print out the log and the actual images .
*
* @ return void
*/
2014-05-20 00:55:43 +02:00
private function verboseOutput ()
2014-02-12 14:45:25 +01:00
{
$log = null ;
2014-11-21 22:20:30 +01:00
$this -> log ( " As JSON: \n " . $this -> json ());
2014-02-12 14:45:25 +01:00
$this -> log ( " Memory peak: " . round ( memory_get_peak_usage () / 1024 / 1024 ) . " M " );
$this -> log ( " Memory limit: " . ini_get ( 'memory_limit' ));
$included = get_included_files ();
$this -> log ( " Included files: " . count ( $included ));
2015-01-10 20:17:12 +01:00
2014-02-12 14:45:25 +01:00
foreach ( $this -> log as $val ) {
if ( is_array ( $val )) {
foreach ( $val as $val1 ) {
$log .= htmlentities ( $val1 ) . '<br/>' ;
}
} else {
$log .= htmlentities ( $val ) . '<br/>' ;
}
}
2015-07-25 22:21:12 +02:00
if ( ! is_null ( $this -> verboseFileName )) {
file_put_contents (
$this -> verboseFileName ,
str_replace ( " <br/> " , " \n " , $log )
);
} else {
echo <<< EOD
2014-02-12 14:45:25 +01:00
< h1 > CImage Verbose Output </ h1 >
< pre > { $log } </ pre >
EOD ;
2015-07-25 22:21:12 +02:00
}
2014-02-12 14:45:25 +01:00
}
/**
* Raise error , enables to implement a selection of error methods .
*
* @ param string $message the error message to display .
*
2015-01-10 20:17:12 +01:00
* @ return void
2014-02-12 14:45:25 +01:00
* @ throws Exception
*/
2014-05-20 00:55:43 +02:00
private function raiseError ( $message )
2014-02-12 14:45:25 +01:00
{
throw new Exception ( $message );
}
2014-05-20 00:55:43 +02:00
}