image_moo.php 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2. /*
  3. * Image_Moo library
  4. *
  5. * Written due to image_lib not being so nice when you have to do multiple things to a single image!
  6. *
  7. * @license MIT License
  8. * @author Matthew Augier, aka Mat-Moo
  9. * @link http://www.dps.uk.com
  10. * @docu http://todo :)
  11. * @email matthew@dps.uk.com
  12. *
  13. * @file image_moo.php
  14. * @version 1.0.1
  15. * @date 2010 Dec 13
  16. *
  17. * Copyright (c) 2010 Matthew Augier
  18. *
  19. * Requires PHP 5 and GD2!
  20. *
  21. * Example usage
  22. * $this->image_moo->load("file")->resize(64,40)->save("thumb")->resize(640,480)->save("medium");
  23. * if ($this->image_moo->errors) print $this->image_moo->display_errors();
  24. *
  25. * COLOURS!
  26. * Any function that can take a colour as a parameter can take "#RGB", "#RRGGBB" or an array(R,G,B)
  27. *
  28. * image manipulation functions
  29. * -----------------------------------------------------------------------------
  30. * load($x) - Loads an image file specified by $x - JPG, PNG, GIF supported
  31. * save($x) - Saved the manipulated image (if applicable) to file $x - JPG, PNG, GIF supported
  32. * save_pa($prepend="", $append="", $overwrite=FALSE) - Saves using the original image name but with prepend and append text, e.g. load('moo.jpg')->save_pa('pre_','_app') would save as filename pre_moo_app.jpg
  33. * save_dynamic($filename="") - Saves as a stream output, use filename to return png/jpg/gif etc., default is jpeg
  34. * resize($x,$y,$pad=FALSE) - Proportioanlly resize original image using the bounds $x and $y, if padding is set return image is as defined centralised using BG colour
  35. * resize_crop($x,$y) - Proportioanlly resize original image using the bounds $x and $y but cropped to fill dimensions
  36. * stretch($x,$y) - Take the original image and stretch it to fill new dimensions $x $y
  37. * crop($x1,$y1,$x2,$y2) - Crop the original image using Top left, $x1,$y1 to bottom right $x2,y2. New image size =$x2-x1 x $y2-y1
  38. * rotate($angle) - Rotates the work image by X degrees, normally 90,180,270 can be any angle.Excess filled with background colour
  39. * load_watermark($filename, $transparent_x=0, $transparent_y=0) - Loads the specified file as the watermark file, if using PNG32/24 use x,y to specify direct positions of colour to use as index
  40. * make_watermark_text($text, $fontfile, $size=16, $colour="#ffffff", $angle=0) - Creates a text watermark
  41. * watermark($position, $offset=8, $abs=FALSE) - Use the loaded watermark, or created text to place a watermark. $position works like NUM PAD key layout, e.g. 7=Top left, 3=Bottom right $offset is the padding/indentation, if $abs is true then use $positiona and $offset as direct values to watermark placement
  42. * border($width,$colour="#000") - Draw a border around the output image X pixels wide in colour specified
  43. * border_3d($width,$rot=0,$opacity=30) - Draw a 3d border (opaque) around the current image $width wise in 0-3 rot positions, $opacity allows you to change how much it effects the picture
  44. * filter($function, $arg1=NULL, $arg2=NULL, $arg3=NULL, $arg4=NULL) -Runs the standard imagefilter GD2 command, see http://www.php.net/manual/en/function.imagefilter.php for details
  45. * round($radius,$invert=FALSE,$corners(array[top left, top right, bottom right, bottom left of true or False)="") default is all on and normal rounding
  46. * shadow($size=4, $direction=3, $colour="#444") - Size in pixels, note that the image will increase by this size, so resize(400,400)->shadoe(4) will give an image 404 pixels in size, Direction works on teh keypad basis like the watermark, so 3 is bottom right, $color if the colour of the shadow.
  47. * -----------------------------------------------------------------------------
  48. * image helper functions
  49. * display_errors($open = '<p>', $close = '</p>') - Display errors as Ci standard style
  50. * set_jpeg_quality($x) - quality to wrte jpeg files in for save, default 75 (1-100)
  51. * set_watermark_transparency($x) - the opacity of the watermark 1-100, 1-just about see, 100=solid
  52. * check_gd() - Run to see if you server can use this library
  53. * clear_temp() - Call to clear the temp changes using the master image again
  54. * clear() - Clears all images in memory
  55. * -----------------------------------------------------------------------------
  56. *
  57. * KNOWN BUGS
  58. * make_watermark_text does not deal with rotation angle correctly, box is cropped
  59. *
  60. * TO DO
  61. *
  62. * THANKS
  63. * Matjaž for poiting out the save_pa bug (should of tested it!)
  64. * Cahva for posting yet another bug in the save_pa (Man I can be silly sometimes!)
  65. * Cole spotting the resize flaw and providing a fix
  66. *
  67. */
  68. class Image_moo
  69. {
  70. // image vars
  71. private $main_image="";
  72. private $watermark_image;
  73. private $temp_image;
  74. private $jpeg_quality=75;
  75. private $background_colour="#ffffff";
  76. private $watermark_method;
  77. // other
  78. private $filename="";
  79. // watermark stuff, opacity
  80. private $watermark_transparency=50;
  81. // reported errors
  82. public $errors=FALSE;
  83. private $error_msg = array();
  84. // image info
  85. public $width=0;
  86. public $height=0;
  87. function Image_moo()
  88. //----------------------------------------------------------------------------------------------------------
  89. // create stuff here as needed
  90. //----------------------------------------------------------------------------------------------------------
  91. {
  92. log_message('debug', "Image Moo Class Initialized");
  93. }
  94. private function _clear_errors()
  95. //----------------------------------------------------------------------------------------------------------
  96. // load a resource
  97. //----------------------------------------------------------------------------------------------------------
  98. {
  99. $this->error_msg = array();
  100. }
  101. private function set_error($msg)
  102. //----------------------------------------------------------------------------------------------------------
  103. // Set an error message
  104. //----------------------------------------------------------------------------------------------------------
  105. {
  106. $this->errors = TRUE;
  107. $this->error_msg[] = $msg;
  108. }
  109. public function display_errors($open = '<p>', $close = '</p>')
  110. //----------------------------------------------------------------------------------------------------------
  111. // returns the errors formatted as needed, same as CI doed
  112. //----------------------------------------------------------------------------------------------------------
  113. {
  114. $str = '';
  115. foreach ($this->error_msg as $val)
  116. {
  117. $str .= $open.$val.$close;
  118. }
  119. return $str;
  120. }
  121. public function check_gd()
  122. //----------------------------------------------------------------------------------------------------------
  123. // verification util to see if you can use image_moo
  124. //----------------------------------------------------------------------------------------------------------
  125. {
  126. if ( ! extension_loaded('gd'))
  127. {
  128. if ( ! dl('gd.so'))
  129. {
  130. $this->set_error('GD library does not appear to be loaded');
  131. return FALSE;
  132. }
  133. }
  134. if (function_exists('gd_info'))
  135. {
  136. $gdarray = @gd_info();
  137. $versiontxt = ereg_replace('[[:alpha:][:space:]()]+', '', $gdarray['GD Version']);
  138. $versionparts=explode('.',$versiontxt);
  139. if ($versionparts[0]=="2")
  140. {
  141. return TRUE;
  142. }
  143. else
  144. {
  145. $this->set_error('Requires GD2, this reported as '.$versiontxt);
  146. return FALSE;
  147. }
  148. }
  149. else
  150. {
  151. $this->set_error('Could not verify GD version');
  152. return FALSE;
  153. }
  154. }
  155. private function _check_image()
  156. //----------------------------------------------------------------------------------------------------------
  157. // checks that we have an image loaded
  158. //----------------------------------------------------------------------------------------------------------
  159. {
  160. if (!is_resource($this->main_image))
  161. {
  162. $this->set_error("No main image loaded!");
  163. return FALSE;
  164. }
  165. else
  166. {
  167. return TRUE;
  168. }
  169. }
  170. function save_dynamic($filename="")
  171. //----------------------------------------------------------------------------------------------------------
  172. // Saves the temp image as a dynamic image
  173. // e.g. direct output to the browser
  174. //----------------------------------------------------------------------------------------------------------
  175. {
  176. // validate we loaded a main image
  177. if (!$this->_check_image()) return $this;
  178. // if no operations, copy it for temp save
  179. $this->_copy_to_temp_if_needed();
  180. // ok, lets go!
  181. if ($filename=="") $filename=rand(1000,999999).".jpg"; // send as jpeg
  182. $ext = strtoupper(pathinfo($filename, PATHINFO_EXTENSION));
  183. header("Content-disposition: filename=$filename;");
  184. header('Content-transfer-Encoding: binary');
  185. header('Last-modified: '.gmdate('D, d M Y H:i:s'));
  186. switch ($ext)
  187. {
  188. case "GIF" :
  189. header("Content-type: image/gif");
  190. imagegif($this->temp_image);
  191. return $this;
  192. break;
  193. case "JPG" :
  194. case "JPEG" :
  195. header("Content-type: image/jpeg");
  196. imagejpeg($this->temp_image, NULL, $this->jpeg_quality);
  197. return $this;
  198. break;
  199. case "PNG" :
  200. header("Content-type: image/png");
  201. imagepng($this->temp_image);
  202. return $this;
  203. break;
  204. }
  205. $this->set_error('Unable to save, extension not GIF/JPEG/JPG/PNG');
  206. return $this;
  207. }
  208. function save_pa($prepend="", $append="", $overwrite=FALSE)
  209. //----------------------------------------------------------------------------------------------------------
  210. // Saves the temp image as the filename specified,
  211. // overwrite = true of false
  212. //----------------------------------------------------------------------------------------------------------
  213. {
  214. // validate we loaded a main image
  215. if (!$this->_check_image()) return $this;
  216. // get current file parts
  217. $parts=pathinfo($this->filename);
  218. // save
  219. $this->save($parts["dirname"].'/'.$prepend.$parts['filename'].$append.'.'.$parts["extension"], $overwrite);
  220. return $this;
  221. }
  222. function save($filename,$overwrite=FALSE)
  223. //----------------------------------------------------------------------------------------------------------
  224. // Saves the temp image as the filename specified,
  225. // overwrite = true of false
  226. //----------------------------------------------------------------------------------------------------------
  227. {
  228. // validate we loaded a main image
  229. if (!$this->_check_image()) return $this;
  230. // if no operations, copy it for temp save
  231. $this->_copy_to_temp_if_needed();
  232. // check if it already exists
  233. if (!$overwrite)
  234. {
  235. // don't overwrite, so check for file
  236. if (file_exists($filename))
  237. {
  238. $this->set_error('File exists, overwrite is FALSE, could not save over file '.$filename);
  239. return $this;
  240. }
  241. }
  242. // find out the type of file to save
  243. $ext = strtoupper(pathinfo($filename, PATHINFO_EXTENSION));
  244. switch ($ext)
  245. {
  246. case "GIF" :
  247. imagegif($this->temp_image, $filename);
  248. return $this;
  249. break;
  250. case "JPG" :
  251. case "JPEG" :
  252. imagejpeg($this->temp_image, $filename, $this->jpeg_quality);
  253. return $this;
  254. break;
  255. case "PNG" :
  256. imagepng($this->temp_image, $filename);
  257. return $this;
  258. break;
  259. }
  260. // invalid filetype?!
  261. $this->set_error('Do no know what '.$ext.' filetype is in filename '.$filename);
  262. return $this;
  263. }
  264. private function _load_image($filename)
  265. //----------------------------------------------------------------------------------------------------------
  266. // private function to load a resource
  267. //----------------------------------------------------------------------------------------------------------
  268. {
  269. // check the request file can be located
  270. if (!file_exists($filename))
  271. {
  272. $this->set_error('Could not locate file '.$filename);
  273. return FALSE;
  274. }
  275. // get image info about this file
  276. $image_info=getimagesize($filename);
  277. // load file depending on mimetype
  278. switch ($image_info["mime"])
  279. {
  280. case "image/gif" :
  281. return imagecreatefromgif($filename);
  282. break;
  283. case "image/jpeg" :
  284. return imagecreatefromjpeg($filename);
  285. break;
  286. case "image/png" :
  287. return imagecreatefrompng($filename);
  288. break;
  289. }
  290. // invalid filetype?!
  291. $this->set_error('Unable to load '.$filename.' filetype '.$image_info["mime"].'not recognised');
  292. return FALSE;
  293. }
  294. public function load($filename)
  295. //----------------------------------------------------------------------------------------------------------
  296. // Load an image, public function
  297. //----------------------------------------------------------------------------------------------------------
  298. {
  299. // new image, reset error messages
  300. $this->_clear_errors();
  301. // remove temporary image stored
  302. $this->clear_temp();
  303. // save filename
  304. $this->filename=$filename;
  305. // reset width and height
  306. $this->width = 0;
  307. $this->height = 0;
  308. // load it
  309. $this->main_image = $this->_load_image($filename);
  310. // no error, then get the dminesions set
  311. if ($this->main_image <> FALSE)
  312. {
  313. $this->width = imageSX($this->main_image);
  314. $this->height = imageSY($this->main_image);
  315. }
  316. // return the object
  317. return $this;
  318. }
  319. public function load_watermark($filename, $transparent_x=NULL, $transparent_y=NULL)
  320. //----------------------------------------------------------------------------------------------------------
  321. // Load an image, public function
  322. //----------------------------------------------------------------------------------------------------------
  323. {
  324. if(is_resource($this->watermark_image)) imagedestroy($this->watermark_image);
  325. $this->watermark_image = $this->_load_image($filename);
  326. if(is_resource($this->watermark_image))
  327. {
  328. $this->watermark_method = 1;
  329. if(($transparent_x <> NULL) AND ($transparent_y <> NULL))
  330. {
  331. // get the top left corner colour allocation
  332. $tpcolour = imagecolorat($this->watermark_image, $transparent_x, $transparent_y);
  333. // set this as the transparent colour
  334. imagecolortransparent($this->watermark_image, $tpcolour);
  335. // $set diff method
  336. $this->watermark_method = 2;
  337. }
  338. }
  339. // return this object
  340. return $this;
  341. }
  342. public function set_watermark_transparency($transparency=50)
  343. //----------------------------------------------------------------------------------------------------------
  344. // Sets the quality that jpeg will be saved at
  345. //----------------------------------------------------------------------------------------------------------
  346. {
  347. $this->watermark_transparency = $transparency;
  348. return $this;
  349. }
  350. public function set_background_colour($colour="#ffffff")
  351. //----------------------------------------------------------------------------------------------------------
  352. // Sets teh background colour to use on rotation and padding for resize
  353. //----------------------------------------------------------------------------------------------------------
  354. {
  355. $this->background_colour = $this->_html2rgb($colour);
  356. return $this;
  357. }
  358. public function set_jpeg_quality($quality=75)
  359. //----------------------------------------------------------------------------------------------------------
  360. // Sets the quality that jpeg will be saved at
  361. //----------------------------------------------------------------------------------------------------------
  362. {
  363. $this->jpeg_quality = $quality;
  364. return $this;
  365. }
  366. private function _copy_to_temp_if_needed()
  367. //----------------------------------------------------------------------------------------------------------
  368. // If temp image is empty, e.g. not resized or done anything then just copy main image
  369. //----------------------------------------------------------------------------------------------------------
  370. {
  371. if (!is_resource($this->temp_image))
  372. {
  373. // create a temp based on new dimensions
  374. $this->temp_image = imagecreatetruecolor($this->width, $this->height);
  375. // check it
  376. if(!is_resource($this->temp_image))
  377. {
  378. $this->set_error('Unable to create temp image sized '.$this->width.' x '.$this->height);
  379. return FALSE;
  380. }
  381. // copy image to temp workspace
  382. imagecopy($this->temp_image, $this->main_image, 0, 0, 0, 0, $this->width, $this->height);
  383. }
  384. }
  385. public function clear()
  386. //----------------------------------------------------------------------------------------------------------
  387. // clear everything!
  388. //----------------------------------------------------------------------------------------------------------
  389. {
  390. if(is_resource($this->main_image)) imagedestroy($this->main_image);
  391. if(is_resource($this->watermark_image)) imagedestroy($this->watermark_image);
  392. if(is_resource($this->temp_image)) imagedestroy($this->temp_image);
  393. return $this;
  394. }
  395. public function clear_temp()
  396. //----------------------------------------------------------------------------------------------------------
  397. // you may want to revert back to teh original image to work on, e.g. watermark, this clears temp
  398. //----------------------------------------------------------------------------------------------------------
  399. {
  400. if(is_resource($this->temp_image)) imagedestroy($this->temp_image);
  401. return $this;
  402. }
  403. public function resize_crop($mw,$mh)
  404. //----------------------------------------------------------------------------------------------------------
  405. // take main image and resize to tempimage using EXACT boundaries mw,mh (max width and max height)
  406. // this is proportional and crops the image centrally to fit
  407. //----------------------------------------------------------------------------------------------------------
  408. {
  409. if (!$this->_check_image()) return $this;
  410. // clear temp image
  411. $this->clear_temp();
  412. // create a temp based on new dimensions
  413. $this->temp_image = imagecreatetruecolor($mw,$mh);
  414. // check it
  415. if(!is_resource($this->temp_image))
  416. {
  417. $this->set_error('Unable to create temp image sized '.$mw.' x '.$mh);
  418. return $this;
  419. }
  420. // work out best positions for copy
  421. $wx=$this->width / $mw;
  422. $wy=$this->height / $mh;
  423. if ($wx >= $wy)
  424. {
  425. // use full height
  426. $sy = 0;
  427. $sy2 = $this->height;
  428. // calcs
  429. $calc_width = $mw * $wy;
  430. $sx = ($this->width - $calc_width) / 2;
  431. $sx2 = $calc_width;
  432. }
  433. else
  434. {
  435. // use full width
  436. $sx = 0;
  437. $sx2 = $this->width;
  438. // calcs
  439. $calc_height = $mh * $wx;
  440. $sy = ($this->height - $calc_height) / 2;
  441. $sy2 = $calc_height;
  442. }
  443. // copy section
  444. imagecopyresampled($this->temp_image, $this->main_image, 0, 0, $sx, $sy, $mw, $mh, $sx2, $sy2);
  445. return $this;
  446. }
  447. public function resize($mw, $mh, $pad=FALSE)
  448. //----------------------------------------------------------------------------------------------------------
  449. // take main image and resize to tempimage using boundaries mw,mh (max width or max height)
  450. // this is proportional, pad to true will set it in the middle of area size
  451. //----------------------------------------------------------------------------------------------------------
  452. {
  453. if (!$this->_check_image()) return $this;
  454. // calc new dimensions
  455. if( $this->width > $mw || $this->height > $mh ) {
  456. // if( $this->width > $this->height ) { could calc wronf - Cole Thorsen swapped to his suggestion
  457. if( ($this->width / $this->height) > ($mw / $mh) ) {
  458. $tnw = $mw;
  459. $tnh = $tnw * $this->height / $this->width;
  460. } else {
  461. $tnh = $mh;
  462. $tnw = $tnh * $this->width / $this->height;
  463. }
  464. } else {
  465. $tnw = $this->width;
  466. $tnh = $this->height;
  467. }
  468. // clear temp image
  469. $this->clear_temp();
  470. // create a temp based on new dimensions
  471. if ($pad)
  472. {
  473. $tx = $mw;
  474. $ty = $mh;
  475. $px = ($mw - $tnw) / 2;
  476. $py = ($mh - $tnh) / 2;
  477. }
  478. else
  479. {
  480. $tx = $tnw;
  481. $ty = $tnh;
  482. $px = 0;
  483. $py = 0;
  484. }
  485. $this->temp_image = imagecreatetruecolor($tx,$ty);
  486. // check it
  487. if(!is_resource($this->temp_image))
  488. {
  489. $this->set_error('Unable to create temp image sized '.$tx.' x '.$ty);
  490. return $this;
  491. }
  492. // if padding, fill background
  493. if ($pad)
  494. {
  495. $col = $this->_html2rgb($this->background_colour);
  496. $bg = imagecolorallocate($this->temp_image, $col[0], $col[1], $col[2]);
  497. imagefilledrectangle($this->temp_image, 0, 0, $tx, $ty, $bg);
  498. }
  499. // copy resized
  500. imagecopyresampled($this->temp_image, $this->main_image, $px, $py, 0, 0, $tnw, $tnh, $this->width, $this->height);
  501. return $this;
  502. }
  503. public function stretch($mw,$mh)
  504. //----------------------------------------------------------------------------------------------------------
  505. // take main image and resize to tempimage using boundaries mw,mh (max width or max height)
  506. // does not retain proportions
  507. //----------------------------------------------------------------------------------------------------------
  508. {
  509. if (!$this->_check_image()) return $this;
  510. // clear temp image
  511. $this->clear_temp();
  512. // create a temp based on new dimensions
  513. $this->temp_image = imagecreatetruecolor($mw, $mh);
  514. // check it
  515. if(!is_resource($this->temp_image))
  516. {
  517. $this->set_error('Unable to create temp image sized '.$mh.' x '.$mw);
  518. return $this;
  519. }
  520. // copy resized (stethced, proportions not kept);
  521. imagecopyresampled($this->temp_image, $this->main_image, 0, 0, 0, 0, $mw, $mh, $this->width, $this->height);
  522. return $this;
  523. }
  524. public function crop($x1, $y1, $x2, $y2)
  525. //----------------------------------------------------------------------------------------------------------
  526. // crop the main image to temp image using coords
  527. //----------------------------------------------------------------------------------------------------------
  528. {
  529. if (!$this->_check_image()) return $this;
  530. // clear temp image
  531. $this->clear_temp();
  532. // check dimensions
  533. if ($x1 < 0 || $y1 < 0 || $x2 - $x1 > $this->width || $y2 - $y1 > $this->height)
  534. {
  535. $this->set_error('Invalid crop dimensions, either - passed or width/heigh too large '.$x1.'/'.$y1.' x '.$x2.'/'.$y2);
  536. return $this;
  537. }
  538. // create a temp based on new dimensions
  539. $this->temp_image = imagecreatetruecolor($x2-$x1, $y2-$y1);
  540. // check it
  541. if(!is_resource($this->temp_image))
  542. {
  543. $this->set_error('Unable to create temp image sized '.$x2-$x1.' x '.$y2-$y1);
  544. return $this;
  545. }
  546. // copy cropped portion
  547. imagecopy($this->temp_image, $this->main_image, 0, 0, $x1, $y1, $x2 - $x1, $y2 - $y1);
  548. return $this;
  549. }
  550. private function _html2rgb($colour)
  551. //----------------------------------------------------------------------------------------------------------
  552. // convert #aa0011 to a php colour array
  553. //----------------------------------------------------------------------------------------------------------
  554. {
  555. if (is_array($colour))
  556. {
  557. if (count($colour)==3) return $colour; // rgb sent as an array so use it
  558. $this->set_error('Colour error, array sent not 3 elements, expected array(r,g,b)');
  559. return false;
  560. }
  561. if ($colour[0] == '#')
  562. $colour = substr($colour, 1);
  563. if (strlen($colour) == 6)
  564. {
  565. list($r, $g, $b) = array($colour[0].$colour[1],
  566. $colour[2].$colour[3],
  567. $colour[4].$colour[5]);
  568. }
  569. elseif (strlen($colour) == 3)
  570. {
  571. list($r, $g, $b) = array($colour[0].$colour[0], $colour[1].$colour[1], $colour[2].$colour[2]);
  572. }
  573. else
  574. {
  575. $this->set_error('Colour error, value sent not #RRGGBB or RRGGBB, and not array(r,g,b)');
  576. return false;
  577. }
  578. $r = hexdec($r); $g = hexdec($g); $b = hexdec($b);
  579. return array($r, $g, $b);
  580. }
  581. public function rotate($angle)
  582. //----------------------------------------------------------------------------------------------------------
  583. // rotate an image bu 0 / 90 / 180 / 270 degrees
  584. //----------------------------------------------------------------------------------------------------------
  585. {
  586. // validate we loaded a main image
  587. if (!$this->_check_image()) return $this;
  588. // if no operations, copy it for temp save
  589. $this->_copy_to_temp_if_needed();
  590. // set the colour
  591. $col = $this->_html2rgb($$this->background_colour);
  592. $bg = imagecolorallocate($this->temp_image, $col[0], $col[1], $col[2]);
  593. // rotate as needed
  594. $this->temp_image = imagerotate($this->temp_image, $angle, $bg);
  595. return $this;
  596. }
  597. public function make_watermark_text($text, $fontfile, $size=16, $colour="#ffffff", $angle=0)
  598. //----------------------------------------------------------------------------------------------------------
  599. // create an image from text that can be applied as a watermark
  600. // text is the text to write, $fontile is a ttf file that will be used $size=font size, $colour is the colour of text
  601. //----------------------------------------------------------------------------------------------------------
  602. {
  603. // check font file can be found
  604. if (!file_exists($fontfile))
  605. {
  606. $this->set_error('Could not locate font file "'.$fontfile.'"');
  607. return $this;
  608. }
  609. // validate we loaded a main image
  610. if (!$this->_check_image())
  611. {
  612. $remove = TRUE;
  613. // no image loaded so make temp image to use
  614. $this->main_image = imagecreatetruecolor(1000,1000);
  615. }
  616. else
  617. {
  618. $remove = FALSE;
  619. }
  620. // work out text dimensions
  621. $bbox = imageftbbox($size, $angle, $fontfile, $text);
  622. $bw = abs($bbox[4] - $bbox[0]) + 1;
  623. $bh = abs($bbox[1] - $bbox[5]) + 1;
  624. $bl = $bbox[1];
  625. // use this to create watermark image
  626. if(is_resource($this->watermark_image)) imagedestroy($this->watermark_image);
  627. $this->watermark_image = imagecreatetruecolor($bw, $bh);
  628. // set colours
  629. $col = $this->_html2rgb($colour);
  630. $font_col = imagecolorallocate($this->watermark_image, $col[0], $col[1], $col[2]);
  631. $bg_col = imagecolorallocate($this->watermark_image, 127, 128, 126);
  632. // set method to use
  633. $this->watermark_method = 2;
  634. // create bg
  635. imagecolortransparent($this->watermark_image, $bg_col);
  636. imagefilledrectangle($this->watermark_image, 0,0, $bw, $bh, $bg_col);
  637. // write text to watermark
  638. imagefttext($this->watermark_image, $size, $angle, 0, $bh-$bl, $font_col, $fontfile, $text);
  639. if ($remove) imagedestroy($this->main_image);
  640. return $this;
  641. }
  642. public function watermark($position, $offset=8, $abs=FALSE)
  643. //----------------------------------------------------------------------------------------------------------
  644. // add a watermark to the image
  645. // position works like a keypad e.g.
  646. // 7 8 9
  647. // 4 5 6
  648. // 1 2 3
  649. // offset moves image inwards by x pixels
  650. // if abs is set then $position, $offset = direct placement coords
  651. //----------------------------------------------------------------------------------------------------------
  652. {
  653. // validate we loaded a main image
  654. if (!$this->_check_image()) return $this;
  655. // validate we have a watermark
  656. if(!is_resource($this->watermark_image))
  657. {
  658. $this->set_error("Can't watermark image, no watermark loaded/created");
  659. return $this;
  660. }
  661. // if no operations, copy it for temp save
  662. $this->_copy_to_temp_if_needed();
  663. // get watermark width
  664. $wm_w = imageSX($this->watermark_image);
  665. $wm_h = imageSY($this->watermark_image);
  666. // get temp widths
  667. $temp_w = imageSX($this->temp_image);
  668. $temp_h = imageSY($this->temp_image);
  669. // check watermark will fit!
  670. if ($wm_w > $temp_w || $wm_h > $temp_h)
  671. {
  672. $this->set_error("Watermark is larger than image. WM: $wm_w x $wm_h Temp image: $temp_w x $temp_h");
  673. return $this;
  674. }
  675. if ($abs)
  676. {
  677. // direct placement
  678. $dest_x = $position;
  679. $dest_y = $offset;
  680. }
  681. else
  682. {
  683. // do X position
  684. switch ($position)
  685. {
  686. // x left
  687. case "7":
  688. case "4":
  689. case "1":
  690. $dest_x = $offset;
  691. break;
  692. // x middle
  693. case "8":
  694. case "5":
  695. case "2":
  696. $dest_x = ($temp_w - $wm_w) /2 ;
  697. break;
  698. // x right
  699. case "9":
  700. case "6":
  701. case "3":
  702. $dest_x = $temp_w - $offset - $wm_w;
  703. break;
  704. default:
  705. $dest_x = $offset;
  706. $this->set_error("Watermark position $position not in vlaid range 7,8,9 - 4,5,6 - 1,2,3");
  707. }
  708. // do y position
  709. switch ($position)
  710. {
  711. // y top
  712. case "7":
  713. case "8":
  714. case "9":
  715. $dest_y = $offset;
  716. break;
  717. // y middle
  718. case "4":
  719. case "5":
  720. case "6":
  721. $dest_y = ($temp_h - $wm_h) /2 ;
  722. break;
  723. // y bottom
  724. case "1":
  725. case "2":
  726. case "3":
  727. $dest_y = $temp_h - $offset - $wm_h;
  728. break;
  729. default:
  730. $dest_y = $offset;
  731. $this->set_error("Watermark position $position not in vlaid range 7,8,9 - 4,5,6 - 1,2,3");
  732. }
  733. }
  734. // copy over temp image to desired location
  735. if ($this->watermark_method == 1)
  736. {
  737. // use back methods to do this, taken from php help files
  738. //$this->imagecopymerge_alpha($this->temp_image, $this->watermark_image, $dest_x, $dest_y, 0, 0, $wm_w, $wm_h, $this->watermark_transparency);
  739. $opacity=$this->watermark_transparency;
  740. // creating a cut resource
  741. $cut = imagecreatetruecolor($wm_w, $wm_h);
  742. // copying that section of the background to the cut
  743. imagecopy($cut, $this->temp_image, 0, 0, $dest_x, $dest_y, $wm_w, $wm_h);
  744. // inverting the opacity
  745. $opacity = 100 - $opacity;
  746. // placing the watermark now
  747. imagecopy($cut, $this->watermark_image, 0, 0, 0, 0, $wm_w, $wm_h);
  748. imagecopymerge($this->temp_image, $cut, $dest_x, $dest_y, 0, 0, $wm_w, $wm_h, $opacity);
  749. }
  750. else
  751. {
  752. // use normal with selected transparency colour
  753. imagecopymerge($this->temp_image, $this->watermark_image, $dest_x, $dest_y, 0, 0, $wm_w, $wm_h, $this->watermark_transparency);
  754. }
  755. return $this;
  756. }
  757. public function border($width=5,$colour="#000")
  758. //----------------------------------------------------------------------------------------------------------
  759. // add a solidborder frame, coloured $colour to the image
  760. //----------------------------------------------------------------------------------------------------------
  761. {
  762. // validate we loaded a main image
  763. if (!$this->_check_image()) return $this;
  764. // if no operations, copy it for temp save
  765. $this->_copy_to_temp_if_needed();
  766. // get colour set for temp image
  767. $col = $this->_html2rgb($colour);
  768. $border_col = imagecolorallocate($this->temp_image, $col[0], $col[1], $col[2]);
  769. // get temp widths
  770. $temp_w = imageSX($this->temp_image);
  771. $temp_h = imageSY($this->temp_image);
  772. // do border
  773. for($x=0;$x<$width;$x++)
  774. {
  775. imagerectangle($this->temp_image, $x, $x, $temp_w-$x-1, $temp_h-$x-1, $border_col);
  776. }
  777. // return object
  778. return $this;
  779. }
  780. public function border_3d($width=5,$rot=0,$opacity=30)
  781. //----------------------------------------------------------------------------------------------------------
  782. // overlay a black white border to make it look 3d
  783. //----------------------------------------------------------------------------------------------------------
  784. {
  785. // validate we loaded a main image
  786. if (!$this->_check_image()) return $this;
  787. // if no operations, copy it for temp save
  788. $this->_copy_to_temp_if_needed();
  789. // get temp widths
  790. $temp_w = imageSX($this->temp_image);
  791. $temp_h = imageSY($this->temp_image);
  792. // create temp canvas to merge
  793. $border_image = imagecreatetruecolor($temp_w, $temp_h);
  794. // create colours
  795. $black = imagecolorallocate($border_image, 0, 0, 0);
  796. $white = imagecolorallocate($border_image, 255, 255, 255);
  797. switch ($rot)
  798. {
  799. case 1 :
  800. $cols=array($white,$black,$white,$black);
  801. break;
  802. case 2 :
  803. $cols=array($black,$black,$white,$white);
  804. break;
  805. case 3 :
  806. $cols=array($black,$white,$black,$white);
  807. break;
  808. default :
  809. $cols=array($white,$white,$black,$black);
  810. }
  811. $bg_col = imagecolorallocate($border_image, 127, 128, 126);
  812. // create bg
  813. imagecolortransparent($border_image, $bg_col);
  814. imagefilledrectangle($border_image, 0,0, $temp_w, $temp_h, $bg_col);
  815. // do border
  816. for($x=0;$x<$width;$x++)
  817. {
  818. // top
  819. imageline($border_image, $x, $x, $temp_w-$x-1, $x, $cols[0]);
  820. // left
  821. imageline($border_image, $x, $x, $x, $temp_w-$x-1, $cols[1]);
  822. // bottom
  823. imageline($border_image, $x, $temp_h-$x-1, $temp_w-1-$x, $temp_h-$x-1, $cols[3]);
  824. // right
  825. imageline($border_image, $temp_w-$x-1, $x, $temp_w-$x-1, $temp_h-$x-1, $cols[2]);
  826. }
  827. // merg with temp image
  828. imagecopymerge($this->temp_image, $border_image, 0, 0, 0, 0, $temp_w, $temp_h, $opacity);
  829. // clean up
  830. imagedestroy($border_image);
  831. // return object
  832. return $this;
  833. }
  834. public function shadow($size=4, $direction=3, $colour="#444")
  835. //----------------------------------------------------------------------------------------------------------
  836. // add a shadow to an image, this will INCREASE the size of the image
  837. //----------------------------------------------------------------------------------------------------------
  838. {
  839. // validate we loaded a main image
  840. if (!$this->_check_image()) return $this;
  841. // if no operations, copy it for temp save
  842. $this->_copy_to_temp_if_needed();
  843. // get the current size
  844. $sx = imagesx($this->temp_image);
  845. $sy = imagesy($this->temp_image);
  846. // new image
  847. $bu_image = imagecreatetruecolor($sx, $sy);
  848. // check it
  849. if(!is_resource($bu_image))
  850. {
  851. $this->set_error('Unable to create shadow temp image sized '.$this->width.' x '.$this->height);
  852. return FALSE;
  853. }
  854. // copy the current image to memory
  855. imagecopy($bu_image, $this->temp_image, 0, 0, 0, 0, $sx, $sy);
  856. imagedestroy($this->temp_image);
  857. $this->temp_image = imagecreatetruecolor($sx+$size, $sy+$size);
  858. // fill background colour
  859. $col = $this->_html2rgb($this->background_colour);
  860. $bg = imagecolorallocate($this->temp_image, $col[0], $col[1], $col[2]);
  861. imagefilledrectangle($this->temp_image, 0, 0, $sx+$size, $sy+$size, $bg);
  862. // work out position
  863. // do X position
  864. switch ($direction)
  865. {
  866. // x left
  867. case "7":
  868. case "4":
  869. case "1":
  870. $sh_x = 0;
  871. $pic_x = $size;
  872. break;
  873. // x middle
  874. case "8":
  875. case "5":
  876. case "2":
  877. $sh_x = $size / 2;
  878. $pic_x = $size / 2;
  879. break;
  880. // x right
  881. case "9":
  882. case "6":
  883. case "3":
  884. $sh_x = $size;
  885. $pic_x = 0;
  886. break;
  887. default:
  888. $sh_x = $size;
  889. $pic_x = 0;
  890. $this->set_error("Shadow position $position not in vlaid range 7,8,9 - 4,5,6 - 1,2,3");
  891. }
  892. // do y position
  893. switch ($direction)
  894. {
  895. // y top
  896. case "7":
  897. case "8":
  898. case "9":
  899. $sh_y = 0;
  900. $pic_y = $size;
  901. break;
  902. // y middle
  903. case "4":
  904. case "5":
  905. case "6":
  906. $sh_y = $size / 2;
  907. $pic_y = $size / 2;
  908. break;
  909. // y bottom
  910. case "1":
  911. case "2":
  912. case "3":
  913. $sh_y = $size;
  914. $pic_y = 0;
  915. break;
  916. default:
  917. $sh_y = $size;
  918. $pic_y = 0;
  919. $this->set_error("Shadow position $position not in vlaid range 7,8,9 - 4,5,6 - 1,2,3");
  920. }
  921. // create the shadow
  922. $shadowcolour = $this->_html2rgb($colour);
  923. $shadow = imagecolorallocate($this->temp_image, $shadowcolour[0], $shadowcolour[1], $shadowcolour[2]);
  924. imagefilledrectangle($this->temp_image, $sh_x, $sh_y, $sh_x+$sx-1, $sh_y+$sy-1, $shadow);
  925. // copy current image to correct location
  926. imagecopy($this->temp_image, $bu_image, $pic_x, $pic_y, 0, 0, $sx, $sy);
  927. // clean up and desstroy temp image
  928. imagedestroy($bu_image);
  929. //return object
  930. return $this;
  931. }
  932. public function filter($function, $arg1=NULL, $arg2=NULL, $arg3=NULL, $arg4=NULL)
  933. //----------------------------------------------------------------------------------------------------------
  934. // allows you to use the inbulit gd2 image filters
  935. //----------------------------------------------------------------------------------------------------------
  936. {
  937. // validate we loaded a main image
  938. if (!$this->_check_image()) return $this;
  939. // if no operations, copy it for temp save
  940. $this->_copy_to_temp_if_needed();
  941. if (!imagefilter($this->temp_image, $function, $arg1, $arg2, $arg3, $arg4))
  942. {
  943. $this->set_error("Filter $function failed");
  944. }
  945. // return object
  946. return $this;
  947. }
  948. public function round($radius=5,$invert=False,$corners="")
  949. //----------------------------------------------------------------------------------------------------------
  950. // adds rounded corners to the output
  951. // using a quarter and rotating as you can end up with odd roudning if you draw a whole and use parts
  952. //----------------------------------------------------------------------------------------------------------
  953. {
  954. // validate we loaded a main image
  955. if (!$this->_check_image()) return $this;
  956. // if no operations, copy it for temp save
  957. $this->_copy_to_temp_if_needed();
  958. // check input
  959. if ($corners=="") $corners=array(True,True,True,True);
  960. if (!is_array($corners) || count($corners)<>4)
  961. {
  962. $this->set_error("Round failed, expected an array of 4 items round(radius,tl,tr,br,bl)");
  963. return $this;
  964. }
  965. // create corner
  966. $corner = imagecreatetruecolor($radius, $radius);
  967. // turn on aa make it nicer
  968. imageantialias($corner, true);
  969. $col = $this->_html2rgb($this->background_colour);
  970. // use bg col for corners
  971. $bg = imagecolorallocate($corner, $col[0], $col[1], $col[2]);
  972. // create our transparent colour
  973. $xparent = imagecolorallocate($corner, 127, 128, 126);
  974. imagecolortransparent($corner, $xparent);
  975. if ($invert)
  976. {
  977. // fill and clear bits
  978. imagefilledrectangle($corner, 0, 0, $radius, $radius, $xparent);
  979. imagefilledellipse($corner, 0, 0, ($radius * 2)-1, ($radius * 2)-1, $bg);
  980. }
  981. else
  982. {
  983. // fill and clear bits
  984. imagefilledrectangle($corner, 0, 0, $radius, $radius, $bg);
  985. imagefilledellipse($corner, $radius, $radius, ($radius * 2) , ($radius * 2) , $xparent);
  986. }
  987. // get temp widths
  988. $temp_w = imageSX($this->temp_image);
  989. $temp_h = imageSY($this->temp_image);
  990. // do corners
  991. if ($corners[0]) imagecopymerge($this->temp_image, $corner, 0, 0, 0, 0, $radius, $radius, 100);
  992. $corner = imagerotate($corner, 270, 0);
  993. if ($corners[1]) imagecopymerge($this->temp_image, $corner, $temp_w-$radius, 0, 0, 0, $radius, $radius, 100);
  994. $corner = imagerotate($corner, 270, 0);
  995. if ($corners[2]) imagecopymerge($this->temp_image, $corner, $temp_w-$radius, $temp_h-$radius, 0, 0, $radius, $radius, 100);
  996. $corner = imagerotate($corner, 270, 0);
  997. if ($corners[3]) imagecopymerge($this->temp_image, $corner, 0, $temp_h-$radius, 0, 0, $radius, $radius, 100);
  998. // return object
  999. return $this;
  1000. }
  1001. }
  1002. /* End of file image_moo.php */
  1003. /* Location: .system/application/libraries/image_moo.php */