Image Manipulator (v0.5)
Item 4 of 9
1 <?php 2 3 4 /** 5 * Class: ImageManipulator 6 * 7 * Provides a small library of image manipulation functions using the inbuilt PHP/GD2 functions. 8 * 9 * @author Dan Pupius <www.pupius.co.uk> 10 * @version 0.5 11 * @copyright ©2003 Dan Pupius 12 * @package Utility 13 * @subpackage Classes 14 */ 15 16 class ImageManipulator { 17 18 /** 19 * @var string Location of current image 20 */ 21 var $curfile = ""; 22 23 /** 24 * @var string Filename of current image 25 */ 26 var $filename = ""; 27 28 /** 29 * @var string Extension of current image 30 */ 31 var $ext = ""; 32 33 /** 34 * @var mixed Resource holder for an image that is loaded into the object 35 */ 36 var $im = null; 37 38 /** 39 * @var int Number between 0 and 100 representing output quality of image 40 */ 41 var $quality = 80; 42 43 /** 44 * @var mixed RGB array representing the background colour used in fills 45 */ 46 var $bgcolor = array(0,0,0); 47 48 /** 49 * @var mixed RGB array representing the foreground colour used in borders and text 50 */ 51 var $color = array(200,200,200); 52 53 /** 54 * @var mixed Array of weights used when making an image grey scale. Preferably add to 3 to keep same overall gamma. 55 */ 56 var $gamma = array(1,1,1); //Represent RGB values. 57 58 59 60 /** 61 * Constructor function - if optional filename is sent then it will auto load the imaeg into the object 62 * 63 * @param string $img image path or url 64 * @return boolean Whether image was successfully loaded 65 * @access public 66 */ 67 function ImageManipulator($img="") { 68 if($img!="") return $this->load_image($img); 69 } 70 71 72 73 /** 74 * Loads an image file into the class 75 * 76 * @param string $img image path or url 77 * @return boolean Whether image was successfully loaded 78 * @access public 79 */ 80 function load_image($img) { 81 if(!file_exists($img) || !is_file($img)) return false; 82 $fileinfo = pathinfo($img); 83 84 $this->filename = $fileinfo["basename"]; 85 $this->ext = strtolower($fileinfo["extension"]); 86 87 //depending on the image type create 88 switch($this->ext) { 89 case "gif": $im = @imagecreatefromgif($img); break; 90 case "jpg": $im = @imagecreatefromjpeg($img); break; 91 case "png": $im = @imagecreatefrompng($img); break; 92 default: return false; 93 } 94 if(!$im) return false; 95 else $this->im = $im; 96 97 return true; 98 } 99 100 /** 101 * Destroys the image held in memory - always call this before the end of your script 102 * 103 * @access public 104 */ 105 function end() { 106 if(!$this->im) return false; 107 imagedestroy($this->im); 108 } 109 110 111 /** 112 * Resamples the current image to a specified size. This function does not take into accound aspect-ratio. 113 * 114 * @param integer $w Width of new image 115 * @param integer $h Height of new image 116 * @return boolean Whether resize was sucessful 117 * @access public 118 */ 119 function resample($w,$h) { 120 if(!$this->im) return false; 121 122 //create a destination image 123 $dest = imagecreatetruecolor($w,$h); 124 125 //try and resample 126 $r = imagecopyresampled($dest,$this->im,0,0,0,0,$w,$h,imagesx($this->im),imagesy($this->im)); 127 128 //resample was successful so replace original image with new one 129 if($r) { 130 imagedestroy($this->im); 131 $this->im = imagecreatetruecolor($w,$h); 132 imagecopy($this->im,$dest,0,0,0,0,$w,$h); 133 imagedestroy($dest); 134 return true; 135 } 136 137 //resample failed 138 else return false; 139 } 140 141 142 /** 143 * Uses resample to resize an image so that it fits inside a certain box while maintaining aspect 144 * ratio. If "clip "is true then it will resize to the smallest dimension and clip the remaining region. 145 * If "clip" is false (default) then it will center the image inside the box, and paint a background 146 * colour in the remaining area. 147 * 148 * @param integer $w Width of new image 149 * @param integer $h Height of new image 150 * @param boolean $noclip Whether to fill entire box or *clip* areas that overflow 151 * @param boolean $noenlarge If true then the file won't be enlarged to fit the spaec but rather sit in the middle 152 * @return boolean Whether it was sucessful 153 * @access public 154 */ 155 function resize_to_fit($w,$h,$noclip=true,$noenlarge=false) { 156 if(!$this->im) return false; 157 158 $curw = imagesx($this->im); 159 $curh = imagesy($this->im); 160 161 //create a destination image 162 $dest = imagecreatetruecolor($w,$h); 163 164 //set background colour 165 $bg = ImageColorAllocate($dest,$this->bgcolor[0],$this->bgcolor[1],$this->bgcolor[2]); 166 ImageFilledRectangle ($dest, 0, 0, $w, $h, $bg); 167 168 //if in clip mode then fit to shortest side, otherwise fit to longest 169 if( ($noclip && $curw/$w>=$curh/$h) || (!$noclip && $curw/$w < $curh/$h) ) { 170 $newh = $curh / ($curw/$w); 171 $neww = $w; 172 } else { 173 $neww = $curw / ($curh/$h); 174 $newh = $h; 175 } 176 177 //try and resample by resized region to middle of the image 178 if($curw<$w && $curh<$h && $noenlarge) $r = imagecopyresampled($dest,$this->im, ($w/2)-($curw/2), ($h/2)-($curh/2), 0, 0, $curw, $curh, $curw, $curh); //no resize just copy into middle of canvas 179 else $r = imagecopyresampled($dest,$this->im, ($w/2)-($neww/2), ($h/2)-($newh/2), 0, 0, $neww, $newh, $curw, $curh); //resize, up or down 180 181 //finish up if it worked 182 if($r) { 183 imagedestroy($this->im); 184 $this->im = imagecreatetruecolor($w,$h); 185 imagecopy($this->im,$dest,0,0,0,0,$w,$h); 186 imagedestroy($dest); 187 return true; 188 } 189 190 //resample failed 191 else return false; 192 193 } 194 195 /** 196 * Sets a specific RGB colour as transparent (only works when outputing as a PNG or GIF) 197 * 198 * @param integer $r Red value 199 * @param integer $g Green value 200 * @param integer $b Blue value 201 * @return boolean Whether it was sucessful 202 * @access public 203 */ 204 function set_transparency($r=0,$g=0,$b=0) { 205 if(!$this->im) return false; 206 207 //find the index of the colour to make transparent, if it doesn't exist then exit. 208 $index = imagecolorexact($this->im,$r,$g,$b); 209 if($index==-1) return false; 210 211 //set the transparency 212 imagecolortransparent($this->im,$index); 213 214 return true; 215 } 216 217 218 219 /** 220 * Desaturates an image, id optional $shade variable = 0 then image will be grey scale, 1 = red, 2 = greem 3 = blue 221 * 222 * NOTE: By adjusting the weight array prior to desaturating the image you can split the channels of an image. 223 * 224 * @param integer $shade What colour to shade the image 225 * @return boolean Whether it was sucessful 226 * @access public 227 */ 228 function desaturate($shade=0){ 229 if(!$this->im) return false; 230 231 //convert o,age to 256 colours 232 ImageTrueColorToPalette($this->im,1,256); 233 234 //calculate total number of colours in palette 235 $total = ImageColorsTotal($this->im); 236 237 //for each colour make it grey 238 for($i=0;$i<$total;$i++){ 239 $old = ImageColorsForIndex($this->im,$i); 240 241 //get correct colouring by performing a weighted average of the 3 242 $grey = round(($this->gamma[0]*$old["red"] + $this->gamma[1]*$old["green"] + $this->gamma[2]*$old["blue"]) / 3); 243 244 if($shade==1) ImageColorSet($this->im,$i,$grey,0,0); 245 else if($shade==2) ImageColorSet($this->im,$i,0,$grey,0); 246 else if($shade==3) ImageColorSet($this->im,$i,0,0,$grey); 247 else ImageColorSet($this->im,$i,$grey,$grey,$grey); 248 } 249 250 return true; 251 } 252 253 /** 254 * Converts an image to n-colours 255 * 256 * @param integer $colors Number of colours in pallete 257 * @return boolean Whether it was sucessful 258 * @access public 259 */ 260 function reduce_colors($colors=255) { 261 //convert o,age to 256 colours 262 if(!function_exists("ImageTrueColorToPalette")) return false; 263 ImageTrueColorToPalette($this->im,1,$colors); 264 return true; 265 } 266 267 /** 268 * Draws a border round the edge of the image using the $color variable storred in the object 269 * 270 * @param integer $size Border size in pixels 271 * @return boolean Whether it was sucessful 272 * @access public 273 */ 274 function draw_border($size) { 275 if(!$this->im) return false; 276 277 //rectangle works out 1px bigger than you'd expect so... 278 $size = $size-1; 279 280 //get image size 281 $w = imagesx($this->im); 282 $h = imagesy($this->im); 283 284 //get the border colour 285 $c = imagecolorallocate($this->im,$this->color[0],$this->color[1],$this->color[2]); 286 287 //draw lines 288 ImageFilledRectangle($this->im,0,0,$w,$size,$c); //top border 289 ImageFilledRectangle($this->im,0,$h-$size-1,$w,$h,$c); //bottom border 290 ImageFilledRectangle($this->im,0,0,$size,$h,$c); //left border 291 ImageFilledRectangle($this->im,$w-$size-1,0,$w,$h,$c); //right border 292 293 return true; 294 } 295 296 297 /** 298 * sends the image currently storred within this object as a jpeg to the output buffer (headers included) 299 * 300 * @return boolean Whether ouput was sucessful 301 * @access public 302 */ 303 function output_jpeg() { 304 if(!$this->im || !function_exists("imagejpeg")) return false; 305 header('Content-Type: image/jpeg'); 306 header("Content-Disposition: inline; filename={$this->filename}.jpg"); //neat header to tell the browser what the filename should be 307 imagejpeg($this->im,"",$this->quality); 308 return true; 309 } 310 311 /** 312 * sends the image currently storred within this object as a png to the output buffer (headers included) 313 * 314 * @return boolean Whether ouput was sucessful 315 * @access public 316 */ 317 function output_png() { 318 if(!$this->im || !function_exists("imagepng")) return false; 319 header('Content-Type: image/jpeg'); 320 header("Content-Disposition: inline; filename={$this->filename}.png"); 321 imagepng($this->im); 322 return true; 323 } 324 325 /** 326 * Saves the image currently storred within this object as a jpeg on the local file system 327 * 328 * @return boolean Whether save was sucessful 329 * @access public 330 */ 331 function save_jpeg($filename) { 332 if(!$this->im || !function_exists("imagejpeg")) return false; 333 imagejpeg($this->im,$filename,$this->quality); 334 return true; 335 } 336 337 /** 338 * Saves the image currently storred within this object as a png on the local file system 339 * 340 * @return boolean Whether sav was sucessful 341 * @access public 342 */ 343 function save_png($filename) { 344 if(!$this->im || !function_exists("imagepng")) return false; 345 imagepng($this->im,$filename); 346 return true; 347 } 348 } 349 350 //DEMO: 351 /* 352 $i = new ImageManipulator("balls.jpg"); 353 $i->resize_to_fit(640,480,false,true); //resize image to 640x480, but make sure image isn't clipped and if it's smaller than 640x480 just increase the canvas 354 $i->color = array(255,255,255); //set foreground colour to white 355 $i->draw_border(15); //draw a 15px border 356 $i->color = array(0,0,0); //set foreground to black 357 $i->draw_border(1); //draw 1px border 358 $i->output_jpeg(); //output image as jpeg 359 $i->end(); //ensure memory is freed up 360 */ 361 362 ?> 363