PHP Classes
Icontem

File: RImageManipulator.class.php


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Riccardo Brambilla  >  RImageManipulator  >  RImageManipulator.class.php  
File: RImageManipulator.class.php
Role: Class source
Content type: text/plain
Description: Class file
Class: RImageManipulator
Manipulate and apply effects on images
 

Contents

Class file image Download
<?php
//  ------------------------------------------------------------------------ //
//  RImageManipulator.class.php,v 1.0 2007/02/15 19:00:00 R.Brambilla        //
//  ------------------------------------------------------------------------ //
//                RImageManipulator - Image Manipulation Class               //
//                  Copyright (C) 2007  Riccardo Brambilla                   //
//                         <ribrambilla@tiscali.it>                   		 //
//  ------------------------------------------------------------------------ //
//  This program is free software; you can redistribute it and/or modify     //
//  it under the terms of the GNU General Public License as published by     //
//  the Free Software Foundation; either version 2 of the License, or        //
//  (at your option) any later version.                                      //
//                                                                           //
//  You may not change or alter any portion of this comment or credits       //
//  of supporting developers from this source code or any supporting         //
//  source code which is considered copyrighted (c) material of the          //
//  original comment or credit authors.                                      //
//                                                                           //
//  This program is distributed in the hope that it will be useful,          //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of           //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
//  GNU General Public License for more details.                             //
//                                                                           //
//  You should have received a copy of the GNU General Public License        //
//  along with this program; if not, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
//  ------------------------------------------------------------------------ //

/**
 * Options are detected from a simple config. file
 * HINT => Change path of the ini file in "parse_ini_file" function to an absolute one
 * 		   dirname(__FILE__) works well only if conf.ini.php file is saved 
 * 		   in the same folder as the class file's one
 */
$conf = parse_ini_file( dirname(__FILE__) . "/conf.ini.php");

$lang = $conf['lang'];
$er_image_w = $conf['er_image_w'];
$er_image_h = $conf['er_image_h'];
$debug_mode = $conf['debug_mode'];

/**
 * Including files
 * [1] Language file
 * HINT => Change path of the lang file to an absolute one
 * 		   dirname(__FILE__) works well only if lang file is saved 
 * 		   in the same folder as the class file's one
 */
if(file_exists( dirname(__FILE__) . "/" . $lang . ".php" )){
	include_once( dirname(__FILE__) . "/" . $lang . ".php" );
}
else {
	die("LANGUAGE FILE NOT FOUND!");
}


/**
 * Handles images 
 * Operations supported: resize ANDOR rotate ANDOR apply filters ANDOR interlace AND save the brand new Image
 * 
 * @author  Riccardo Brambilla aka ricketno <riccardobra@gmail.com>
 * @package RImageManipulator
 * @version 1.0 Feb 2007 PHP5
 *
 */
class RImageManipulator
{
	
	/**
	 * Class var :: $image_pathname
	 *
	 * @var string
	 * @access private
	 */
	private $image_pathname;
	
	/**
	 * Class var :: $image_name
	 *
	 * @var string
	 * @access private
	 */
	private $image_name;
	
	/**
	 * Class var :: $image_path
	 *
	 * @var string
	 * @access private
	 */
	private $image_path;
	
	/**
	 * Class var :: $ext
	 *
	 * @var string
	 * @access private
	 */
	private $ext;
	
	/**
	 * Class var :: $new_w
	 *
	 * @var int
	 * @access private
	 */
	private $new_w;
	
	/**
	 * Class var :: $new_h
	 *
	 * @var int
	 * @access private
	 */
	private $new_h;
	
	/**
	 * Class var :: $new_name
	 *
	 * @var string
	 * @access private
	 */
	private $new_name;
	
	/**
	 * Class var :: $mantain_prop
	 *
	 * @var bool
	 * @access private
	 */
	private $constrain_prop = true;
	
	/**
	 * Class var :: $allowed_ext
	 *
	 * @var array
	 * @access private
	 */
	private $allowed_ext = array( 'jpg', 'jpeg', 'png', 'gif' );
		
	/**
	 * Class var :: image resource
	 *
	 * @var resource
	 * @access private
	 */
	private $im_resource;
	
	/**
	 * Class var :: $img_info
	 *
	 * @var array
	 * @access private
	 */
	private $im_resource_info = array();
	
	/**
	 * Class var :: $error_string
	 * Holds infos about errors occurred
	 *
	 * @var string
	 * @access public
	 */
	public $error_string = "";
	
	/**
	 * Class var :: $memory_needed
	 * Memory needed for script to perform actions
	 *
	 * @var int
	 * @access private
	 */
	private $memory_needed = 0;
		
	
	/**
	 * CLASS Constants
	 * Defaul Size values
	 * Note: _WIDTH & _HEIGHT are both of type int
	 *
	 */
	const _WIDTH  = 120;
	const _HEIGHT = 120;	
		
	/**
	 * CLASS Constants
	 * Constants used by the alloc(), predictMemoryUsage() functions
	 *
	 */
	const _MB      = 1048576;         // Bytes in a MB 
   	const _64K     = 65536;    		  // Bytes in 64K
   	const _TFACTOR = 4.8;      		  // This value works for me :: you can change it
   	const _UPPERLIMIT   = 83886080;   // 80MB ( in Bytes ) Limit :: you can change it

	
	/**
	 * Class Constructor
	 *
	 * @param  string $image_pathname
	 * @param  string $new_name
	 * @return RImageManipulator
	 * 
	 * @access public
	 */
	public function __construct( $image_pathname, $new_name = "" )
	{
		
		// :: CHECKING INPUTS
			
		if(!is_string($image_pathname) || !ereg(".", $image_pathname))
		{
			$this->setError(_ERR_PATHINVALID, 1);
		}
		
		if(!is_file($image_pathname) || !file_exists($image_pathname))
		{
			$this->setError(_ERR_NOTAFILE, 1);
		}

		// :: SETTING CLASS VARS
		
		// : Extension manipulation
		$this->image_pathname = $image_pathname;
		
		$path_components  = explode("/", $this->image_pathname);
		$image_name_ext   = array_pop($path_components);// returns the last element of the path array ( name.ext )
		
		// : If image is in the same directory of the script then path is dirname(__FILE__)
		// : else path is the result of the implode function 
		$this->image_path = sizeof($path_components > 0) ? implode("/", $path_components) : dirname(__FILE__);	
		
		// : Detecting image name and extension
		$name_components  = explode(".", $image_name_ext);
		$this->ext        = strtolower(array_pop($name_components));// extracts last component
		$this->image_name = implode(".", $name_components);
	
		// : Checking if extension is allowed
		if( empty($this->ext) ) 
			$this->setError(_ERRNOTALLOWED, 1);
		
		if( !in_array($this->ext, $this->allowed_ext) )
			$this->setError(_ERRNOTALLOWED, 1);
		
		// : New name if any ; else original name is used
		$this->new_name = empty($new_name) ? $this->image_name : $new_name;
		
		// : Creates the image resource to work on
		$this->createImageResource();
		
	}// ef
	
	
	/**
	 * Get class var value using class var name
	 *
	 * @param string $var_name 
	 * @return mixed
	 * 
	 * @example $extension = $object->getVar('ext');
	 * @access public
	 */
	public function getVar($var_name = "")
	{
		return (isset($this->$var_name) && !empty($var_name)) ? $this->$var_name : "";	
			
	}// ef

	
	/**
	 * Creates an image resource from filesystem 
	 * Appropriate function is chose on the base of file's extension
	 * 
	 * @access private
	 */
	private function createImageResource()
	{
		
// : Get current image size, extra infos like channels and bits
$this->im_resource_info = getimagesize($this->image_pathname);		
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: Creating an empty image
		switch($this->ext)
		{
			
			default:
			case "jpg":// JPG Images
			case "jpeg":
				
				if(!($img = imagecreatefromjpeg($this->image_pathname)))
				{
					 // : Setting the error string
					 $this->setError(_ERR_IMAGECREATION);
					 $this->showImgError();
				}
				
			
				break;
			
			case "png":// PNG Images :: Note: Right pronunciation is "ping" NOT "pee en gee" :)
				
				if(!($img = @imagecreatefrompng($this->image_pathname)))
				{
					 // : Setting the error string
					 $this->setError(_ERR_IMAGECREATION);
					 $this->showImgError();
				}
				
				break;
			
			case "gif":// GIF Images :: Note: Right pronunciation is "jif" NOT "GIF" :)
			
				// Note: GIF Support is expected to return in a GD library version released after mid 2004
				if( function_exists('imagecreatefromgif') && function_exists('imagegif'))
				{
					if((!$img = @imagecreatefromgif($this->image_pathname)))
					{
						 // : Setting the error string
						 $this->setError(_ERR_IMAGECREATION);
						 $this->showImgError();
					}
				}
				else 
				{
					// Gif Support disabled
					$this->setError(_ERR_GIFNOTSUPPORTED);
					$this->showImgError();
				}
				
				break;
			
		}// ends switch
		
		// : Image created is saved as a class var
		// : Type is 'resource'
		$this->im_resource = $img;
		
	}// ef
	
	
	/**
	 * Resizes the image, constrains proportions if asked
	 * 
	 * @param  int $new_w
	 * @param  int $new_h
	 * @param  bool $mantain_prop
	 *   
	 * @access private
	 */
	public function resize( $new_w = 0, $new_h = 0, $constrain_prop = true)
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECKING INPUTS
		
		if(!is_int($new_w) || empty($new_w))
		{
			$new_w = self::_WIDTH;
		}
		
		if(!is_int($new_h) || empty($new_h))
		{
			$new_h = self::_HEIGHT;
		}
		
		if(!is_bool($constrain_prop))
		{
			$constrain_prop = true;
		}
		
		// Check if resource is valid
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}
		
		// : New Size
		$this->new_w = $new_w;
		$this->new_h = $new_h;
		
		// : Proportion must or must not be kept
		$this->constrain_prop = $constrain_prop;
		
		// Image Size
		$img_width  = $this->im_resource_info[0];// W
		$img_height = $this->im_resource_info[1];// H
		
		// :: CONSTRAIN PROPORTION
		if( $this->constrain_prop )
		{			
				
			// Ratio
			$size_prop  = round( ($img_width/$img_height), 3 );
			
			// W = H square
			if( $size_prop == 1 )
			{		
				
				if( $img_width === $this->new_w && $img_height === $this->new_h)
				{
					$tmp_img = $this->im_resource;// no changes needed
				}
				else 
				{	
					// New W-H
					$new_width  = $this->new_w;
					$new_height = $this->new_h;
					
					// Copy ( resample )
					$tmp_img = ImageCreateTrueColor( $new_width, $new_height );
					imagecopyresampled( $tmp_img, $this->im_resource, 0, 0, 0, 0,$this->new_w, $this->new_h, $img_width, $img_height );
				}			
				
			}// ends square case
			elseif( $size_prop > 1 )// W > H
			{
				
				// : Ratio must be computed
				if( $img_width > $this->new_w )
				{
					$ratio   = ( $img_width/$this->new_w );					
					$new_height = floor( $img_height/$ratio );
				}
				else 
				{
					$ratio   = ( $this->new_w/$img_width );
					$new_height = floor( $img_height*$ratio );
				}
				
				$new_width  = $this->new_w;
				
				// Copy ( resample )
				$tmp_img = ImageCreateTrueColor($new_width,$new_height);
				imagecopyresampled($tmp_img, $this->im_resource, 0, 0, 0, 0,$new_width,$new_height, $img_width, $img_height);
			
			}// ends W > H
			elseif( $size_prop < 1 )// W < H
			{
				
				// : Ratio must be computed
				if( $img_height > $this->new_h )
				{
					$ratio   = ( $img_height/$this->new_h );
					$new_width  = floor( $img_width/$ratio );
				}
				else 
				{
					$ratio   = ( $this->new_h/$img_height );
					$new_width  = floor( $img_width*$ratio );
				}
				
				$new_height = $this->new_h;
				
				// Copy ( resample )
				$tmp_img    = ImageCreateTrueColor($new_width,$new_height);
				imagecopyresampled( $tmp_img, $this->im_resource, 0, 0, 0, 0, $new_width, $new_height, $img_width, $img_height);
			
			}// ends W < H
			else
			{
				$this->setError(_ERR_RESIZE);// Error
			}
			
			// "Refreshing" resource
			$this->im_resource = $tmp_img;
			
		}// ends if costrain proportions
		else // Note: PROPORTIONS WILL BE LOST
		{
			
			// Copy ( resample ) width are height are taken directly from user input
			$tmp_img = ImageCreateTrueColor($this->new_w, $this->new_h);
			imagecopyresampled( $tmp_img, $this->im_resource, 0, 0, 0, 0, $this->new_w, $this->new_h, $img_width, $img_height);
			
			// "Refreshing" resource
			$this->im_resource = $tmp_img;
		
		}// ends main else
		
		$this->im_resource = $tmp_img;
		
		// :: Size infos must be refreshed
		// :: Now size infos are taken directly from the resource itself
		$this->im_resource_info[0] = imagesx($this->im_resource);
		$this->im_resource_info[1] = imagesy($this->im_resource);
		
	}// ef
	
	
	/**
	 * Rotates image by $angle degrees
	 * IMPORTANT NOTE: imagerotate function does not preserve infos about transparency
	 * 
	 * @param int $angle 0 < angle < 360 
	 * @param int $bgc  "background" color :: specifies the color of the uncovered zone after the rotation. 
	 * @param bool $clockwise rotation is clockwise ( default ) or counter clockwise
	 * 
	 * @access public
	 */
	public function rotate($angle, $bgc = 0, $clockwise = true)
	{	
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECKING INPUTS
		
		if(!is_int($angle) || ($angle % 90) != 0)
		{
			$angle = 90;// angle must be a multiple of 90
		}
		
		if(!is_int($bgc) || $bgc > 360 || $bgc < 0 )
		{
			$bgc = 0;
		}
		
		if( $clockwise == true ) 
		{
			$angle = abs(360 - $angle);
		}
       
		// Check if resource is valid
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}
		
		// : Rotation
		$this->im_resource = @imagerotate($this->im_resource, $angle, $bgc ) or $this->setError(_ERR_ROTATION);
		
	}// ef
	
	
	/**
	 * Applies filters provided by imagefilter function
	 * Filter Constants are numeric; range is between 0 and 10
	 * Performs checks on optional args number
	 * Filter names are:
	 * 
	 * IMG_FILTER_NEGATE            => 0
	 * IMG_FILTER_GRAYSCALE 		=> 1
	 * IMG_FILTER_BRIGHTNESS 		=> 2
	 * IMG_FILTER_CONTRAST 			=> 3
	 * IMG_FILTER_COLORIZE 			=> 4
	 * IMG_FILTER_EDGEDETECT 		=> 5
	 * IMG_FILTER_EMBOSS 			=> 6
	 * IMG_FILTER_GAUSSIAN_BLUR 	=> 7
	 * IMG_FILTER_SELECTIVE_BLUR 	=> 8
	 * IMG_FILTER_MEAN_REMOVAL 		=> 9
	 * IMG_FILTER_SMOOTH 			=> 10
	 * 
	 * @param int $filter_index
	 * @param array $args optional args
	 * 
	 * @access public
	 */
	public function applyFilter( $filter_index = 0 )
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECK
		// Index is not in the range 0 - 10
		if($filter_index < 0 || $filter_index > 10)
		{
			$this->setError(_ERR_FILTERDOESNOTEXIST);
		}
		
		// Check if resource is valid
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}
		
		// : How many args were sent to the function
		$args_num = func_num_args();
		
		// : Args
		$args = func_get_args();
		
		// :: Switch between indexes, options have their own number of parameters
		switch($filter_index)
		{
			
			default:
			case IMG_FILTER_NEGATE:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_GRAYSCALE:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_BRIGHTNESS:
				
				if($args_num != 2)
					$this->setError(_ERR_FILTERPARAMNUMBER);
					
				@imagefilter($this->im_resource, $filter_index, $args[1]); 
				break;
				
			case IMG_FILTER_CONTRAST:
				
				if($args_num != 2)
					$this->setError(_ERR_FILTERPARAMNUMBER);
					
				@imagefilter($this->im_resource, $filter_index, $args[1]); 
				break;
				
			case IMG_FILTER_COLORIZE:
				
				if($args_num != 4)
					$this->setError(_ERR_FILTERPARAMNUMBER);
					
				@imagefilter($this->im_resource, $filter_index, $args[1], $args[2], $args[3]); 
				break;
			
			case IMG_FILTER_EDGEDETECT:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_EMBOSS:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_GAUSSIAN_BLUR:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_SELECTIVE_BLUR:
				@imagefilter($this->im_resource, $filter_index); 
				break;
				
			case IMG_FILTER_MEAN_REMOVAL:
				@imagefilter($this->im_resource, $filter_index); 
				break;		
			
			case IMG_FILTER_SMOOTH:
								
				if($args_num != 2)
					$this->setError(_ERR_FILTERPARAMNUMBER);
					
				@imagefilter($this->im_resource, $filter_index, $args[1]); 
				break;				

		}// ends switch
	
	}// ef
	

	/**
	 * Interlace or deinterlace image
	 *
	 * @param int $interlace_bit_val
	 */
	public function interlace( $interlace_bit_val = 0 )
	{
		
		// :: CHECKING INPUTS
		
		if( !in_array($interlace_bit_val, array(1, 0)) )
			$interlace_bit_val = 0;
			
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// Check if resource is valid
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}		
		
		// : Interlace op
		@imageinterlace($this->im_resource, $interlace_bit_val);
		
	}// ef
	
	
	/**
	 * Crops image
	 *
	 * @param int $crop_width
	 * @param int $crop_height
	 * @param int $d_x
	 * @param int $d_y
	 * @param int $src_x
	 * @param int $src_y
	 * @param array $bgc 
	 * 
	 * @access public
	 */
	public function crop($crop_width, $crop_height, $d_x = 0, $d_y = 0, $src_x = 0, $src_y = 0, $bgc = array())
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECKING INPUTS
		
		// Is resource a valid one
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}		
		
		if(!is_int($crop_width))
		{
			$crop_width = $this->im_resource_info[0];
		}
		
		if(!is_int($crop_height))
		{
			$crop_height = $this->im_resource_info[1];
		}
		
		if(!is_array($bgc) || count($bgc) !== 3)
		{
			$bgc = array(255, 255, 255);
		}
	
		// : Fill
		$tmp_img  = ImageCreateTrueColor($crop_width, $crop_height);
		$bg_color = imagecolorallocate($tmp_img, $bgc[0], $bgc[1], $bgc[2]);
		imagefill($tmp_img, 0, 0, $bg_color);
		
		// Copy ( resample )
		@imagecopyresampled( $tmp_img, $this->im_resource, (int)$d_x, (int)$d_y, (int)$src_x, (int)$src_y, $crop_width, $crop_height, $crop_width, $crop_height);
		
		// :: Size infos must be refreshed
		$this->im_resource_info[0] = $crop_width;
		$this->im_resource_info[1] = $crop_height;
		$this->im_resource = $tmp_img;
		
	}// ef
	
	
	/**
	 * Draw a message on the image
	 *
	 * @param string $msg
	 * @param int $font
	 * @param int $x
	 * @param int $y
	 * @param array $text_color
	 * 
	 * @access public
	 */
	public function drawString($msg, $font = 2, $x = 0, $y = 0, $text_color = array())
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECKING INPUTS
	
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}		
		
		if(!is_string($msg))
		{
			$this->setError(_ERR_DRAWNOMSG);
		}
		
		if(!is_int($x) || !is_int($y))
		{
			$x = $y = 0;
		}
		
		if($font < 1 || $font > 5)
		{
			$font = 2;
		}
		
		if(!is_array($text_color) || count($text_color) !== 3)
		{
			$text_color = array(255, 255, 255);
		}
		
		$text_color = imagecolorallocate($this->im_resource, $text_color[0], $text_color[1], $text_color[2]);// a kind of white
		
		// : Writing a message on the canvas
        @imagestring($this->im_resource, $font, $x, $y, $msg, $text_color) or $this->setError(_ERR_DS);
	
	}// ef  
	
		
	/**
	 * Generate a fog-like effect 
	 * It draws an alpha indexed gray rectangle on the image
	 * Note: alpha is 0 to 127, where 0 is opaque
	 *
	 * @param int $alpha
	 * 
	 * @access public
	 */
	function fog($alpha = 63)
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}
				
		if(!is_numeric($alpha) || $alpha < 0 || $alpha >127)
		{
			$alpha = 63;
		}
		
		// :: $fog is a light gray, put on the image generate a fog-like effect
		$fog = imagecolorallocatealpha($this->im_resource, 211, 211, 211, (int)$alpha);
		@imagefilledrectangle($this->im_resource, 0, 0, $this->im_resource_info[0], $this->im_resource_info[1], $fog) or $this->setError(_ERR_FOG);

	}// ef
	
	
	/**
	 * Draw a string ( TRUE TYPE FONTS ) on image with a given angle
	 *
	 * @param int $size font size
	 * @param int $angle angolo
	 * @param int $x
	 * @param int $y
	 * @param array $text_color
	 * @param string $font
	 * @param string $msg
	 * 
	 * @access public
	 */
	public function drawTText($size, $angle, $x, $y, $text_color = array(), $msg, $font = 'arial.ttf')
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		// :: CHECKING INPUTS
	
		if (!is_resource($this->im_resource))
		{ 
			$this->setError(_ERR_NOTAVALIDRESOURCE, 1);
		}		
		
		if(!is_numeric($size))
		{
			$size = 10;
		}
		
		if(!is_numeric($angle))
		{
			$angle = 0;
		}
		
		if(!is_int($x) || !is_int($y))
		{
			$x = $y = 0;
		}
		
		if(!is_string($font))
		{
			$font = 'arial.ttf';
		}
		
		if(!is_array($text_color) || count($text_color) !== 3)
		{
			$text_color = array(255, 255, 255);
		}
		
		if(!is_string($msg))
		{
			$this->setError(_ERR_DRAWNOMSG);
		}

		// : Allocating text color
		$text_color = imagecolorallocate($this->im_resource, $text_color[0], $text_color[1], $text_color[2]);// a kind of white
		
		// : Draw string
		@imagettftext($this->im_resource, $size, $angle, $x, $y, $text_color, $font, $msg) or $this->setError(_ERR_TTEXT);
	
	}// ef 

	
	/**
	 * Gives a sepia-like effect 
	 * [1] Image is converted in grayscale
	 * [2] Image is converted from RGB to CMYK
	 * [3] CMYK values are changed to obtain a sepia-like effect
	 * [4] CMKY values are converted to RGB
	 * 
	 * @access public
	 */
	public function sepia()
	{
		$this->alloc();
		
		// : First we need to grayscale the image
		$this->applyFilter(1);
		
		// : Let's create an empty image
		$im = imagecreatetruecolor($this->im_resource_info[0],  $this->im_resource_info[1]);
				
		// :: Looping image's pixels
		for ($y = 0; $y < $this->im_resource_info[1]; $y++)
		{
			
			for ($x = 0; $x < $this->im_resource_info[0]; $x++)
			{
				/**
				 * THESE LINES FROM PHP MANUAL
				 * FUNCTION: imagecolorat
				 * Returns the index of the color of the pixel at the specified location
				 * Use bitshifting and masking to access the distinct red, green and blue component values
				 */
				$rgb = imagecolorat($this->im_resource, $x, $y);
				
				$r = ($rgb >> 16) & 0xFF;
				$g = ($rgb >> 8) & 0xFF;
				$b = $rgb & 0xFF;
				
				// : We need CMYK values to obtain our sepia-like effect 
				list($C, $M, $Y, $K) = $this->rgbToCMYK($r, $g, $b);
			
				// : These are custom values, they works for me
				// : You can increase $M ( magenta channel ) to obtain 
				// : a more "purpled" sepia effect
				$M = $M + 0.14;				
				$Y = $Y + 0.30;
				
				// : Reconvert to RGB
				list($r, $g, $b) = $this->cmykToRGB($C, $M, $Y, $K);
				
				// : This is our new sepia-like color
				$col = imagecolorallocate($im, $r, $g, $b);
				
				// : Setting pixel RGB Value
				imagesetpixel($im, $x, $y, $col);

			}// end inner for
		
		}// ends 2D loop
		
		$this->im_resource = $im;
	
	}// ef
	
	
	/**
	 * Converts RGB values to CMYK values
	 * Function first converts to CMY and then
	 * performs the convertion between CMY and CMYK
	 * 
	 * Algorithm found at easyrgb http://www.easyrgb.com/ ( pseudocode )
	 * Here's my php implementation
	 *
	 * @param int $r
	 * @param int $g
	 * @param int $b
	 * @return array
	 * 
	 * @access private
	 */
	private function rgbToCMYK($r, $g, $b)
	{
		
		// RGB to CMY
		$C = 1 - ( $r / 255 );
		$M = 1 - ( $g / 255 );
		$Y = 1 - ( $b / 255 );
		
		//Where CMYK and CMY values = 0 ÷ 1
		$var_K = 1;
		
		if ( $C < $var_K )   $var_K = $C;
		if ( $M < $var_K )   $var_K = $M;
		if ( $Y < $var_K )   $var_K = $Y;
		
		if ( $var_K == 1 ) { //Black
		   $C = 0;
		   $M = 0;
		   $Y = 0;
		}
		else {
		   $C = ( $C - $var_K ) / ( 1 - $var_K );
		   $M = ( $M - $var_K ) / ( 1 - $var_K );
		   $Y = ( $Y - $var_K ) / ( 1 - $var_K );
		}
		
		// $K ( black value )
		$K = $var_K;
		
		return array($C, $M, $Y, $K);
	
	}// ef
	
	
	/**
	 * Converts CMYK to RGB
	 * First converts from CMYK to CMY
	 * then performs the convertion between CMY and RGB
	 *
	 * Algorithm found at easyrgb http://www.easyrgb.com/ ( pseudocode )
	 * Here's my php implementation
	 * 
	 * @param float $C
	 * @param float $M
	 * @param float $Y
	 * @param float $K
	 * @return array
	 * 
	 * @access private
	 */
	private function cmykToRGB($C, $M, $Y, $K)
	{
				
		// : CMYK and CMY values are 0 ÷ 1
		// : CMYK to CMY
		$C = doubleval( $C * ( 1 - $K ) + $K );
		$M = doubleval( $M * ( 1 - $K ) + $K );
		$Y = doubleval( $Y * ( 1 - $K ) + $K );
		
		// : CMY to RGB
		$R = ( 1 - $C ) * 255;
		$G = ( 1 - $M ) * 255;
		$B = ( 1 - $Y ) * 255;	
		
		return array($R, $G, $B);
	
	}// ef

	
	/**
	 * Allows multiple manipulations to take effect with a single function call
	 * Optional args for applyFilter are hardcoded here 
	 * For custom behaviours use applyFilter function alone
	 * A funny method isn't it? Enjoy :) 
	 * 
	 * @param  string $combo_code
	 * @param  int $angle rotation angle
	 * @access public
	 * 
	 * @example $istance->$a->rcombo("introtneg", 90);
	 * @example $istance->$a->rcombo("bluebrig");
	 */
	public function rcombo($combo_code = "", $angle = 0)
	{
		
		// : We may have to dinamically allocate some extra memory
		$this->alloc();
		
		if(eregi("int",   $combo_code))
			$this->interlace(1);
		
		if(eregi("rot",   $combo_code))
			$this->rotate($angle);
			
		if(eregi("neg",   $combo_code))
			$this->applyFilter(0);
			
		if(eregi("gray",  $combo_code))
			$this->applyFilter(1);
		
		if(eregi("emb",   $combo_code))
			$this->applyFilter(6);	
			
		if(eregi("blue",  $combo_code))
			$this->applyFilter(4, 0, 0, 255);	
			
		if(eregi("red",   $combo_code))
			$this->applyFilter(4, 255, 0, 0);		
			
		if(eregi("green", $combo_code))
			$this->applyFilter(4, 0, 255, 0);
			
		if(eregi("smo", $combo_code))
			$this->applyFilter(10, 50);		
		
		if(eregi("blur", $combo_code))
			$this->applyFilter(7);	
			
		if(eregi("brig", $combo_code))
			$this->applyFilter(2, 50);	

		if(eregi("edge", $combo_code))
			$this->applyFilter(5);		
		
		if(eregi("cont", $combo_code))
			$this->applyFilter(3, 50);
			
		if(eregi("sketch", $combo_code))
			$this->applyFilter(9);		
		
		if(eregi("sepia",  $combo_code))
			$this->sepia();
		
	}// ef
	
	
	/**
	 * Saves the brand new image to filesystem
	 *
	 * @param  string $suffix string will be appended at the image name 
	 * @access public
	 * 
	 * @example $this->save('_rotated') => filename will be : imagename_rotated.ext 
	 */
	public function save( $suffix = "" )
	{
		
		global $debug_mode;
		
		// : Saving image according to extension
		switch($this->ext)
		{
			// imagejpeg has a third parameter ( int quality :: hard coded here value=100)
			default:
			case "jpg":
			case "jpeg": 
				imagejpeg($this->im_resource, $this->new_name . $suffix . "." . $this->ext, 100);
			break;
			
			case "gif":
				imagegif($this->im_resource,  $this->new_name . $suffix . "." . $this->ext);
				break;
				
			case "png":
				imagepng($this->im_resource,  $this->new_name . $suffix . "." . $this->ext);
				break;
		}// ends switch
		
		// :: Free
		imagedestroy($this->im_resource);
		
		// : Show errors if any
		echo ( empty($this->error_string) && $debug_mode) ? "Op Successfull<br />" : $this->showError();
		
	}// ef
		
	
	/**
	 * Alloc as much memory as needed to work with the image
	 * 
	 * This function inspired by posts appeared on php.net site in the manual page of
	 * imagecreatefromjpeg function
	 * Thanks to yaroukh at gmail dot com, Karolis Tamutis karolis.t_AT_gmail.com,  JohnBrook at pobox dot com
	 *
	 * @access private
	 */
	private function alloc()
	{
		
		// : How many bytes we'll need to allocate
		$memory_needed = !empty($this->memory_needed) ? $this->memory_needed : $this->predictMemoryUsage();
		
		// : Retrieving data on current memory limit
		$current_limit = ceil(ini_get('memory_limit')) * 1024 * 1024; 
		$current_usage = ceil(memory_get_usage());

		// : New limit 
		$new_limit = $current_limit + ceil(($current_usage + $memory_needed - $current_limit ));
		
		if(($new_limit > $current_limit))
		{
			if(!($new_limit > self::_UPPERLIMIT))
			{
				// : Malloc
				ini_set( 'memory_limit', ceil($new_limit/self::_MB)  . 'M' );
			}
			else
			{ 
				$this->setError( sprintf(_MEM_LIMIT_REACHED, $new_limit), 1);
			}
				
		}// endif
		
	}// ef
	
	
	/**
	 * Computes memory needed forn performing operations
	 * 
	 * This function inspired by posts appeared on php.net site in the manual page of
	 * imagecreatefromjpeg function
	 * Thanks to yaroukh at gmail dot com, Karolis Tamutis karolis.t_AT_gmail.com, JohnBrook at pobox dot com
	 * 
	 * @return int
	 * @access private
	 * 
	 */
	private function predictMemoryUsage()
	{
		// : Computing memory needed
		$memory_needed = ceil( (    $this->im_resource_info[0] 
								 *  $this->im_resource_info[1]
							     *  $this->im_resource_info['bits']
							     *  $this->im_resource_info['channels'] / 8
							 	 + self::_64K 
							) 	 							
							* self::_TFACTOR 
							);
							
		return $memory_needed;
		
	}// ef
	
	
	/**
	 * Appends data ($er_msg) to the $error_string Class var
	 * If code is set to 1 execution is stopped
	 *
	 * @param string $er_msg
	 * @param int $code 
	 * 
	 * @access private
	 */
	private function setError($er_msg = "", $code = 0)
	{
		
		$this->error_string .= $er_msg . " ";	
		
		// If code is 1 execution must be stopped
		// Error is fatal 
		if( $code === 1 )
		{	
			$this->showError();
			exit();
		}
		
	}// ef

	
	/**
	 * Shows Current Error String
	 * 
	 * @access public
	 *
	 */
	public function showError()
	{
		global $debug_mode;
		
		if( $debug_mode )
			echo $this->error_string;
		
	}// ef
	
	
	/**
	 * Shows a PNG image or a string with an error message
	 * if something has gone wrong during the image creation
	 * 
	 * @access private
	 */
	private function showImgError()
	{  
		
		// : Image size is a configuration option
		global $er_image_w;
		global $er_image_h;
		
		// :: Creating an empty image
		$im = imagecreate($er_image_w, $er_image_h);
		
		// : Color Allocation
		$bg_color    = imagecolorallocate($im, 160, 0, 0);// a kind of red
        $text_color  = imagecolorallocate($im, 240, 240, 240);// a kind of white
        
        // : Painting the background rectangle with $bg_color
        imagefilledrectangle($im, 0, 0, $er_image_w, $er_image_h, $bg_color);
       
        // : Writing a message on the canvas
        imagestring($im, 4, 20, 10, $this->error_string, $text_color);
        
        // :: Output, checks if headers are already sent
        if(!headers_sent())
        {
			header("Content-type: image/png");
			if(!@imagepng($im)) { $this->showError(); }
        }
        else { echo $this->showError(); }
        
		// :: Free
        imagedestroy($im);
    
	}// ef

	
	/**
	 * Class Destructor
	 * 
	 * @access public
	 */
	public function __destruct()
	{ 
		// If save() has not been called let's destroy the image resource
		if($this->im_resource)
		{
			@imagedestroy($this->im_resource);
		}
	
	}// ef

}// END OF CLASS
?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products