PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/library/F3/lib/graphics.php

https://github.com/huckfinnaafb/leviatha
PHP | 365 lines | 247 code | 13 blank | 105 comment | 37 complexity | 70c3db5dac8e5788f24bc7eab443575e MD5 | raw file
  1. <?php
  2. /**
  3. Graphics plugin for the PHP Fat-Free Framework
  4. The contents of this file are subject to the terms of the GNU General
  5. Public License Version 3.0. You may not use this file except in
  6. compliance with the license. Any of the license terms and conditions
  7. can be waived if you get permission from the copyright holder.
  8. Copyright (c) 2009-2011 F3::Factory
  9. Bong Cosca <bong.cosca@yahoo.com>
  10. @package Graphics
  11. @version 2.0.0
  12. **/
  13. //! Graphics plugin
  14. class Graphics extends Base {
  15. //@{ Locale-specific error/exception messages
  16. const
  17. TEXT_Color='Invalid color specified';
  18. //@}
  19. const
  20. // Background color
  21. GFX_BGColor=0xFFF,
  22. // Foreground transparency
  23. GFX_Transparency=0x020,
  24. // Identicon horizontal/vertical blocks
  25. GFX_IdBlocks=4,
  26. // Identicon pixels per block
  27. GFX_IdPixels=64,
  28. //! PNG compression level
  29. PNG_Compress=1;
  30. /**
  31. Convert RGB hex triad to array
  32. @return mixed
  33. @param $int integer
  34. @public
  35. **/
  36. static function rgb($int) {
  37. $hex=str_pad(dechex($int),$int<4096?3:6,'0',STR_PAD_LEFT);
  38. $len=strlen($hex);
  39. if ($len>6) {
  40. trigger_error(self::TEXT_Color);
  41. return FALSE;
  42. }
  43. $color=str_split($hex,$len/3);
  44. foreach ($color as &$hue)
  45. $hue=hexdec(str_repeat($hue,6/$len));
  46. return $color;
  47. }
  48. /**
  49. Generate CAPTCHA image
  50. @param $dimx integer
  51. @param $dimy integer
  52. @param $len integer
  53. @param $ttfs string
  54. @param $var string
  55. @public
  56. **/
  57. static function
  58. captcha($dimx=150,$dimy=50,$len=5,$ttfs='cube',$var='captcha') {
  59. $base=self::rgb(self::$vars['BGCOLOR']);
  60. $trans=self::$vars['FGTRANS'];
  61. // Specify Captcha seed
  62. $seed=substr(md5(uniqid()),0,$len);
  63. F3::set('SESSION.'.$var,$seed);
  64. // Font size
  65. $size=.9*min($dimx/$len,$dimy);
  66. // Load TrueType fonts
  67. $fonts=self::split($ttfs);
  68. $file=self::$vars['FONTS'].
  69. self::fixslashes($fonts[array_rand($fonts)]).'.ttf';
  70. $stats=&self::ref('STATS');
  71. if (!isset($stats['FILES']))
  72. $stats['FILES']=array('fonts'=>array());
  73. $stats['FILES']['fonts'][basename($file)]=filesize($file);
  74. $maxdeg=12;
  75. // Create blank image
  76. $captcha=imagecreatetruecolor($dimx,$dimy);
  77. list($r,$g,$b)=$base;
  78. $bg=imagecolorallocate($captcha,$r,$g,$b);
  79. imagefill($captcha,0,0,$bg);
  80. $width=0;
  81. // Insert each Captcha character
  82. for ($i=0;$i<$len;$i++) {
  83. // Random angle
  84. $angle=$maxdeg-mt_rand(0,$maxdeg*2);
  85. // Get CAPTCHA character from session cookie
  86. $char=$seed[$i];
  87. $fg=imagecolorallocatealpha(
  88. $captcha,
  89. mt_rand(0,255-$trans),
  90. mt_rand(0,255-$trans),
  91. mt_rand(0,255-$trans),
  92. $trans
  93. );
  94. // Compute bounding box metrics
  95. $bbox=imagettfbbox($size,0,$file,$char);
  96. $w=max($bbox[2],$bbox[4])-max($bbox[0],$bbox[6]);
  97. $h=max($bbox[1],$bbox[3])-max($bbox[5],$bbox[7]);
  98. $sin=sin(deg2rad($angle));
  99. imagettftext(
  100. $captcha,$size,$angle,
  101. .9*$width+abs($h*$sin),
  102. $dimy-$h/2+abs($w*$sin),
  103. $fg,$file,$char
  104. );
  105. $width+=$w+abs($h*$sin);
  106. imagecolordeallocate($captcha,$fg);
  107. }
  108. // Make the background transparent
  109. imagecolortransparent($captcha,$bg);
  110. // Send output as PNG image
  111. if (PHP_SAPI!='cli')
  112. header(self::HTTP_Content.': image/png');
  113. imagepng($captcha,NULL,self::PNG_Compress,PNG_NO_FILTER);
  114. }
  115. /**
  116. Invert colors of specified image
  117. @param $file
  118. @public
  119. **/
  120. static function invert($file) {
  121. preg_match('/\.(gif|jp[e]*g|png)$/',$file,$ext);
  122. $ext[1]=str_replace('jpg','jpeg',$ext[1]);
  123. $file=self::fixslashes(self::resolve($file));
  124. $img=imagecreatefromstring(file_get_contents($file));
  125. imagefilter($img,IMG_FILTER_NEGATE);
  126. if (PHP_SAPI!='cli')
  127. header(self::HTTP_Content.': image/'.$ext[1]);
  128. // Send output in same graphics format as original
  129. eval('image'.$ext[1].'($img);');
  130. }
  131. /**
  132. Apply grayscale filter on specified image
  133. @param $file
  134. @public
  135. **/
  136. static function grayscale($file) {
  137. preg_match('/\.(gif|jp[e]*g|png)$/',$file,$ext);
  138. $ext[1]=str_replace('jpg','jpeg',$ext[1]);
  139. $file=self::fixslashes(self::resolve($file));
  140. $img=imagecreatefromstring(file_get_contents($file));
  141. imagefilter($img,IMG_FILTER_GRAYSCALE);
  142. if (PHP_SAPI!='cli')
  143. header(self::HTTP_Content.': image/'.$ext[1]);
  144. // Send output in same graphics format as original
  145. eval('image'.$ext[1].'($img);');
  146. }
  147. /**
  148. Generate thumbnail image
  149. @param $file string
  150. @param $dimx integer
  151. @param $dimy integer
  152. @public
  153. **/
  154. static function thumb($file,$dimx,$dimy) {
  155. preg_match('/\.(gif|jp[e]*g|png)$/',$file,$ext);
  156. $ext[1]=str_replace('jpg','jpeg',$ext[1]);
  157. $file=self::fixslashes(self::resolve($file));
  158. $img=imagecreatefromstring(file_get_contents($file));
  159. // Get image dimensions
  160. $oldx=imagesx($img);
  161. $oldy=imagesy($img);
  162. // Adjust dimensions; retain aspect ratio
  163. $ratio=$oldx/$oldy;
  164. if ($dimx<=$oldx && $dimx/$ratio<=$dimy)
  165. // Adjust height
  166. $dimy=$dimx/$ratio;
  167. elseif ($dimy<=$oldy && $dimy*$ratio<=$dimx)
  168. // Adjust width
  169. $dimx=$dimy*$ratio;
  170. else {
  171. // Retain size if dimensions exceed original image
  172. $dimx=$oldx;
  173. $dimy=$oldy;
  174. }
  175. // Create blank image
  176. $tmp=imagecreatetruecolor($dimx,$dimy);
  177. list($r,$g,$b)=self::rgb(self::$vars['BGCOLOR']);
  178. $bg=imagecolorallocate($tmp,$r,$g,$b);
  179. imagefill($tmp,0,0,$bg);
  180. // Resize
  181. imagecopyresampled($tmp,$img,0,0,0,0,$dimx,$dimy,$oldx,$oldy);
  182. // Make the background transparent
  183. imagecolortransparent($tmp,$bg);
  184. if (PHP_SAPI!='cli')
  185. header(self::HTTP_Content.': image/'.$ext[1]);
  186. // Send output in same graphics format as original
  187. eval('image'.$ext[1].'($tmp);');
  188. }
  189. /**
  190. Generate identicon from an MD5 hash value
  191. @param $hash string
  192. @param $size integer
  193. @public
  194. **/
  195. static function identicon($hash,$size=NULL) {
  196. $hash=self::resolve($hash);
  197. $blox=self::$vars['IBLOCKS'];
  198. if (is_null($size))
  199. $size=self::$vars['IPIXELS'];
  200. // Rotatable shapes
  201. $dynamic=array(
  202. array(.5,1,1,0,1,1),
  203. array(.5,0,1,0,.5,1,0,1),
  204. array(.5,0,1,0,1,1,.5,1,1,.5),
  205. array(0,.5,.5,0,1,.5,.5,1,.5,.5),
  206. array(0,.5,1,0,1,1,0,1,1,.5),
  207. array(1,0,1,1,.5,1,1,.5,.5,.5),
  208. array(0,0,1,0,1,.5,0,0,.5,1,0,1),
  209. array(0,0,.5,0,1,.5,.5,1,0,1,.5,.5),
  210. array(.5,0,.5,.5,1,.5,1,1,.5,1,.5,.5,0,.5),
  211. array(0,0,1,0,.5,.5,1,.5,.5,1,.5,.5,0,1),
  212. array(0,.5,.5,1,1,.5,.5,0,1,0,1,1,0,1),
  213. array(.5,0,1,0,1,1,.5,1,1,.75,.5,.5,1,.25),
  214. array(0,.5,.5,0,.5,.5,1,0,1,.5,.5,1,.5,.5,0,1),
  215. array(0,0,1,0,1,1,0,1,1,.5,.5,.25,.5,.75,0,.5,.5,.25),
  216. array(0,.5,.5,.5,.5,0,1,0,.5,.5,1,.5,.5,1,.5,.5,0,1),
  217. array(0,0,1,0,.5,.5,.5,0,0,.5,1,.5,.5,1,.5,.5,0,1)
  218. );
  219. // Fixed shapes (for center sprite)
  220. $static=array(
  221. array(),
  222. array(0,0,1,0,1,1,0,1),
  223. array(.5,0,1,.5,.5,1,0,.5),
  224. array(0,0,1,0,1,1,0,1,0,.5,.5,1,1,.5,.5,0,0,.5),
  225. array(.25,0,.75,0,.5,.5,1,.25,1,.75,.5,.5,
  226. .75,1,.25,1,.5,.5,0,.75,0,.25,.5,.5),
  227. array(0,0,.5,.25,1,0,.75,.5,1,1,.5,.75,0,1,.25,.5),
  228. array(.33,.33,.67,.33,.67,.67,.33,.67),
  229. array(0,0,.33,0,.33,.33,.67,.33,.67,0,1,0,1,.33,.67,.33,
  230. .67,.67,1,.67,1,1,.67,1,.67,.67,.33,.67,.33,1,0,1,
  231. 0,.67,.33,.67,.33,.33,0,.33)
  232. );
  233. // Parse MD5 hash
  234. list($bgR,$bgG,$bgB)=self::rgb(self::$vars['BGCOLOR']);
  235. list($fgR,$fgG,$fgB)=self::rgb(hexdec(substr($hash,0,6)));
  236. $shapeC=hexdec($hash[6]);
  237. $angleC=hexdec($hash[7]%4);
  238. $shapeX=hexdec($hash[8]);
  239. for ($i=0;$i<$blox-2;$i++) {
  240. $shapeS[$i]=hexdec($hash[9+$i*2]);
  241. $angleS[$i]=hexdec($hash[10+$i*2]%4);
  242. }
  243. // Start with NxN blank slate
  244. $identicon=imagecreatetruecolor($size*$blox,$size*$blox);
  245. imageantialias($identicon,TRUE);
  246. $bg=imagecolorallocate($identicon,$bgR,$bgG,$bgB);
  247. $fg=imagecolorallocate($identicon,$fgR,$fgG,$fgB);
  248. // Generate corner sprites
  249. $corner=imagecreatetruecolor($size,$size);
  250. imagefill($corner,0,0,$bg);
  251. $sprite=$dynamic[$shapeC];
  252. for ($i=0,$len=count($sprite);$i<$len;$i++)
  253. $sprite[$i]=$sprite[$i]*$size;
  254. imagefilledpolygon($corner,$sprite,$len/2,$fg);
  255. for ($i=0;$i<$angleC;$i++)
  256. $corner=imagerotate($corner,90,$bg);
  257. // Generate side sprites
  258. for ($i=0;$i<$blox-2;$i++) {
  259. $side[$i]=imagecreatetruecolor($size,$size);
  260. imagefill($side[$i],0,0,$bg);
  261. $sprite=$dynamic[$shapeS[$i]];
  262. for ($j=0,$len=count($sprite);$j<$len;$j++)
  263. $sprite[$j]=$sprite[$j]*$size;
  264. imagefilledpolygon($side[$i],$sprite,$len/2,$fg);
  265. for ($j=0;$j<$angleS[$i];$j++)
  266. $side[$i]=imagerotate($side[$i],90,$bg);
  267. }
  268. // Generate center sprites
  269. for ($i=0;$i<$blox-2;$i++) {
  270. $center[$i]=imagecreatetruecolor($size,$size);
  271. imagefill($center[$i],0,0,$bg);
  272. $sprite=$dynamic[$shapeX];
  273. if ($blox%2>0 && $i==$blox-3)
  274. // Odd center sprites
  275. $sprite=$static[$shapeX%8];
  276. $len=count($sprite);
  277. if ($len) {
  278. for ($j=0;$j<$len;$j++)
  279. $sprite[$j]=$sprite[$j]*$size;
  280. imagefilledpolygon($center[$i],$sprite,$len/2,$fg);
  281. }
  282. if ($i<($blox-3))
  283. for ($j=0;$j<$angleS[$i];$j++)
  284. $center[$i]=imagerotate($center[$i],90,$bg);
  285. }
  286. // Paste sprites
  287. for ($i=0;$i<4;$i++) {
  288. imagecopy($identicon,$corner,0,0,0,0,$size,$size);
  289. for ($j=0;$j<$blox-2;$j++) {
  290. imagecopy($identicon,$side[$j],
  291. $size*($j+1),0,0,0,$size,$size);
  292. for ($k=$j;$k<$blox-3-$j;$k++)
  293. imagecopy($identicon,$center[$k],
  294. $size*($k+1),$size*($j+1),0,0,$size,$size);
  295. }
  296. $identicon=imagerotate($identicon,90,$bg);
  297. }
  298. if ($blox%2>0)
  299. // Paste odd center sprite
  300. imagecopy($identicon,$center[$blox-3],
  301. $size*(floor($blox/2)),$size*(floor($blox/2)),0,0,
  302. $size,$size);
  303. // Resize
  304. $resized=imagecreatetruecolor($size,$size);
  305. imagecopyresampled($resized,$identicon,0,0,0,0,$size,$size,
  306. $size*$blox,$size*$blox);
  307. // Make the background transparent
  308. imagecolortransparent($resized,$bg);
  309. if (PHP_SAPI!='cli')
  310. header(self::HTTP_Content.': image/png');
  311. imagepng($resized,NULL,self::PNG_Compress,PNG_NO_FILTER);
  312. }
  313. /**
  314. Generate a blank image for use as a placeholder
  315. @param $dimx integer
  316. @param $dimy integer
  317. @param $bg string
  318. @public
  319. **/
  320. static function fakeImage($dimx,$dimy,$bg=0xEEE) {
  321. list($r,$g,$b)=self::rgb($bg);
  322. $img=imagecreatetruecolor($dimx,$dimy);
  323. $bg=imagecolorallocate($img,$r,$g,$b);
  324. imagefill($img,0,0,$bg);
  325. if (PHP_SAPI!='cli')
  326. header(self::HTTP_Content.': image/png');
  327. imagepng($img,NULL,self::PNG_Compress,PNG_NO_FILTER);
  328. }
  329. /**
  330. Class initializer
  331. @public
  332. **/
  333. static function onload() {
  334. if (!extension_loaded('gd')) {
  335. // GD extension required
  336. trigger_error(sprintf(self::TEXT_PHPExt,'gd'));
  337. }
  338. if (!isset(self::$vars['FONTS']))
  339. self::$vars['FONTS']=self::$vars['ROOT'];
  340. if (!isset(self::$vars['BGCOLOR']))
  341. self::$vars['BGCOLOR']=self::GFX_BGColor;
  342. if (!isset(self::$vars['FGTRANS']))
  343. self::$vars['FGTRANS']=self::GFX_Transparency;
  344. if (!isset(self::$vars['IBLOCKS']))
  345. self::$vars['IBLOCKS']=self::GFX_IdBlocks;
  346. if (!isset(self::$vars['IPIXELS']))
  347. self::$vars['IPIXELS']=self::GFX_IdPixels;
  348. }
  349. }