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
*
* @ author Mikael Roos mos @ dbwebb . se
2014-02-12 14:45:25 +01:00
* @ example http :// dbwebb . se / opensource / cimage
2012-04-25 15:53:46 +02:00
* @ link https :// github . com / mosbth / cimage
2012-04-25 15:49:09 +02:00
*/
2014-02-12 14:45:25 +01:00
class CImage
{
/**
* 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 ;
/**
* Constant for default image quality when not set
*/
const JPEG_QUALITY_DEFAULT = 60 ;
/**
* Quality level for JPEG images .
*/
private $quality ;
/**
* Constant for default image quality when not set
*/
const PNG_COMPRESSION_DEFAULT = - 1 ;
/**
* Compression level for PNG images .
*/
private $compress ;
/**
* Where to save the target file .
*/
private $saveFolder ;
/**
* The working image object .
*/
private $image ;
/**
* The root folder of images ( only used in constructor to create $pathToImage ? ) .
*/
private $imageFolder ;
/**
* Image filename , may include subdirectory , relative from $imageFolder
*/
private $imageSrc ;
/**
* Actual path to the image , $imageFolder . '/' . $imageSrc
*/
private $pathToImage ;
/**
* Original file extension
*/
private $fileExtension ;
/**
* File extension to use when saving image
*/
private $extension ;
/**
* Verbose mode to print out a trace and display the created image
*/
private $verbose = false ;
/**
* Keep a log / trace on what happens
*/
private $log = array ();
/**
* 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 ;
/**
* Path to command for deflate optimize , for example pngout or null .
*/
private $pngDeflate ;
/**
* Path to command to optimize jpeg images , for example jpegtran or null .
*/
private $jpegOptimize ;
private $width ; // Calculated from source image
private $height ; // Calculated from source image
private $offset ;
public $keepRatio ;
public $cropToFit ;
public $crop ;
2012-04-25 15:49:09 +02:00
2013-10-03 18:16:33 +02:00
2012-04-25 15:49:09 +02:00
/**
* Properties
*/
public $newWidth ;
public $newHeight ;
private $cropWidth ;
private $cropHeight ;
2012-05-09 17:57:48 +02:00
public $crop_x ;
public $crop_y ;
public $filters ;
2012-04-25 15:49:09 +02:00
private $type ; // Calculated from source image
private $attr ; // Calculated from source image
2013-10-03 18:16:33 +02:00
private $useCache ; // Use the cache if true, set to false to ignore the cached file.
private $useOriginal ; // Use original image if possible
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 .
*/
public function __construct ( $imageSrc = null , $imageFolder = null , $saveFolder = null , $saveName = null )
{
$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 .
*
* @ param boolean $mode true or false to enable and disable versbose mode , default is true .
*
* @ return $this
*/
public function setVerbose ( $mode = true )
{
$this -> verbose = $mode ;
return $this ;
}
2013-10-03 18:16:33 +02: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
*/
private function checkFileExtension ( $extension )
{
$valid = array ( 'jpg' , 'jpeg' , 'png' , 'gif' );
in_array ( $extension , $valid )
or $this -> raiseError ( 'Not a valid file extension.' );
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Set src file .
*
* @ param string $src of image .
* @ param string $dir as base directory where images are .
*
* @ return $this
*/
public function setSource ( $src = null , $dir = null )
{
if ( ! ( isset ( $src ) && isset ( $dir ))) {
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
$this -> imageSrc = ltrim ( $src , '/' );
$this -> imageFolder = rtrim ( $dir , '/' );
$this -> pathToImage = $this -> imageFolder . '/' . $this -> imageSrc ;
$this -> fileExtension = pathinfo ( $this -> pathToImage , PATHINFO_EXTENSION );
$this -> extension = $this -> fileExtension ;
$this -> checkFileExtension ( $this -> fileExtension );
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
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
* Set target file .
*
* @ param string $src of target image .
* @ param string $dir as base directory where images are stored .
*
* @ return $this
*/
public function setTarget ( $src = null , $dir = null )
{
if ( ! ( isset ( $src ) && isset ( $dir ))) {
return $this ;
2012-05-09 17:57:48 +02:00
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
$this -> saveFolder = $dir ;
$this -> cacheFileName = $dir . '/' . $src ;
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
is_writable ( $this -> saveFolder )
or $this -> raiseError ( 'Target directory is not writable.' );
// Sanitize filename
$this -> cacheFileName = preg_replace ( '/^a-zA-Z0-9\.-_/' , '' , $this -> cacheFileName );
$this -> log ( " The cache file name is: " . $this -> cacheFileName );
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
/**
* Set options to use when processing image .
*
* @ param array $args used when processing image .
*
* @ return $this
*/
public function setOptions ( $args )
{
$this -> log ( " Set new options for processing image. " );
$defaults = array (
// Options for calculate dimensions
'newWidth' => null ,
'newHeight' => null ,
'aspectRatio' => null ,
'keepRatio' => true ,
'cropToFit' => false ,
'crop' => null , //array('width'=>null, 'height'=>null, 'start_x'=>0, 'start_y'=>0),
'area' => null , //'0,0,0,0',
// Options for caching or using original
'useCache' => true ,
'useOriginal' => true ,
// Pre-processing, before resizing is done
'scale' => null ,
// Post-processing, after resizing is done
'palette' => null ,
'filters' => null ,
'sharpen' => null ,
'emboss' => null ,
'blur' => null ,
// Options for saving
//'quality' => null,
//'compress' => null,
//'saveAs' => null,
);
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 ;
for ( $i = 1 ; $i <= $filter [ 'argc' ]; $i ++ ) {
if ( isset ( $parts [ $i ])) {
$filter [ " arg { $i } " ] = $parts [ $i ];
} else {
throw new Exception ( 'Missing arg to filter, review how many arguments are needed at http://php.net/manual/en/function.imagefilter.php' );
}
}
$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 );
foreach ( $defaults as $key => $val ) {
$this -> { $key } = $args [ $key ];
2013-10-07 23:50:53 +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
* @ throws Exception
*/
private function mapFilter ( $name )
{
$map = array (
'negate' => array ( 'id' => 0 , 'argc' => 0 , 'type' => IMG_FILTER_NEGATE ),
'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 ),
);
if ( isset ( $map [ $name ]))
return $map [ $name ];
2013-10-07 23:50:53 +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
}
}
2014-02-12 14:45:25 +01:00
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
* Init new width and height and do some sanity checks on constraints , before any
* processing can be done .
*
* @ return $this
* @ throws Exception
*/
public function initDimensions ()
{
is_readable ( $this -> pathToImage )
or $this -> raiseError ( 'Image file does not exist.' );
// Get details on image
$info = list ( $this -> width , $this -> height , $this -> type , $this -> attr ) = getimagesize ( $this -> pathToImage );
! empty ( $info ) or $this -> raiseError ( " The file doesn't seem to be an image. " );
if ( $this -> verbose ) {
$this -> log ( " Image file: { $this -> pathToImage } " );
$this -> log ( " Image width x height (type): { $this -> width } x { $this -> height } ( { $this -> type } ). " );
$this -> log ( " Image filesize: " . filesize ( $this -> pathToImage ) . " bytes. " );
}
// 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 } " );
}
// Check values to be within domain
is_null ( $this -> newWidth )
or is_numeric ( $this -> newWidth )
or $this -> raiseError ( 'Width not numeric' );
is_null ( $this -> newHeight )
or is_numeric ( $this -> newHeight )
or $this -> raiseError ( 'Height not numeric' );
2013-10-03 18:16:33 +02:00
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
*/
public function calculateNewWidthAndHeight ()
{
// 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 } . " );
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 ;
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 );
}
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 );
}
$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-02-12 14:45:25 +01:00
// Calculate new width and height if keeping aspect-ratio.
if ( $this -> keepRatio ) {
// Crop-to-fit and both new width and height are set.
if ( $this -> cropToFit && isset ( $this -> newWidth ) && isset ( $this -> newHeight )) {
// Use newWidth and newHeigh as width/height, image should fit in box.
;
} elseif ( isset ( $this -> newWidth ) && isset ( $this -> newHeight )) {
// 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 );
} elseif ( isset ( $this -> newWidth )) {
// Use new width as max-width
$factor = ( float ) $this -> newWidth / ( float ) $width ;
$this -> newHeight = round ( $factor * $height );
} elseif ( isset ( $this -> newHeight )) {
// Use new height as max-hight
$factor = ( float ) $this -> newHeight / ( float ) $height ;
$this -> newWidth = round ( $factor * $width );
}
// Use newWidth and newHeigh as defined width/height, image should fit the area.
if ( $this -> cropToFit ) {
$ratioWidth = $width / $this -> newWidth ;
$ratioHeight = $height / $this -> newHeight ;
$ratio = ( $ratioWidth < $ratioHeight ) ? $ratioWidth : $ratioHeight ;
$this -> cropWidth = round ( $width / $ratio );
$this -> cropHeight = round ( $height / $ratio );
}
}
// Crop, ensure to set new width and height
if ( $this -> crop ) {
$this -> newWidth = round ( isset ( $this -> newWidth ) ? $this -> newWidth : $this -> crop [ 'width' ]);
$this -> newHeight = round ( isset ( $this -> newHeight ) ? $this -> newHeight : $this -> crop [ 'height' ]);
}
// No new height or width is set, use existing measures.
$this -> newWidth = round ( isset ( $this -> newWidth ) ? $this -> newWidth : $this -> width );
$this -> newHeight = round ( isset ( $this -> newHeight ) ? $this -> newHeight : $this -> height );
$this -> log ( " Calculated new width x height as { $this -> newWidth } x { $this -> newHeight } . " );
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Set extension for filename to save as .
*
* @ param string $saveas extension to save image as
*
* @ return $this
*/
public function setSaveAsExtension ( $saveAs = null )
{
if ( isset ( $saveAs )) {
$this -> checkFileExtension ( $saveAs );
$this -> saveAs = $saveAs ;
$this -> extension = $saveAs ;
}
$this -> log ( " Prepare to save image using as: " . $this -> extension );
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 .
*
* @ return $this
*/
public function setJpegQuality ( $quality = null )
{
$this -> quality = isset ( $quality )
? $quality
: self :: JPEG_QUALITY_DEFAULT ;
( is_numeric ( $this -> quality ) and $this -> quality > 0 and $this -> quality <= 100 )
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 .
*
* @ return $this
*/
public function setPngCompression ( $compress = null )
{
$this -> compress = isset ( $compress )
? $compress
: self :: PNG_COMPRESSION_DEFAULT ;
( is_numeric ( $this -> compress ) and $this -> compress >= - 1 and $this -> compress <= 9 )
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
*/
public function useOriginalIfPossible ( $useOrig = true )
{
if ( $useOrig
&& ( $this -> newWidth == $this -> width )
&& ( $this -> newHeight == $this -> height )
&& ! $this -> area
&& ! $this -> crop
&& ! $this -> filters
&& ! $this -> sharpen
&& ! $this -> emboss
&& ! $this -> blur
&& ! $this -> palette
&& ! $this -> quality
&& ! $this -> compress
&& ! $this -> saveAs
) {
$this -> log ( " Using original image. " );
$this -> output ( $this -> pathToImage );
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
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Generate filename to save file in cache .
*
* @ param string $base as basepath for storing file .
*
* @ return $this
*/
public function generateFilename ( $base )
{
$parts = pathinfo ( $this -> pathToImage );
$cropToFit = $this -> cropToFit ? '_cf' : null ;
$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 ;
$quality = $this -> quality ? " _q { $this -> quality } " : null ;
$compress = $this -> compress ? " _co { $this -> compress } " : null ;
$offset = isset ( $this -> offset )
? '_o' . $this -> offset [ 'top' ] . '-' . $this -> offset [ 'right' ] . '-' . $this -> offset [ 'bottom' ] . '-' . $this -> offset [ 'left' ]
: null ;
$crop = $this -> crop
? '_c' . $this -> crop [ 'width' ] . '-' . $this -> crop [ 'height' ] . '-' . $this -> crop [ 'start_x' ] . '-' . $this -> crop [ 'start_y' ]
: null ;
$filters = null ;
if ( isset ( $this -> filters )) {
foreach ( $this -> filters as $filter ) {
if ( is_array ( $filter )) {
$filters .= " _f { $filter [ 'id' ] } " ;
for ( $i = 1 ; $i <= $filter [ 'argc' ]; $i ++ ) {
$filters .= " : " . $filter [ " arg { $i } " ];
}
}
}
}
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 ;
$this -> extension = isset ( $this -> extension )
? $this -> extension
: $parts [ 'extension' ];
// Check optimizing options
$optimize = null ;
if ( $this -> extension == 'jpeg' || $this -> extension == 'jpg' ) {
$optimize = $this -> jpegOptimize ? 'o' : null ;
} elseif ( $this -> extension == 'png' ) {
$optimize .= $this -> pngFilter ? 'f' : null ;
$optimize .= $this -> pngDeflate ? 'd' : null ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
$subdir = str_replace ( '/' , '-' , dirname ( $this -> imageSrc ));
$subdir = ( $subdir == '.' ) ? '_.' : $subdir ;
$file = $subdir . '_' . $parts [ 'filename' ] . '_' . round ( $this -> newWidth ) . '_'
. round ( $this -> newHeight ) . $offset . $crop . $cropToFit . $crop_x . $crop_y
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
. $scale . '.' . $this -> extension ;
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 .
*
* @ param boolean $useCache is default true , set to false to avoid using cached object .
*
* @ return $this
*/
public function useCacheIfPossible ( $useCache = true )
{
if ( $useCache && is_readable ( $this -> cacheFileName )) {
$fileTime = filemtime ( $this -> pathToImage );
$cacheTime = filemtime ( $this -> cacheFileName );
if ( $fileTime <= $cacheTime ) {
if ( $this -> useCache ) {
if ( $this -> verbose ) {
$this -> log ( " Use cached file. " );
$this -> log ( " Cached image filesize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
}
$this -> output ( $this -> cacheFileName );
} 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
2012-04-25 15:49:09 +02:00
2014-02-12 14:45:25 +01:00
/**
* Load image from disk .
*
* @ param string $src of image .
* @ param string $dir as base directory where images are .
*
* @ return $this
*
*/
public function load ( $src = null , $dir = null )
{
if ( isset ( $src )) {
$this -> setSource ( $src , $dir );
}
$this -> log ( " Opening file as { $this -> fileExtension } . " );
switch ( $this -> fileExtension ) {
case 'jpg' :
case 'jpeg' :
2014-08-21 02:13:01 +02:00
$this -> image = @ imagecreatefromjpeg ( $this -> pathToImage );
2014-08-21 02:08:49 +02:00
$this -> image or die ( " Fatal error when opening image. " );
2014-02-12 14:45:25 +01:00
break ;
2012-10-02 22:49:43 +02:00
2014-02-12 14:45:25 +01:00
case 'gif' :
2014-08-21 02:13:01 +02:00
$this -> image = @ imagecreatefromgif ( $this -> pathToImage );
2014-08-21 02:08:49 +02:00
$this -> image or die ( " Fatal error when opening image. " );
2014-02-12 14:45:25 +01:00
break ;
case 'png' :
2014-08-21 02:13:01 +02:00
$this -> image = @ imagecreatefrompng ( $this -> pathToImage );
2014-08-21 02:08:49 +02:00
$this -> image or die ( " Fatal error when opening image. " );
2014-02-12 14:45:25 +01:00
$type = $this -> getPngType ();
$hasFewColors = imagecolorstotal ( $this -> image );
if ( $type == self :: PNG_RGB_PALETTE || ( $hasFewColors > 0 && $hasFewColors <= 256 )) {
if ( $this -> verbose ) {
$this -> log ( " Handle this image as a palette image. " );
}
$this -> palette = true ;
}
break ;
default :
$this -> image = false ;
throw new Exception ( 'No support for this file extension.' );
}
if ( $this -> verbose ) {
$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 ));
}
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 .
*
* @ return int as the type of the png - image
*
*/
private function getPngType ()
{
$pngType = ord ( file_get_contents ( $this -> pathToImage , false , null , 25 , 1 ));
switch ( $pngType ) {
case self :: PNG_GREYSCALE :
$this -> log ( " PNG is type 0, Greyscale. " );
break ;
case self :: PNG_RGB :
$this -> log ( " PNG is type 2, RGB " );
break ;
case self :: PNG_RGB_PALETTE :
$this -> log ( " PNG is type 3, RGB with palette " );
break ;
case self :: PNG_GREYSCALE_ALPHA :
$this -> Log ( " PNG is type 4, Greyscale with alpha channel " );
break ;
case self :: PNG_RGB_ALPHA :
$this -> Log ( " PNG is type 6, RGB with alpha channel (PNG 32-bit) " );
break ;
default :
$this -> Log ( " PNG is UNKNOWN type, is it really a PNG image? " );
}
return $pngType ;
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
/**
* Calculate number of colors in an image .
*
* @ param resource $im the image .
*
* @ return int
*/
private function colorsTotal ( $im )
{
if ( imageistruecolor ( $im )) {
$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 {
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
*/
public function preResize ()
{
$this -> log ( " Pre-process before resizing " );
// 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 ;
}
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Resize and or crop the image .
*
* @ return $this
*/
public function resize ()
{
$this -> log ( " Starting to Resize() " );
// Only use a specified area of the image, $this->offset is defining the area to use
if ( isset ( $this -> offset )) {
$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' ];
}
// SaveAs need to copy image to remove transparency, if any
if ( $this -> saveAs ) {
$this -> log ( " Copying image before saving as another format, loosing transparency, width= { $this -> width } , height= { $this -> height } . " );
$img = imagecreatetruecolor ( $this -> width , $this -> height );
$bg = imagecolorallocate ( $img , 255 , 255 , 255 );
imagefill ( $img , 0 , 0 , $bg );
imagecopy ( $img , $this -> image , 0 , 0 , 0 , 0 , $this -> width , $this -> height );
$this -> image = $img ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
// Do as crop, take only part of image
if ( $this -> crop ) {
2013-10-03 18:16:33 +02:00
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' ]);
imagecopyresampled ( $img , $this -> image , 0 , 0 , $this -> crop [ 'start_x' ], $this -> crop [ 'start_y' ], $this -> crop [ 'width' ], $this -> crop [ 'height' ], $this -> crop [ 'width' ], $this -> crop [ 'height' ]);
$this -> image = $img ;
$this -> width = $this -> crop [ 'width' ];
$this -> height = $this -> crop [ 'height' ];
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Resize by crop to fit
if ( $this -> cropToFit ) {
$this -> log ( " Crop to fit " );
$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 );
imagecopyresampled ( $imgPreCrop , $this -> image , 0 , 0 , 0 , 0 , $this -> cropWidth , $this -> cropHeight , $this -> width , $this -> height );
imagecopyresampled ( $imageResized , $imgPreCrop , 0 , 0 , $cropX , $cropY , $this -> newWidth , $this -> newHeight , $this -> newWidth , $this -> newHeight );
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
} else if ( ! ( $this -> newWidth == $this -> width && $this -> newHeight == $this -> height )) {
// Resize it
$this -> log ( " Resizing, new height and/or width " );
$imageResized = $this -> CreateImageKeepTransparency ( $this -> newWidth , $this -> newHeight );
imagecopyresampled ( $imageResized , $this -> image , 0 , 0 , 0 , 0 , $this -> newWidth , $this -> newHeight , $this -> width , $this -> height );
//imagecopyresized($imageResized, $this->image, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
$this -> image = $imageResized ;
$this -> width = $this -> newWidth ;
$this -> height = $this -> newHeight ;
}
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
*/
public function postResize ()
{
$this -> log ( " Post-process after resizing " );
// Apply filters
if ( isset ( $this -> filters ) && is_array ( $this -> filters )) {
foreach ( $this -> filters as $filter ) {
$this -> log ( " Applying filter $filter . " );
switch ( $filter [ 'argc' ]) {
case 0 :
imagefilter ( $this -> image , $filter [ 'type' ]);
break ;
case 1 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ]);
break ;
case 2 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ]);
break ;
case 3 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ], $filter [ 'arg3' ]);
break ;
case 4 :
imagefilter ( $this -> image , $filter [ 'type' ], $filter [ 'arg1' ], $filter [ 'arg2' ], $filter [ 'arg3' ], $filter [ 'arg4' ]);
break ;
}
}
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Convert to palette image
if ( $this -> palette ) {
$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
if ( $this -> blur ) {
$this -> log ( " Blur. " );
$this -> blurImage ();
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Emboss the image
if ( $this -> emboss ) {
$this -> log ( " Emboss. " );
$this -> embossImage ();
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Sharpen the image
if ( $this -> sharpen ) {
$this -> log ( " Sharpen. " );
$this -> sharpenImage ();
2012-05-09 17:57:48 +02:00
}
2013-10-07 23:50:53 +02:00
2014-02-12 14:45:25 +01: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
*/
public function trueColorToPalette ()
{
$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
/**
* Sharpen image as http :// php . net / manual / en / ref . image . php #56144
* http :// loriweb . pair . com / 8 udf - sharpen . html
*
* @ return $this
*/
public function sharpenImage ()
{
$matrix = array (
array ( - 1 , - 1 , - 1 ,),
array ( - 1 , 16 , - 1 ,),
array ( - 1 , - 1 , - 1 ,),
);
$divisor = 8 ;
$offset = 0 ;
imageconvolution ( $this -> image , $matrix , $divisor , $offset );
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
/**
* Emboss image as http :// loriweb . pair . com / 8 udf - emboss . html
*
* @ return $this
*/
public function embossImage ()
{
$matrix = array (
array ( 1 , 1 , - 1 ,),
array ( 1 , 3 , - 1 ,),
array ( 1 , - 1 , - 1 ,),
);
2013-10-07 23:50:53 +02:00
2014-02-12 14:45:25 +01:00
$divisor = 3 ;
$offset = 0 ;
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
imageconvolution ( $this -> image , $matrix , $divisor , $offset );
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
/**
* Blur image as http :// loriweb . pair . com / 8 udf - basics . html
*
* @ return $this
*/
public function blurImage ()
{
$matrix = array (
array ( 1 , 1 , 1 ,),
array ( 1 , 15 , 1 ,),
array ( 1 , 1 , 1 ,),
);
2012-10-02 22:49:43 +02:00
2014-02-12 14:45:25 +01:00
$divisor = 23 ;
$offset = 0 ;
2012-10-02 22:49:43 +02:00
2014-02-12 14:45:25 +01:00
imageconvolution ( $this -> image , $matrix , $divisor , $offset );
2012-05-09 17:57:48 +02:00
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-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 .
* @ return image resource .
*/
2014-05-20 00:55:43 +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 );
imagesavealpha ( $img , true );
/*
$this -> Log ( " Filling image with background color. " );
$bg = imagecolorallocate ( $img , 255 , 255 , 255 );
imagefill ( $img , 0 , 0 , $bg );
*/
return $img ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Set optimizing and post - processing options . CHANGE FROM DEFINE TO INJECT INTO CLASS , TO BE ABLE TO SET OFF POSTPROCESSING
*
* @ param array $options with config for postprocessing with external tools .
*
* @ return $this
*/
public function setPostProcessingOptions ( $options )
{
if ( isset ( $options [ 'jpeg_optimize' ]) && $options [ 'jpeg_optimize' ]) {
$this -> jpegOptimizeCmd = $options [ 'jpeg_optimize_cmd' ];
2014-04-01 08:11:49 +02:00
} else {
$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
}
return $this ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
/**
* Save image .
*
* @ param string $src as target filename .
* @ param string $base as base directory where to store images .
*
* @ return $this or false if no folder is set .
*/
2014-08-21 02:02:50 +02:00
public function save ( $src = null , $base = null )
2014-02-12 14:45:25 +01:00
{
if ( isset ( $src )) {
$this -> setTarget ( $src , $base );
}
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
switch ( $this -> extension ) {
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 );
2013-10-03 18:16:33 +02: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-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> log ( " Filesize before optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
}
$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 );
}
break ;
case 'gif' :
if ( $this -> saveFolder ) {
$this -> Log ( " Saving image as GIF to cache. " );
imagegif ( $this -> image , $this -> cacheFileName );
}
break ;
case 'png' :
$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 );
imagepng ( $this -> image , $this -> cacheFileName , $this -> compress );
// Use external program to filter PNG, if defined
2014-02-12 15:09:29 +01:00
if ( $this -> pngFilterCmd ) {
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> Log ( " Filesize before filter optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
}
$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-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
clearstatcache ();
$this -> Log ( " Filesize before deflate optimize: " . filesize ( $this -> cacheFileName ) . " bytes. " );
}
$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 );
}
break ;
default :
$this -> RaiseError ( 'No support for this file extension.' );
break ;
}
if ( $this -> verbose ) {
clearstatcache ();
$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 ));
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
return $this ;
}
/**
* Output image to browser using caching .
*
* @ param string $file to read and output , default is to use $this -> cacheFileName
*
* @ return void
*/
public function output ( $file = null )
{
if ( is_null ( $file )) {
$file = $this -> cacheFileName ;
2013-10-03 18:16:33 +02:00
}
2014-02-12 14:45:25 +01:00
$this -> log ( " Outputting image: $file " );
2013-10-03 18:16:33 +02:00
2014-02-12 14:45:25 +01:00
// Get details on image
$info = list ( $width , $height , $type , $attr ) = getimagesize ( $file );
! empty ( $info ) or $this -> raiseError ( " The file doesn't seem to be an image. " );
$mime = $info [ 'mime' ];
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
if ( isset ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) && strtotime ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) == $lastModified ) {
if ( $this -> verbose ) {
$this -> log ( " 304 not modified " );
$this -> verboseOutput ();
exit ;
}
header ( " HTTP/1.0 304 Not Modified " );
2014-05-20 00:55:43 +02:00
} else {
2014-02-12 14:45:25 +01:00
if ( $this -> verbose ) {
$this -> log ( " Last modified: " . $gmdate . " GMT " );
$this -> verboseOutput ();
exit ;
}
2014-05-20 00:55:43 +02:00
header ( 'Content-type: ' . $mime );
2014-02-12 14:45:25 +01:00
readfile ( $file );
}
exit ;
2013-10-03 18:16:33 +02:00
}
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
}
2012-04-25 15:49:09 +02:00
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 ;
$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 ));
foreach ( $this -> log as $val ) {
if ( is_array ( $val )) {
foreach ( $val as $val1 ) {
$log .= htmlentities ( $val1 ) . '<br/>' ;
}
} else {
$log .= htmlentities ( $val ) . '<br/>' ;
}
}
echo <<< EOD
<! doctype html >
< html lang = en >
< meta charset = utf - 8 >
< title > CImage verbose output </ title >
< style > body { background - color : #ddd}</style>
< h1 > CImage Verbose Output </ h1 >
< pre > { $log } </ pre >
EOD ;
}
/**
* Raise error , enables to implement a selection of error methods .
*
* @ param string $message the error message to display .
*
* @ return void
* @ 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
}