/**
* class Image
*
*/
class Image
{
private static $_classname = __CLASS__;
/**
* image resource
* @var resource
*/
protected $_image = null;
/**
* image width
* @var integer
*/
private $_width = 1;
/**
* image height
* @var integer
*/
private $_height = 1;
/**
* wether to use antialiasing
* @var boolean
*/
private $_antialiasing = true;
/**
* wether to use alpha blending
* @var boolean
*/
private $_alphablending = false;
/**
* render quality (used for JPEG output)
* @var integer
*/
private $_renderquality = 80;
/**
* constructor
*
* different parameter values are possible:
* 1) @param resource of 'gd'
* 2) @param Image
* 3) @param string (path to source image)
* 4) @param integer width
* @param integer height (optional, if not set, height = 1)
* 5) no parameters
*/
public function __construct()
{
$arguments_count = func_num_args();
$arguments = func_get_args();
if ($arguments_count > 0) {
if (is_resource($arguments[0]) AND get_resource_type($arguments[0]) === 'gd') {
// $instance = new Image($imageresource);
// copies image resource as $this->_image
$this->_image = $arguments[0];
@imagedestroy($argument[0]);
} else if ($arguments[0] instanceof self::$_classname) {
// $instance = new Image($instance of self);
// copies image resource of an image instance
$this->_image = $arguments[0]->getImageResource();
} else if (is_string($arguments[0]) AND is_readable($arguments[0])) {
// $instance = new Image('/path/to/image.ext');
// path to an image
$info = @getimagesize($arguments[0]);
// GIF, JPEG, PNG
if (Validate::isBetween($info[2], 1, 3)) {
switch ($info[2]) {
case 1: $this->_image = @imagecreatefromgif($arguments[0]); break;
case 2: $this->_image = @imagecreatefromjpeg($arguments[0]); break;
case 3: $this->_image = @imagecreatefrompng($arguments[0]); break;
}
$this->_width = $info[0];
$this->_height = $info[1];
}
} else {
// $instance = new Image(256); --> imagecreatetruecolor(256,1)
// $instance = new Image(256, 128); --> imagecreatetruecolor(256,128)
// create new image resource
$this->_width = (isset($arguments[0]) AND is_integer($arguments[0]) AND $arguments[0] >= 1)
? (int) $arguments[0]
: 1;
$this->height = (isset($arguments[1]) AND is_integer($arguments[1]) AND $arguments[1] >= 1)
? (int) $arguments[1]
: 1;
$this->_image = @imagecreatetruecolor($this->_width, $this->_height);
}
}
if (!is_resource($this->_image) OR get_resource_type($this->_image) !== 'gd' ) {
$this->_image = imagecreatetruecolor(1, 1);
}
$this->setAntiAliasing(true);
$this->setAlphaBlending(false);
$this->setRenderQuality(80);
}
/**
* returns a reference to the image resource
*
* @return reference of $this->_image
*/
public function &getImageResource()
{
return $this->_image;
}
/**
* returns width of $this->_image
*
* @return integer
*/
public function getWidth()
{
return imagesx($this->_image);
}
/**
* returns height of $this->_image
*
* @return integer
*/
public function getHeight()
{
return imagesy($this->_image);
}
/**
* set canvas size
*
* @param integer $width
* @param integer $height
* @return boolean
*/
public function setCanvasSize($width, $height)
{
settype($width, 'int');
settype($height, 'int');
if ($width <= 0) {
$width = 1;
}
if ($height <= 0) {
$height = 1;
}
if ($this->_image === null) {
if ($this->_image = @imagecreatetruecolor($width, $height)) {
return true;
}
} else if ($image_new = @imagecreatetruecolor($width, $height)
AND @imagecopy($image_new, $this->_image, 0, 0, 0, 0, $this->_width, $this->_height) )
{
imagedestroy($this->_image);
$this->_image = &$image_new;
$this->_width = imagesx($this->_image);
$this->_height = imagesy($this->_image);
return true;
}
$this->_width = $this->getWidth();
$this->_height = $this->getHeight();
return false;
}
/**
* resize canvas
*
* @param integer $width_max
* @param integer $height_max
* @param string $scale (case: 'x' [default], 'y', 'fit')
* @return boolean
*/
public function resizeCanvas($width_max, $height_max, $scale = 'x')
{
if ($this->_image === null) {
return false;
}
settype($width_max, 'int');
settype($height_max, 'int');
settype($fixratio, 'float');
if ($width_max <= 0) {
$width_max = 1;
}
if ($height_max <= 0) {
$height_max = 1;
}
if ($fixratio < 0) {
$fixratio = 1;
}
$source = array( 'width' => $this->getWidth(),
'height' => $this->getHeight() );
$canvas = array( 'width' => $width_max,
'height' => $height_max );
$destination = array( 'x1' => 0,
'y1' => 0,
'x2' => 0,
'y2' => 0 );
$ratio = $source['width'] / $source['height'];
$scalar = 1;
switch ($scale) {
default:
case 'x':
$canvas['height'] = $canvas['width'] / $ratio;
$destination = array( 'x1' => 0,
'y1' => 0,
'x2' => $canvas['width'],
'y2' => $canvas['height'],
'w' => $canvas['width'],
'h' => $canvas['height'] );
break;
case 'y':
$canvas['width'] = $canvas['height'] * $ratio;
$destination = array( 'x1' => 1,
'y1' => 1,
'x2' => $source['width'],
'y2' => $canvas['height'],
'w' => $canvas['width'],
'h' => $canvas['height'] );
break;
case 'fit':
$set = array();
if (($source['width'] / $source['height']) > ($canvas['width'] / $canvas['height'])) {
$scalar = $canvas['height'] / $source['height'];
$set['width'] = $scalar * $source['width'];
$destination = array( 'x1' => ($canvas['width'] - $source['width'] * $scalar) / 2,
'y1' => 0,
'x2' => ($canvas['width'] + $source['width'] * $scalar) / 2,
'y2' => $canvas['height'],
'w' => $source['width'] * $scalar,
'h' => $canvas['height'] );
} else {
$scalar = $canvas['width'] / $source['width'];
$set['height'] = $scalar * $source['height'];
$destination = array( 'x1' => 0,
'y1' => ($canvas['height'] - $source['height'] * $scalar) / 2,
'x2' => $canvas['width'],
'y2' => ($canvas['height'] + $source['height'] * $scalar) / 2,
'w' => $canvas['width'],
'h' => $source['height'] * $scalar );
}
break;
}
if ($canvas['width'] < 1) {
$canvas['width'] = 1;
}
if ($canvas['height'] < 1) {
$canvas['height'] = 1;
}
if ($image_new = @imagecreatetruecolor((int) $canvas['width'], (int) $canvas['height'])
AND @imagecopyresampled ($image_new,
$this->_image,
(int) $destination['x1'],
(int) $destination['y1'],
(int) 0,
(int) 0,
(int) ($destination['w']),
(int) ($destination['h']),
(int) $source['width'],
(int) $source['height']) )
{
$this->_image = &$image_new;
$this->_width = $this->getWidth();
$this->_height = $this->getHeight();
return true;
}
$this->_width = $this->getWidth();
$this->_height = $this->getHeight();
return false;
}
/**
* sets antialiasing
*
* @param boolean $aa
* @return boolean (success)
*/
public function setAntiAliasing($antialiasing)
{
settype($antialiasing, 'boolean');
if (@imageantialias($this->_image, $antialiasing)) {
$this->_antialiasing = $antialiasing;
return true;
}
return false;
}
/**
* sets alpha blending
*
* @param boolean $ab
* @return boolean (success)
*/
public function setAlphaBlending($alphablending)
{
settype($alphablending, 'boolean');
if (@imagealphablending($this->_image, $alphablending)
AND @imagesavealpha($this->_image, $alphablending) ) {
$this->_alphablending = $alphablending;
return true;
}
return false;
}
/**
* sets render quality (JPEG output only)
*
* @param integer $quality
*/
public function setRenderQuality($quality)
{
settype($quality, 'int');
$this->_renderquality = (Validate::isBetween($quality, 0, 100))
? $quality
: 80;
}
/**
* output of internal image resource
*
* @param string (enum: 'gif', 'png', 'jpeg' [default])
* @return boolean
*/
public function render($format = '')
{
if (!Validate::isResourceOf($this->_image, 'gd')
OR headers_sent() === true) {
throw new Image_Exception('Rendering Error: No valid Image Resource or Headers already sent!');
}
switch ($format) {
case 'gif':
header('Content-type: image/gif');
imagegif($this->_image);
break;
case 'png':
header('Content-type: image/png');
imagepng($this->_image);
break;
case 'jpeg':
case 'jpg':
default:
header('Content-type: image/jpeg');
imagejpeg($this->_image, '', $this->_renderquality);
break;
}
return true;
}
/**
* fill canvas with $color, beginning at ($x | $y)
*
* @param integer $color
* @param integer $x
* @param integer $y
* @return boolean
*/
public function fillCanvas($color, $x, $y)
{
settype($x, 'int');
settype($y, 'int');
if ($x <= 0 OR $y <= 0 OR !Validate::isBetween($color, 0x000000, 0xffffff, false, true)) {
return false;
}
if (@imagefill($this->_image, $x, $y, $color)) {
return true;
}
return false;
}
/**
* returns allocated color value of the desired color
*
* @param integer, array of integer $color
* @param integer $alpha
* @return integer
*/
public function getColor($color, $alpha = 0)
{
settype($alpha, 'int');
if (!Validate::isBetween($alpha, 0, 127)) {
$alpha = 0;
}
switch (true) {
case (Validate::ofType($color, 'integer') AND Validate::isBetween($color, 0x000000, 0xffffff)):
$col = array( 'red' => 0xff & ($color >> 0x10),
'green' => 0xff & ($color >> 0x8),
'blue' => 0xff & ($color) );
$color = &$col;
case (is_array($color) AND isset($color['red'], $color['green'], $color['blue'])):
if (!Validate::isBetween($color['red'], 0x000000, 0xffffff)
OR !Validate::isBetween($color['green'], 0x000000, 0xffffff)
OR !Validate::isBetween($color['blue'], 0x000000, 0xffffff)) {
break;
}
$color = imagecolorallocatealpha($this->_image, $color['red'], $color['green'], $color['blue'], $alpha);
break;
}
return $color;
}
/**
* embed image (if exists) onto canvas
*
* @param string, ressource of gd $source
* @param integer $position
* @param integer, array $border_padding
* @return boolean
* @throws Image_Exception
*/
public function embedImage($source, $position = 3, $border_padding = array(8, 8, 8, 8))
{
// get image resource or throw Image_Exception
if (Validate::ofType($source, 'string') AND is_readable($source)) {
$embed = new self::$_classname($source);
$image_embed = $embed->getImageResource();
if (!Validate::isResourceOf($image_embed, 'gd')) {
return false;
}
} else if (Validate::isResourceOf($image_embed, 'gd')) {
$image_embed = &$source;
} else if ($source instanceof self::$_classname) {
$image_embed = $source->getImageResource();
} else {
throw new Image_Exception('Embedding Image: Wrong Input Format!');
}
$image_embed_size = array('width' => imagesx($image_embed),
'height' => imagesy($image_embed));
// padding
if (is_integer($border_padding)) {
$padding = array( 0 => (int) $border_padding,
1 => (int) $border_padding,
2 => (int) $border_padding,
3 => (int) $border_padding );
} else if (is_array($border_padding)) {
switch (true) {
case (isset($border_padding[0], $border_padding[1], $border_padding[2], $border_padding[3])):
$padding = array( 0 => (int) $border_padding[0],
1 => (int) $border_padding[1],
2 => (int) $border_padding[2],
3 => (int) $border_padding[3] );
break;
case (isset($border_padding[0], $border_padding[1], $border_padding[2])):
$padding = array( 0 => (int) $border_padding[0],
1 => (int) $border_padding[1],
2 => (int) $border_padding[2],
3 => (int) $border_padding[1] );
break;
case (isset($border_padding[0], $border_padding[1])):
$padding = array( 0 => (int) $border_padding[0],
1 => (int) $border_padding[1],
2 => (int) $border_padding[0],
3 => (int) $border_padding[1] );
break;
case (isset($border_padding[0])):
$padding = array( 0 => (int) $border_padding[0],
1 => (int) $border_padding[0],
2 => (int) $border_padding[0],
3 => (int) $border_padding[0] );
break;
default:
$padding = array( 0 => (int) 0,
1 => (int) 0,
2 => (int) 0,
3 => (int) 0 );
break;
}
} else {
$padding = array( 0 => (int) 0,
1 => (int) 0,
2 => (int) 0,
3 => (int) 0 );
}
// return false if embedded image is too wide
if ((1.5 * $image_embed_size['width']) > $this->getWidth()
OR (1.5 * $image_embed_size['height']) > $this->getHeight() ) {
return false;
}
// Positioning
settype($position, 'int');
if (!Validate::isBetween($position, 1, 9, false, true)) {
$position = 3;
}
switch ($position) {
case 1: $destination = array( 'x' => $padding[3],
'y' => $this->getHeight() - $image_embed_size['height'] - $padding[2] );
break;
case 2: $destination = array( 'x' => ($this->getWidth() - $image_embed_size['width']) / 2,
'y' => $this->getHeight() - $image_embed_size['height'] - $padding[2] );
break;
case 3: $destination = array( 'x' => $this->getWidth() - $image_embed_size['width'] - $padding[1],
'y' => $this->getHeight() - $image_embed_size['height'] - $padding[2] );
break;
case 4: $destination = array( 'x' => $padding[3],
'y' => ($this->getHeight() - $image_embed_size['height']) / 2 );
break;
case 5: $destination = array( 'x' => ($this->getWidth() - $image_embed_size['width']) / 2,
'y' => ($this->getHeight() - $image_embed_size['height']) / 2 );
break;
case 6: $destination = array( 'x' => $this->getWidth() - $image_embed_size['width'] - $padding[1],
'y' => ($this->getHeight() - $image_embed_size['height']) / 2 );
break;
case 7: $destination = array( 'x' => $padding[3],
'y' => $padding[0] );
break;
case 8: $destination = array( 'x' => ($this->getWidth() - $image_embed_size['width']) / 2,
'y' => $padding[0] );
break;
case 9: $destination = array( 'x' => $this->getWidth() - $image_embed_size['width'] - $padding[1],
'y' => $padding[0] );
break;
}
imagecopy($this->_image,
$image_embed,
(int) $destination['x'],
(int) $destination['y'],
(int) 0,
(int) 0,
(int) $image_embed_size['width'],
(int) $image_embed_size['height']);
return true;
}
/**
* draw filled rectangle
*
* @param integer $color
* @param integer $x1
* @param integer $y1
* @param integer $x2
* @param integer $y2
*/
public function drawFilledRectangle($color, $x1, $y1, $x2, $y2)
{
imagefilledrectangle($this->_image,
(int) $x1,
(int) $y1,
(int) $x2,
(int) $y2,
(int) $this->getColor($color));
}
/**
* draw border
*
* @param integer $color
* @param integer $x1
* @param integer $y1
* @param integer $x2
* @param integer $y2
*/
public function drawBorder($color = 0, $x1 = 1, $y1 = 1, $x2 = null, $y2 = null)
{
if ($x2 === null) {
$x2 = $this->_width;
}
if ($y2 === null) {
$y2 = $this->_height;
}
imagerectangle($this->_image,
(int) $x1,
(int) $y1,
(int) $x2,
(int) $y2,
(int) $this->getColor($color));
}
}