PageRenderTime 66ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/captcha/captcha_gd.php

http://seo-phpbb.googlecode.com/
PHP | 1567 lines | 1280 code | 159 blank | 128 comment | 71 complexity | d0c255131e409d86bb11f70358df08b4 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. * @package VC
  5. * @version $Id: captcha_gd.php 8479 2008-03-29 00:22:48Z naderman $
  6. * @copyright (c) 2006 phpBB Group
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10. /**
  11. * @ignore
  12. */
  13. if (!defined('IN_PHPBB'))
  14. {
  15. exit;
  16. }
  17. /**
  18. * Original Author - Xore (Robert Hetzler)
  19. * With contributions from Neothermic
  20. *
  21. * @package VC
  22. */
  23. class captcha
  24. {
  25. var $width = 360;
  26. var $height = 96;
  27. /**
  28. * Create the image containing $code with a seed of $seed
  29. */
  30. function execute($code, $seed)
  31. {
  32. global $config;
  33. srand($seed);
  34. mt_srand($seed);
  35. // Create image
  36. $img = imagecreatetruecolor($this->width, $this->height);
  37. // Generate colours
  38. $colour = new colour_manager($img, array(
  39. 'random' => true,
  40. 'min_value' => 60,
  41. ), 'hsv');
  42. $scheme = $colour->colour_scheme('background', false);
  43. $scheme = $colour->mono_range($scheme, 10, false);
  44. shuffle($scheme);
  45. $bg_colours = array_splice($scheme, mt_rand(6, 12));
  46. // Generate code characters
  47. $characters = $sizes = $bounding_boxes = array();
  48. $width_avail = $this->width - 15;
  49. $code_len = strlen($code);
  50. $captcha_bitmaps = $this->captcha_bitmaps();
  51. for ($i = 0; $i < $code_len; ++$i)
  52. {
  53. $characters[$i] = new char_cube3d($captcha_bitmaps, $code[$i]);
  54. list($min, $max) = $characters[$i]->range();
  55. $sizes[$i] = mt_rand($min, $max);
  56. $box = $characters[$i]->dimensions($sizes[$i]);
  57. $width_avail -= ($box[2] - $box[0]);
  58. $bounding_boxes[$i] = $box;
  59. }
  60. // Redistribute leftover x-space
  61. $offset = array();
  62. for ($i = 0; $i < $code_len; ++$i)
  63. {
  64. $denom = ($code_len - $i);
  65. $denom = max(1.3, $denom);
  66. $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom);
  67. $width_avail -= $offset[$i];
  68. }
  69. if ($config['captcha_gd_x_grid'])
  70. {
  71. $grid = (int) $config['captcha_gd_x_grid'];
  72. for ($y = 0; $y < $this->height; $y += mt_rand($grid - 2, $grid + 2))
  73. {
  74. $current_colour = $scheme[array_rand($scheme)];
  75. imageline($img, mt_rand(0,4), mt_rand($y - 3, $y), mt_rand($this->width - 5, $this->width), mt_rand($y - 3, $y), $current_colour);
  76. }
  77. }
  78. if ($config['captcha_gd_y_grid'])
  79. {
  80. $grid = (int) $config['captcha_gd_y_grid'];
  81. for ($x = 0; $x < $this->width; $x += mt_rand($grid - 2, $grid + 2))
  82. {
  83. $current_colour = $scheme[array_rand($scheme)];
  84. imagedashedline($img, mt_rand($x -3, $x + 3), mt_rand(0, 4), mt_rand($x -3, $x + 3), mt_rand($this->height - 5, $this->height), $current_colour);
  85. }
  86. }
  87. $xoffset = 5;
  88. for ($i = 0; $i < $code_len; ++$i)
  89. {
  90. $dimm = $bounding_boxes[$i];
  91. $xoffset += ($offset[$i] - $dimm[0]);
  92. $yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]);
  93. $characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme);
  94. $xoffset += $dimm[2];
  95. }
  96. if ($config['captcha_gd_foreground_noise'])
  97. {
  98. $this->noise_line($img, 0, 0, $this->width, $this->height, $colour->get_resource('background'), $scheme, $bg_colours);
  99. }
  100. // Send image
  101. header('Content-Type: image/png');
  102. header('Cache-control: no-cache, no-store');
  103. imagepng($img);
  104. imagedestroy($img);
  105. }
  106. /**
  107. * Noise line
  108. */
  109. function noise_line($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font)
  110. {
  111. imagesetthickness($img, 2);
  112. $x1 = $min_x;
  113. $x2 = $max_x;
  114. $y1 = $min_y;
  115. $y2 = $min_y;
  116. do
  117. {
  118. $line = array_merge(
  119. array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]),
  120. array_fill(0, mt_rand(30, 60), $bg)
  121. );
  122. imagesetstyle($img, $line);
  123. imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
  124. $y1 += mt_rand(12, 35);
  125. $y2 += mt_rand(12, 35);
  126. }
  127. while ($y1 < $max_y && $y2 < $max_y);
  128. $x1 = $min_x;
  129. $x2 = $min_x;
  130. $y1 = $min_y;
  131. $y2 = $max_y;
  132. do
  133. {
  134. $line = array_merge(
  135. array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]),
  136. array_fill(0, mt_rand(30, 60), $bg)
  137. );
  138. imagesetstyle($img, $line);
  139. imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
  140. $x1 += mt_rand(20, 35);
  141. $x2 += mt_rand(20, 35);
  142. }
  143. while ($x1 < $max_x && $x2 < $max_x);
  144. imagesetthickness($img, 1);
  145. }
  146. /**
  147. * Return bitmaps
  148. */
  149. function captcha_bitmaps()
  150. {
  151. return array(
  152. 'width' => 9,
  153. 'height' => 15,
  154. 'data' => array(
  155. 'A' => array(
  156. array(0,0,0,0,1,0,0,0,0),
  157. array(0,0,0,1,0,1,0,0,0),
  158. array(0,0,0,1,0,1,0,0,0),
  159. array(0,0,0,1,0,1,0,0,0),
  160. array(0,0,1,0,0,0,1,0,0),
  161. array(0,0,1,0,0,0,1,0,0),
  162. array(0,0,1,0,0,0,1,0,0),
  163. array(0,1,0,0,0,0,0,1,0),
  164. array(0,1,0,0,0,0,0,1,0),
  165. array(0,1,1,1,1,1,1,1,0),
  166. array(0,1,0,0,0,0,0,1,0),
  167. array(1,0,0,0,0,0,0,0,1),
  168. array(1,0,0,0,0,0,0,0,1),
  169. array(1,0,0,0,0,0,0,0,1),
  170. array(1,0,0,0,0,0,0,0,1),
  171. ),
  172. 'B' => array(
  173. array(1,1,1,1,1,1,1,0,0),
  174. array(1,0,0,0,0,0,0,1,0),
  175. array(1,0,0,0,0,0,0,0,1),
  176. array(1,0,0,0,0,0,0,0,1),
  177. array(1,0,0,0,0,0,0,0,1),
  178. array(1,0,0,0,0,0,0,0,1),
  179. array(1,0,0,0,0,0,0,1,0),
  180. array(1,1,1,1,1,1,1,0,0),
  181. array(1,0,0,0,0,0,0,1,0),
  182. array(1,0,0,0,0,0,0,0,1),
  183. array(1,0,0,0,0,0,0,0,1),
  184. array(1,0,0,0,0,0,0,0,1),
  185. array(1,0,0,0,0,0,0,0,1),
  186. array(1,0,0,0,0,0,0,1,0),
  187. array(1,1,1,1,1,1,1,0,0),
  188. ),
  189. 'C' => array(
  190. array(0,0,1,1,1,1,1,0,0),
  191. array(0,1,0,0,0,0,0,1,0),
  192. array(1,0,0,0,0,0,0,0,1),
  193. array(1,0,0,0,0,0,0,0,1),
  194. array(1,0,0,0,0,0,0,0,0),
  195. array(1,0,0,0,0,0,0,0,0),
  196. array(1,0,0,0,0,0,0,0,0),
  197. array(1,0,0,0,0,0,0,0,0),
  198. array(1,0,0,0,0,0,0,0,0),
  199. array(1,0,0,0,0,0,0,0,0),
  200. array(1,0,0,0,0,0,0,0,0),
  201. array(1,0,0,0,0,0,0,0,1),
  202. array(1,0,0,0,0,0,0,0,1),
  203. array(0,1,0,0,0,0,0,1,0),
  204. array(0,0,1,1,1,1,1,0,0),
  205. ),
  206. 'D' => array(
  207. array(1,1,1,1,1,1,1,0,0),
  208. array(1,0,0,0,0,0,0,1,0),
  209. array(1,0,0,0,0,0,0,0,1),
  210. array(1,0,0,0,0,0,0,0,1),
  211. array(1,0,0,0,0,0,0,0,1),
  212. array(1,0,0,0,0,0,0,0,1),
  213. array(1,0,0,0,0,0,0,0,1),
  214. array(1,0,0,0,0,0,0,0,1),
  215. array(1,0,0,0,0,0,0,0,1),
  216. array(1,0,0,0,0,0,0,0,1),
  217. array(1,0,0,0,0,0,0,0,1),
  218. array(1,0,0,0,0,0,0,0,1),
  219. array(1,0,0,0,0,0,0,0,1),
  220. array(1,0,0,0,0,0,0,1,0),
  221. array(1,1,1,1,1,1,1,0,0),
  222. ),
  223. 'E' => array(
  224. array(1,1,1,1,1,1,1,1,1),
  225. array(1,0,0,0,0,0,0,0,0),
  226. array(1,0,0,0,0,0,0,0,0),
  227. array(1,0,0,0,0,0,0,0,0),
  228. array(1,0,0,0,0,0,0,0,0),
  229. array(1,0,0,0,0,0,0,0,0),
  230. array(1,0,0,0,0,0,0,0,0),
  231. array(1,1,1,1,1,1,1,1,0),
  232. array(1,0,0,0,0,0,0,0,0),
  233. array(1,0,0,0,0,0,0,0,0),
  234. array(1,0,0,0,0,0,0,0,0),
  235. array(1,0,0,0,0,0,0,0,0),
  236. array(1,0,0,0,0,0,0,0,0),
  237. array(1,0,0,0,0,0,0,0,0),
  238. array(1,1,1,1,1,1,1,1,1),
  239. ),
  240. 'F' => array(
  241. array(1,1,1,1,1,1,1,1,1),
  242. array(1,0,0,0,0,0,0,0,0),
  243. array(1,0,0,0,0,0,0,0,0),
  244. array(1,0,0,0,0,0,0,0,0),
  245. array(1,0,0,0,0,0,0,0,0),
  246. array(1,0,0,0,0,0,0,0,0),
  247. array(1,0,0,0,0,0,0,0,0),
  248. array(1,1,1,1,1,1,1,0,0),
  249. array(1,0,0,0,0,0,0,0,0),
  250. array(1,0,0,0,0,0,0,0,0),
  251. array(1,0,0,0,0,0,0,0,0),
  252. array(1,0,0,0,0,0,0,0,0),
  253. array(1,0,0,0,0,0,0,0,0),
  254. array(1,0,0,0,0,0,0,0,0),
  255. array(1,0,0,0,0,0,0,0,0),
  256. ),
  257. 'G' => array(
  258. array(0,0,1,1,1,1,1,0,0),
  259. array(0,1,0,0,0,0,0,1,0),
  260. array(1,0,0,0,0,0,0,0,1),
  261. array(1,0,0,0,0,0,0,0,0),
  262. array(1,0,0,0,0,0,0,0,0),
  263. array(1,0,0,0,0,0,0,0,0),
  264. array(1,0,0,0,0,0,0,0,0),
  265. array(1,0,0,0,0,0,0,0,0),
  266. array(1,0,0,0,0,0,1,1,1),
  267. array(1,0,0,0,0,0,0,0,1),
  268. array(1,0,0,0,0,0,0,0,1),
  269. array(1,0,0,0,0,0,0,0,1),
  270. array(1,0,0,0,0,0,0,0,1),
  271. array(0,1,0,0,0,0,0,1,0),
  272. array(0,0,1,1,1,1,1,0,0),
  273. ),
  274. 'H' => array(
  275. array(1,0,0,0,0,0,0,0,1),
  276. array(1,0,0,0,0,0,0,0,1),
  277. array(1,0,0,0,0,0,0,0,1),
  278. array(1,0,0,0,0,0,0,0,1),
  279. array(1,0,0,0,0,0,0,0,1),
  280. array(1,0,0,0,0,0,0,0,1),
  281. array(1,0,0,0,0,0,0,0,1),
  282. array(1,1,1,1,1,1,1,1,1),
  283. array(1,0,0,0,0,0,0,0,1),
  284. array(1,0,0,0,0,0,0,0,1),
  285. array(1,0,0,0,0,0,0,0,1),
  286. array(1,0,0,0,0,0,0,0,1),
  287. array(1,0,0,0,0,0,0,0,1),
  288. array(1,0,0,0,0,0,0,0,1),
  289. array(1,0,0,0,0,0,0,0,1),
  290. ),
  291. 'I' => array(
  292. array(1,1,1,1,1,1,1,1,1),
  293. array(0,0,0,0,1,0,0,0,0),
  294. array(0,0,0,0,1,0,0,0,0),
  295. array(0,0,0,0,1,0,0,0,0),
  296. array(0,0,0,0,1,0,0,0,0),
  297. array(0,0,0,0,1,0,0,0,0),
  298. array(0,0,0,0,1,0,0,0,0),
  299. array(0,0,0,0,1,0,0,0,0),
  300. array(0,0,0,0,1,0,0,0,0),
  301. array(0,0,0,0,1,0,0,0,0),
  302. array(0,0,0,0,1,0,0,0,0),
  303. array(0,0,0,0,1,0,0,0,0),
  304. array(0,0,0,0,1,0,0,0,0),
  305. array(0,0,0,0,1,0,0,0,0),
  306. array(1,1,1,1,1,1,1,1,1),
  307. ),
  308. 'J' => array(
  309. array(1,1,1,1,1,1,1,1,1),
  310. array(0,0,0,0,0,1,0,0,0),
  311. array(0,0,0,0,0,1,0,0,0),
  312. array(0,0,0,0,0,1,0,0,0),
  313. array(0,0,0,0,0,1,0,0,0),
  314. array(0,0,0,0,0,1,0,0,0),
  315. array(0,0,0,0,0,1,0,0,0),
  316. array(0,0,0,0,0,1,0,0,0),
  317. array(0,0,0,0,0,1,0,0,0),
  318. array(0,0,0,0,0,1,0,0,0),
  319. array(0,0,0,0,0,1,0,0,0),
  320. array(1,0,0,0,0,1,0,0,0),
  321. array(1,0,0,0,0,1,0,0,0),
  322. array(0,1,0,0,1,0,0,0,0),
  323. array(0,0,1,1,0,0,0,0,0),
  324. ),
  325. 'K' => array( // New 'K', supplied by NeoThermic
  326. array(1,0,0,0,0,0,0,0,1),
  327. array(1,0,0,0,0,0,0,1,0),
  328. array(1,0,0,0,0,0,1,0,0),
  329. array(1,0,0,0,0,1,0,0,0),
  330. array(1,0,0,0,1,0,0,0,0),
  331. array(1,0,0,1,0,0,0,0,0),
  332. array(1,0,1,0,0,0,0,0,0),
  333. array(1,1,0,0,0,0,0,0,0),
  334. array(1,0,1,0,0,0,0,0,0),
  335. array(1,0,0,1,0,0,0,0,0),
  336. array(1,0,0,0,1,0,0,0,0),
  337. array(1,0,0,0,0,1,0,0,0),
  338. array(1,0,0,0,0,0,1,0,0),
  339. array(1,0,0,0,0,0,0,1,0),
  340. array(1,0,0,0,0,0,0,0,1),
  341. ),
  342. 'L' => array(
  343. array(0,0,0,0,0,0,0,0,0),
  344. array(1,0,0,0,0,0,0,0,0),
  345. array(1,0,0,0,0,0,0,0,0),
  346. array(1,0,0,0,0,0,0,0,0),
  347. array(1,0,0,0,0,0,0,0,0),
  348. array(1,0,0,0,0,0,0,0,0),
  349. array(1,0,0,0,0,0,0,0,0),
  350. array(1,0,0,0,0,0,0,0,0),
  351. array(1,0,0,0,0,0,0,0,0),
  352. array(1,0,0,0,0,0,0,0,0),
  353. array(1,0,0,0,0,0,0,0,0),
  354. array(1,0,0,0,0,0,0,0,0),
  355. array(1,0,0,0,0,0,0,0,0),
  356. array(1,0,0,0,0,0,0,0,0),
  357. array(1,1,1,1,1,1,1,1,1),
  358. ),
  359. 'M' => array(
  360. array(1,1,0,0,0,0,0,1,1),
  361. array(1,1,0,0,0,0,0,1,1),
  362. array(1,0,1,0,0,0,1,0,1),
  363. array(1,0,1,0,0,0,1,0,1),
  364. array(1,0,1,0,0,0,1,0,1),
  365. array(1,0,0,1,0,1,0,0,1),
  366. array(1,0,0,1,0,1,0,0,1),
  367. array(1,0,0,1,0,1,0,0,1),
  368. array(1,0,0,0,1,0,0,0,1),
  369. array(1,0,0,0,1,0,0,0,1),
  370. array(1,0,0,0,0,0,0,0,1),
  371. array(1,0,0,0,0,0,0,0,1),
  372. array(1,0,0,0,0,0,0,0,1),
  373. array(1,0,0,0,0,0,0,0,1),
  374. array(1,0,0,0,0,0,0,0,1),
  375. ),
  376. 'N' => array(
  377. array(1,1,0,0,0,0,0,0,1),
  378. array(1,1,0,0,0,0,0,0,1),
  379. array(1,0,1,0,0,0,0,0,1),
  380. array(1,0,1,0,0,0,0,0,1),
  381. array(1,0,0,1,0,0,0,0,1),
  382. array(1,0,0,1,0,0,0,0,1),
  383. array(1,0,0,0,1,0,0,0,1),
  384. array(1,0,0,0,1,0,0,0,1),
  385. array(1,0,0,0,1,0,0,0,1),
  386. array(1,0,0,0,0,1,0,0,1),
  387. array(1,0,0,0,0,1,0,0,1),
  388. array(1,0,0,0,0,0,1,0,1),
  389. array(1,0,0,0,0,0,1,0,1),
  390. array(1,0,0,0,0,0,0,1,1),
  391. array(1,0,0,0,0,0,0,1,1),
  392. ),
  393. 'O' => array(
  394. array(0,0,1,1,1,1,1,0,0),
  395. array(0,1,0,0,0,0,0,1,0),
  396. array(1,0,0,0,0,0,0,0,1),
  397. array(1,0,0,0,0,0,0,0,1),
  398. array(1,0,0,0,0,0,0,0,1),
  399. array(1,0,0,0,0,0,0,0,1),
  400. array(1,0,0,0,0,0,0,0,1),
  401. array(1,0,0,0,0,0,0,0,1),
  402. array(1,0,0,0,0,0,0,0,1),
  403. array(1,0,0,0,0,0,0,0,1),
  404. array(1,0,0,0,0,0,0,0,1),
  405. array(1,0,0,0,0,0,0,0,1),
  406. array(1,0,0,0,0,0,0,0,1),
  407. array(0,1,0,0,0,0,0,1,0),
  408. array(0,0,1,1,1,1,1,0,0),
  409. ),
  410. 'P' => array(
  411. array(1,1,1,1,1,1,1,0,0),
  412. array(1,0,0,0,0,0,0,1,0),
  413. array(1,0,0,0,0,0,0,0,1),
  414. array(1,0,0,0,0,0,0,0,1),
  415. array(1,0,0,0,0,0,0,0,1),
  416. array(1,0,0,0,0,0,0,0,1),
  417. array(1,0,0,0,0,0,0,1,0),
  418. array(1,1,1,1,1,1,1,0,0),
  419. array(1,0,0,0,0,0,0,0,0),
  420. array(1,0,0,0,0,0,0,0,0),
  421. array(1,0,0,0,0,0,0,0,0),
  422. array(1,0,0,0,0,0,0,0,0),
  423. array(1,0,0,0,0,0,0,0,0),
  424. array(1,0,0,0,0,0,0,0,0),
  425. array(1,0,0,0,0,0,0,0,0),
  426. ),
  427. 'Q' => array(
  428. array(0,0,1,1,1,1,1,0,0),
  429. array(0,1,0,0,0,0,0,1,0),
  430. array(1,0,0,0,0,0,0,0,1),
  431. array(1,0,0,0,0,0,0,0,1),
  432. array(1,0,0,0,0,0,0,0,1),
  433. array(1,0,0,0,0,0,0,0,1),
  434. array(1,0,0,0,0,0,0,0,1),
  435. array(1,0,0,0,0,0,0,0,1),
  436. array(1,0,0,0,0,0,0,0,1),
  437. array(1,0,0,0,0,0,0,0,1),
  438. array(1,0,0,0,0,0,0,0,1),
  439. array(1,0,0,0,0,1,0,0,1),
  440. array(1,0,0,0,0,0,1,0,1),
  441. array(0,1,0,0,0,0,0,1,0),
  442. array(0,0,1,1,1,1,1,0,1),
  443. ),
  444. 'R' => array(
  445. array(1,1,1,1,1,1,1,0,0),
  446. array(1,0,0,0,0,0,0,1,0),
  447. array(1,0,0,0,0,0,0,0,1),
  448. array(1,0,0,0,0,0,0,0,1),
  449. array(1,0,0,0,0,0,0,0,1),
  450. array(1,0,0,0,0,0,0,0,1),
  451. array(1,0,0,0,0,0,0,1,0),
  452. array(1,1,1,1,1,1,1,0,0),
  453. array(1,1,1,0,0,0,0,0,0),
  454. array(1,0,0,1,0,0,0,0,0),
  455. array(1,0,0,0,1,0,0,0,0),
  456. array(1,0,0,0,0,1,0,0,0),
  457. array(1,0,0,0,0,0,1,0,0),
  458. array(1,0,0,0,0,0,0,1,0),
  459. array(1,0,0,0,0,0,0,0,1),
  460. ),
  461. 'S' => array(
  462. array(0,0,1,1,1,1,1,0,0),
  463. array(0,1,0,0,0,0,0,1,0),
  464. array(1,0,0,0,0,0,0,0,1),
  465. array(1,0,0,0,0,0,0,0,0),
  466. array(1,0,0,0,0,0,0,0,0),
  467. array(1,0,0,0,0,0,0,0,0),
  468. array(0,1,0,0,0,0,0,0,0),
  469. array(0,0,1,1,1,1,1,0,0),
  470. array(0,0,0,0,0,0,0,1,0),
  471. array(0,0,0,0,0,0,0,0,1),
  472. array(0,0,0,0,0,0,0,0,1),
  473. array(0,0,0,0,0,0,0,0,1),
  474. array(1,0,0,0,0,0,0,0,1),
  475. array(0,1,0,0,0,0,0,1,0),
  476. array(0,0,1,1,1,1,1,0,0),
  477. ),
  478. 'T' => array(
  479. array(1,1,1,1,1,1,1,1,1),
  480. array(0,0,0,0,1,0,0,0,0),
  481. array(0,0,0,0,1,0,0,0,0),
  482. array(0,0,0,0,1,0,0,0,0),
  483. array(0,0,0,0,1,0,0,0,0),
  484. array(0,0,0,0,1,0,0,0,0),
  485. array(0,0,0,0,1,0,0,0,0),
  486. array(0,0,0,0,1,0,0,0,0),
  487. array(0,0,0,0,1,0,0,0,0),
  488. array(0,0,0,0,1,0,0,0,0),
  489. array(0,0,0,0,1,0,0,0,0),
  490. array(0,0,0,0,1,0,0,0,0),
  491. array(0,0,0,0,1,0,0,0,0),
  492. array(0,0,0,0,1,0,0,0,0),
  493. array(0,0,0,0,1,0,0,0,0),
  494. ),
  495. 'U' => array(
  496. array(1,0,0,0,0,0,0,0,1),
  497. array(1,0,0,0,0,0,0,0,1),
  498. array(1,0,0,0,0,0,0,0,1),
  499. array(1,0,0,0,0,0,0,0,1),
  500. array(1,0,0,0,0,0,0,0,1),
  501. array(1,0,0,0,0,0,0,0,1),
  502. array(1,0,0,0,0,0,0,0,1),
  503. array(1,0,0,0,0,0,0,0,1),
  504. array(1,0,0,0,0,0,0,0,1),
  505. array(1,0,0,0,0,0,0,0,1),
  506. array(1,0,0,0,0,0,0,0,1),
  507. array(1,0,0,0,0,0,0,0,1),
  508. array(1,0,0,0,0,0,0,0,1),
  509. array(0,1,0,0,0,0,0,1,0),
  510. array(0,0,1,1,1,1,1,0,0),
  511. ),
  512. 'V' => array(
  513. array(1,0,0,0,0,0,0,0,1),
  514. array(1,0,0,0,0,0,0,0,1),
  515. array(1,0,0,0,0,0,0,0,1),
  516. array(0,1,0,0,0,0,0,1,0),
  517. array(0,1,0,0,0,0,0,1,0),
  518. array(0,1,0,0,0,0,0,1,0),
  519. array(0,0,1,0,0,0,1,0,0),
  520. array(0,0,1,0,0,0,1,0,0),
  521. array(0,0,1,0,0,0,1,0,0),
  522. array(0,0,1,0,0,0,1,0,0),
  523. array(0,0,0,1,0,1,0,0,0),
  524. array(0,0,0,1,0,1,0,0,0),
  525. array(0,0,0,1,0,1,0,0,0),
  526. array(0,0,0,0,1,0,0,0,0),
  527. array(0,0,0,0,1,0,0,0,0),
  528. ),
  529. 'W' => array( // New 'W', supplied by MHobbit
  530. array(1,0,0,0,0,0,0,0,1),
  531. array(1,0,0,0,0,0,0,0,1),
  532. array(1,0,0,0,0,0,0,0,1),
  533. array(1,0,0,0,0,0,0,0,1),
  534. array(1,0,0,0,0,0,0,0,1),
  535. array(1,0,0,0,1,0,0,0,1),
  536. array(1,0,0,0,1,0,0,0,1),
  537. array(1,0,0,1,0,1,0,0,1),
  538. array(1,0,0,1,0,1,0,0,1),
  539. array(1,0,0,1,0,1,0,0,1),
  540. array(1,0,1,0,0,0,1,0,1),
  541. array(1,0,1,0,0,0,1,0,1),
  542. array(1,0,1,0,0,0,1,0,1),
  543. array(1,1,0,0,0,0,0,1,1),
  544. array(1,1,0,0,0,0,0,1,1),
  545. ),
  546. 'X' => array(
  547. array(1,0,0,0,0,0,0,0,1),
  548. array(1,0,0,0,0,0,0,0,1),
  549. array(0,1,0,0,0,0,0,1,0),
  550. array(0,1,0,0,0,0,0,1,0),
  551. array(0,0,1,0,0,0,1,0,0),
  552. array(0,0,0,1,0,1,0,0,0),
  553. array(0,0,0,1,0,1,0,0,0),
  554. array(0,0,0,0,1,0,0,0,0),
  555. array(0,0,0,1,0,1,0,0,0),
  556. array(0,0,0,1,0,1,0,0,0),
  557. array(0,0,1,0,0,0,1,0,0),
  558. array(0,1,0,0,0,0,1,0,0),
  559. array(0,1,0,0,0,0,0,1,0),
  560. array(1,0,0,0,0,0,0,0,1),
  561. array(1,0,0,0,0,0,0,0,1),
  562. ),
  563. 'Y' => array(
  564. array(1,0,0,0,0,0,0,0,1),
  565. array(1,0,0,0,0,0,0,0,1),
  566. array(0,1,0,0,0,0,0,1,0),
  567. array(0,1,0,0,0,0,0,1,0),
  568. array(0,0,1,0,0,0,1,0,0),
  569. array(0,0,1,0,0,0,1,0,0),
  570. array(0,0,0,1,0,1,0,0,0),
  571. array(0,0,0,0,1,0,0,0,0),
  572. array(0,0,0,0,1,0,0,0,0),
  573. array(0,0,0,0,1,0,0,0,0),
  574. array(0,0,0,0,1,0,0,0,0),
  575. array(0,0,0,0,1,0,0,0,0),
  576. array(0,0,0,0,1,0,0,0,0),
  577. array(0,0,0,0,1,0,0,0,0),
  578. array(0,0,0,0,1,0,0,0,0),
  579. ),
  580. 'Z' => array( // New 'Z' supplied by Anon
  581. array(1,1,1,1,1,1,1,1,1),
  582. array(1,0,0,0,0,0,0,0,1),
  583. array(0,0,0,0,0,0,0,0,1),
  584. array(0,0,0,0,0,0,0,1,0),
  585. array(0,0,0,0,0,0,1,0,0),
  586. array(0,0,0,0,0,1,0,0,0),
  587. array(0,0,0,0,0,1,0,0,0),
  588. array(0,0,0,0,1,0,0,0,0),
  589. array(0,0,0,1,0,0,0,0,0),
  590. array(0,0,0,1,0,0,0,0,0),
  591. array(0,0,1,0,0,0,0,0,0),
  592. array(0,1,0,0,0,0,0,0,0),
  593. array(1,0,0,0,0,0,0,0,0),
  594. array(1,0,0,0,0,0,0,0,1),
  595. array(1,1,1,1,1,1,1,1,1),
  596. ),
  597. '1' => array(
  598. array(0,0,0,1,1,0,0,0,0),
  599. array(0,0,1,0,1,0,0,0,0),
  600. array(0,1,0,0,1,0,0,0,0),
  601. array(0,0,0,0,1,0,0,0,0),
  602. array(0,0,0,0,1,0,0,0,0),
  603. array(0,0,0,0,1,0,0,0,0),
  604. array(0,0,0,0,1,0,0,0,0),
  605. array(0,0,0,0,1,0,0,0,0),
  606. array(0,0,0,0,1,0,0,0,0),
  607. array(0,0,0,0,1,0,0,0,0),
  608. array(0,0,0,0,1,0,0,0,0),
  609. array(0,0,0,0,1,0,0,0,0),
  610. array(0,0,0,0,1,0,0,0,0),
  611. array(0,0,0,0,1,0,0,0,0),
  612. array(0,1,1,1,1,1,1,1,0),
  613. ),
  614. '2' => array( // New '2' supplied by Anon
  615. array(0,0,0,1,1,1,0,0,0),
  616. array(0,0,1,0,0,0,1,0,0),
  617. array(0,1,0,0,0,0,1,1,0),
  618. array(0,0,0,0,0,0,0,0,1),
  619. array(0,0,0,0,0,0,0,0,1),
  620. array(0,0,0,0,0,0,0,1,1),
  621. array(0,0,0,0,0,0,0,1,0),
  622. array(0,0,0,0,0,0,1,0,0),
  623. array(0,0,0,0,0,1,0,0,0),
  624. array(0,0,0,0,1,0,0,0,0),
  625. array(0,0,0,1,0,0,0,0,0),
  626. array(0,0,1,0,0,0,0,0,0),
  627. array(0,1,0,0,0,0,0,0,0),
  628. array(1,1,1,1,1,1,1,1,1),
  629. array(0,0,0,0,0,0,0,0,0),
  630. ),
  631. '3' => array(
  632. array(0,0,1,1,1,1,1,0,0),
  633. array(0,1,0,0,0,0,0,1,0),
  634. array(1,0,0,0,0,0,0,0,1),
  635. array(0,0,0,0,0,0,0,0,1),
  636. array(0,0,0,0,0,0,0,0,1),
  637. array(0,0,0,0,0,0,0,0,1),
  638. array(0,0,0,0,0,0,0,1,0),
  639. array(0,0,0,0,0,1,1,0,0),
  640. array(0,0,0,0,0,0,0,1,0),
  641. array(0,0,0,0,0,0,0,0,1),
  642. array(0,0,0,0,0,0,0,0,1),
  643. array(0,0,0,0,0,0,0,0,1),
  644. array(1,0,0,0,0,0,0,0,1),
  645. array(0,1,0,0,0,0,0,1,0),
  646. array(0,0,1,1,1,1,1,0,0),
  647. ),
  648. '4' => array(
  649. array(0,0,0,0,0,0,1,1,0),
  650. array(0,0,0,0,0,1,0,1,0),
  651. array(0,0,0,0,1,0,0,1,0),
  652. array(0,0,0,1,0,0,0,1,0),
  653. array(0,0,1,0,0,0,0,1,0),
  654. array(0,1,0,0,0,0,0,1,0),
  655. array(1,0,0,0,0,0,0,1,0),
  656. array(1,0,0,0,0,0,0,1,0),
  657. array(1,1,1,1,1,1,1,1,1),
  658. array(0,0,0,0,0,0,0,1,0),
  659. array(0,0,0,0,0,0,0,1,0),
  660. array(0,0,0,0,0,0,0,1,0),
  661. array(0,0,0,0,0,0,0,1,0),
  662. array(0,0,0,0,0,0,0,1,0),
  663. array(0,0,0,0,0,0,0,1,0),
  664. ),
  665. '5' => array(
  666. array(1,1,1,1,1,1,1,1,1),
  667. array(1,0,0,0,0,0,0,0,0),
  668. array(1,0,0,0,0,0,0,0,0),
  669. array(1,0,0,0,0,0,0,0,0),
  670. array(1,0,0,0,0,0,0,0,0),
  671. array(0,1,0,0,0,0,0,0,0),
  672. array(0,0,1,1,1,1,1,0,0),
  673. array(0,0,0,0,0,0,0,1,0),
  674. array(0,0,0,0,0,0,0,0,1),
  675. array(0,0,0,0,0,0,0,0,1),
  676. array(0,0,0,0,0,0,0,0,1),
  677. array(0,0,0,0,0,0,0,0,1),
  678. array(1,0,0,0,0,0,0,0,1),
  679. array(0,1,0,0,0,0,0,1,0),
  680. array(0,0,1,1,1,1,1,0,0),
  681. ),
  682. '6' => array(
  683. array(0,0,1,1,1,1,1,0,0),
  684. array(0,1,0,0,0,0,0,1,0),
  685. array(1,0,0,0,0,0,0,0,1),
  686. array(1,0,0,0,0,0,0,0,1),
  687. array(1,0,0,0,0,0,0,0,0),
  688. array(1,0,0,0,0,0,0,0,0),
  689. array(1,0,0,1,1,1,1,0,0),
  690. array(1,0,1,0,0,0,0,1,0),
  691. array(1,1,0,0,0,0,0,0,1),
  692. array(1,0,0,0,0,0,0,0,1),
  693. array(1,0,0,0,0,0,0,0,1),
  694. array(1,0,0,0,0,0,0,0,1),
  695. array(1,0,0,0,0,0,0,0,1),
  696. array(0,1,0,0,0,0,0,1,0),
  697. array(0,0,1,1,1,1,1,0,0),
  698. ),
  699. '7' => array(
  700. array(1,1,1,1,1,1,1,1,1),
  701. array(0,0,0,0,0,0,0,0,1),
  702. array(0,0,0,0,0,0,0,1,0),
  703. array(0,0,0,0,0,0,0,1,0),
  704. array(0,0,0,0,0,0,1,0,0),
  705. array(0,0,0,0,0,1,0,0,0),
  706. array(0,0,0,0,0,1,0,0,0),
  707. array(0,0,0,0,1,0,0,0,0),
  708. array(0,0,0,1,0,0,0,0,0),
  709. array(0,0,0,1,0,0,0,0,0),
  710. array(0,0,1,0,0,0,0,0,0),
  711. array(0,1,0,0,0,0,0,0,0),
  712. array(0,1,0,0,0,0,0,0,0),
  713. array(1,0,0,0,0,0,0,0,0),
  714. array(1,0,0,0,0,0,0,0,0),
  715. ),
  716. '8' => array(
  717. array(0,0,1,1,1,1,1,0,0),
  718. array(0,1,0,0,0,0,0,1,0),
  719. array(1,0,0,0,0,0,0,0,1),
  720. array(1,0,0,0,0,0,0,0,1),
  721. array(1,0,0,0,0,0,0,0,1),
  722. array(1,0,0,0,0,0,0,0,1),
  723. array(0,1,0,0,0,0,0,1,0),
  724. array(0,0,1,1,1,1,1,0,0),
  725. array(0,1,0,0,0,0,0,1,0),
  726. array(1,0,0,0,0,0,0,0,1),
  727. array(1,0,0,0,0,0,0,0,1),
  728. array(1,0,0,0,0,0,0,0,1),
  729. array(1,0,0,0,0,0,0,0,1),
  730. array(0,1,0,0,0,0,0,1,0),
  731. array(0,0,1,1,1,1,1,0,0),
  732. ),
  733. '9' => array(
  734. array(0,0,1,1,1,1,1,0,0),
  735. array(0,1,0,0,0,0,0,1,0),
  736. array(1,0,0,0,0,0,0,0,1),
  737. array(1,0,0,0,0,0,0,0,1),
  738. array(1,0,0,0,0,0,0,0,1),
  739. array(1,0,0,0,0,0,0,0,1),
  740. array(1,0,0,0,0,0,0,1,1),
  741. array(0,1,0,0,0,0,1,0,1),
  742. array(0,0,1,1,1,1,0,0,1),
  743. array(0,0,0,0,0,0,0,0,1),
  744. array(0,0,0,0,0,0,0,0,1),
  745. array(1,0,0,0,0,0,0,0,1),
  746. array(1,0,0,0,0,0,0,0,1),
  747. array(0,1,0,0,0,0,0,1,0),
  748. array(0,0,1,1,1,1,1,0,0),
  749. ),
  750. )
  751. );
  752. }
  753. }
  754. /**
  755. * @package VC
  756. */
  757. class char_cube3d
  758. {
  759. var $bitmap;
  760. var $bitmap_width;
  761. var $bitmap_height;
  762. var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1));
  763. var $abs_x = array(1, 0);
  764. var $abs_y = array(0, 1);
  765. var $x = 0;
  766. var $y = 1;
  767. var $z = 2;
  768. var $letter = '';
  769. /**
  770. */
  771. function char_cube3d(&$bitmaps, $letter)
  772. {
  773. $this->bitmap = $bitmaps['data'][$letter];
  774. $this->bitmap_width = $bitmaps['width'];
  775. $this->bitmap_height = $bitmaps['height'];
  776. $this->basis_matrix[0][0] = mt_rand(-600, 600);
  777. $this->basis_matrix[0][1] = mt_rand(-600, 600);
  778. $this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000;
  779. $this->basis_matrix[1][0] = mt_rand(-1000, 1000);
  780. $this->basis_matrix[1][1] = mt_rand(-1000, 1000);
  781. $this->basis_matrix[1][2] = mt_rand(-1000, 1000);
  782. $this->normalize($this->basis_matrix[0]);
  783. $this->normalize($this->basis_matrix[1]);
  784. $this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]);
  785. $this->normalize($this->basis_matrix[2]);
  786. // $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0]
  787. $this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]);
  788. $this->normalize($this->basis_matrix[1]);
  789. // Make sure our cube is facing into the canvas (assuming +z == in)
  790. for ($i = 0; $i < 3; ++$i)
  791. {
  792. if ($this->basis_matrix[$i][2] < 0)
  793. {
  794. $this->basis_matrix[$i][0] *= -1;
  795. $this->basis_matrix[$i][1] *= -1;
  796. $this->basis_matrix[$i][2] *= -1;
  797. }
  798. }
  799. // Force our "z" basis vector to be the one with greatest absolute z value
  800. $this->x = 0;
  801. $this->y = 1;
  802. $this->z = 2;
  803. // Swap "y" with "z"
  804. if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2])
  805. {
  806. $this->z = 1;
  807. $this->y = 2;
  808. }
  809. // Swap "x" with "z"
  810. if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2])
  811. {
  812. $this->x = $this->z;
  813. $this->z = 0;
  814. }
  815. // Still need to determine which of $x,$y are which.
  816. // wrong orientation if y's y-component is less than it's x-component
  817. // likewise if x's x-component is less than it's y-component
  818. // if they disagree, go with the one with the greater weight difference.
  819. // rotate if positive
  820. $weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1]));
  821. // Swap "x" with "y"
  822. if ($weight > 0)
  823. {
  824. list($this->x, $this->y) = array($this->y, $this->x);
  825. }
  826. $this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]);
  827. $this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]);
  828. if ($this->abs_x[0] < 0)
  829. {
  830. $this->abs_x[0] *= -1;
  831. $this->abs_x[1] *= -1;
  832. }
  833. if ($this->abs_y[1] > 0)
  834. {
  835. $this->abs_y[0] *= -1;
  836. $this->abs_y[1] *= -1;
  837. }
  838. $this->letter = $letter;
  839. }
  840. /**
  841. * Draw a character
  842. */
  843. function drawchar($scale, $xoff, $yoff, $img, $background, $colours)
  844. {
  845. $width = $this->bitmap_width;
  846. $height = $this->bitmap_height;
  847. $bitmap = $this->bitmap;
  848. $colour1 = $colours[array_rand($colours)];
  849. $colour2 = $colours[array_rand($colours)];
  850. $swapx = ($this->basis_matrix[$this->x][0] > 0);
  851. $swapy = ($this->basis_matrix[$this->y][1] < 0);
  852. for ($y = 0; $y < $height; ++$y)
  853. {
  854. for ($x = 0; $x < $width; ++$x)
  855. {
  856. $xp = ($swapx) ? ($width - $x - 1) : $x;
  857. $yp = ($swapy) ? ($height - $y - 1) : $y;
  858. if ($bitmap[$height - $yp - 1][$xp])
  859. {
  860. $dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale);
  861. $dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale);
  862. $xo = $xoff + $dx[0] + $dy[0];
  863. $yo = $yoff + $dx[1] + $dy[1];
  864. $origin = array(0, 0, 0);
  865. $xvec = $this->scale($this->basis_matrix[$this->x], $scale);
  866. $yvec = $this->scale($this->basis_matrix[$this->y], $scale);
  867. $face_corner = $this->sum2($xvec, $yvec);
  868. $zvec = $this->scale($this->basis_matrix[$this->z], $scale);
  869. $x_corner = $this->sum2($xvec, $zvec);
  870. $y_corner = $this->sum2($yvec, $zvec);
  871. imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1);
  872. imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2);
  873. $face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec);
  874. imagefilledpolygon($img, $face, 4, $background);
  875. imagepolygon($img, $face, 4, $colour1);
  876. }
  877. }
  878. }
  879. }
  880. /*
  881. * return a roughly acceptable range of sizes for rendering with this texttype
  882. */
  883. function range()
  884. {
  885. return array(3, 4);
  886. }
  887. /**
  888. * Vector length
  889. */
  890. function vectorlen($vector)
  891. {
  892. return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2));
  893. }
  894. /**
  895. * Normalize
  896. */
  897. function normalize(&$vector, $length = 1)
  898. {
  899. $length = (( $length < 1) ? 1 : $length);
  900. $length /= $this->vectorlen($vector);
  901. $vector[0] *= $length;
  902. $vector[1] *= $length;
  903. $vector[2] *= $length;
  904. }
  905. /**
  906. */
  907. function cross_product($vector1, $vector2)
  908. {
  909. $retval = array(0, 0, 0);
  910. $retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1]));
  911. $retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0]));
  912. $retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0]));
  913. return $retval;
  914. }
  915. /**
  916. */
  917. function sum($vector1, $vector2)
  918. {
  919. return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]);
  920. }
  921. /**
  922. */
  923. function sum2($vector1, $vector2)
  924. {
  925. return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]);
  926. }
  927. /**
  928. */
  929. function scale($vector, $length)
  930. {
  931. if (sizeof($vector) == 2)
  932. {
  933. return array($vector[0] * $length, $vector[1] * $length);
  934. }
  935. return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length);
  936. }
  937. /**
  938. */
  939. function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4)
  940. {
  941. $poly = array();
  942. $poly[0] = $xoff + $vec1[0];
  943. $poly[1] = $yoff + $vec1[1];
  944. $poly[2] = $xoff + $vec2[0];
  945. $poly[3] = $yoff + $vec2[1];
  946. $poly[4] = $xoff + $vec3[0];
  947. $poly[5] = $yoff + $vec3[1];
  948. $poly[6] = $xoff + $vec4[0];
  949. $poly[7] = $yoff + $vec4[1];
  950. return $poly;
  951. }
  952. /**
  953. * dimensions
  954. */
  955. function dimensions($size)
  956. {
  957. $xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size);
  958. $xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size);
  959. $yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size);
  960. $yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size);
  961. $p = array();
  962. $p[0] = $this->sum2($xn, $yn);
  963. $p[1] = $this->sum2($xp, $yn);
  964. $p[2] = $this->sum2($xp, $yp);
  965. $p[3] = $this->sum2($xn, $yp);
  966. $min_x = $max_x = $p[0][0];
  967. $min_y = $max_y = $p[0][1];
  968. for ($i = 1; $i < 4; ++$i)
  969. {
  970. $min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x;
  971. $min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y;
  972. $max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x;
  973. $max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y;
  974. }
  975. return array($min_x, $min_y, $max_x, $max_y);
  976. }
  977. }
  978. /**
  979. * @package VC
  980. */
  981. class colour_manager
  982. {
  983. var $img;
  984. var $mode;
  985. var $colours;
  986. var $named_colours;
  987. /**
  988. * Create the colour manager, link it to the image resource
  989. */
  990. function colour_manager($img, $background = false, $mode = 'ahsv')
  991. {
  992. $this->img = $img;
  993. $this->mode = $mode;
  994. $this->colours = array();
  995. $this->named_colours = array();
  996. if ($background !== false)
  997. {
  998. $bg = $this->allocate_named('background', $background);
  999. imagefill($this->img, 0, 0, $bg);
  1000. }
  1001. }
  1002. /**
  1003. * Lookup a named colour resource
  1004. */
  1005. function get_resource($named_colour)
  1006. {
  1007. if (isset($this->named_colours[$named_colour]))
  1008. {
  1009. return $this->named_colours[$named_colour];
  1010. }
  1011. if (isset($this->named_rgb[$named_colour]))
  1012. {
  1013. return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb');
  1014. }
  1015. return false;
  1016. }
  1017. /**
  1018. * Assign a name to a colour resource
  1019. */
  1020. function name_colour($name, $resource)
  1021. {
  1022. $this->named_colours[$name] = $resource;
  1023. }
  1024. /**
  1025. * names and allocates a colour resource
  1026. */
  1027. function allocate_named($name, $colour, $mode = false)
  1028. {
  1029. $resource = $this->allocate($colour, $mode);
  1030. if ($resource !== false)
  1031. {
  1032. $this->name_colour($name, $resource);
  1033. }
  1034. return $resource;
  1035. }
  1036. /**
  1037. * allocates a specified colour into the image
  1038. */
  1039. function allocate($colour, $mode = false)
  1040. {
  1041. if ($mode === false)
  1042. {
  1043. $mode = $this->mode;
  1044. }
  1045. if (!is_array($colour))
  1046. {
  1047. if (isset($this->named_rgb[$colour]))
  1048. {
  1049. return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb');
  1050. }
  1051. if (!is_int($colour))
  1052. {
  1053. return false;
  1054. }
  1055. $mode = 'rgb';
  1056. $colour = array(255 & ($colour >> 16), 255 & ($colour >> 8), 255 & $colour);
  1057. }
  1058. if (isset($colour['mode']))
  1059. {
  1060. $mode = $colour['mode'];
  1061. unset($colour['mode']);
  1062. }
  1063. if (isset($colour['random']))
  1064. {
  1065. unset($colour['random']);
  1066. // everything else is params
  1067. return $this->random_colour($colour, $mode);
  1068. }
  1069. $rgb = colour_manager::model_convert($colour, $mode, 'rgb');
  1070. $store = ($this->mode == 'rgb') ? $rgb : colour_manager::model_convert($colour, $mode, $this->mode);
  1071. $resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]);
  1072. $this->colours[$resource] = $store;
  1073. return $resource;
  1074. }
  1075. /**
  1076. * randomly generates a colour, with optional params
  1077. */
  1078. function random_colour($params = array(), $mode = false)
  1079. {
  1080. if ($mode === false)
  1081. {
  1082. $mode = $this->mode;
  1083. }
  1084. switch ($mode)
  1085. {
  1086. case 'rgb':
  1087. // @TODO random rgb generation. do we intend to do this, or is it just too tedious?
  1088. break;
  1089. case 'ahsv':
  1090. case 'hsv':
  1091. default:
  1092. $default_params = array(
  1093. 'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o'
  1094. 'hue_range' => false, // if hue bias, then difference range +/- from bias
  1095. 'min_saturation' => 30, // 0 - 100
  1096. 'max_saturation' => 80, // 0 - 100
  1097. 'min_value' => 30, // 0 - 100
  1098. 'max_value' => 80, // 0 - 100
  1099. );
  1100. $alt = ($mode == 'ahsv') ? true : false;
  1101. $params = array_merge($default_params, $params);
  1102. $min_hue = 0;
  1103. $max_hue = 359;
  1104. $min_saturation = max(0, $params['min_saturation']);
  1105. $max_saturation = min(100, $params['max_saturation']);
  1106. $min_value = max(0, $params['min_value']);
  1107. $max_value = min(100, $params['max_value']);
  1108. if ($params['hue_bias'] !== false)
  1109. {
  1110. if (is_numeric($params['hue_bias']))
  1111. {
  1112. $h = intval($params['hue_bias']) % 360;
  1113. }
  1114. else
  1115. {
  1116. switch ($params['hue_bias'])
  1117. {
  1118. case 'o':
  1119. $h = $alt ? 60 : 30;
  1120. break;
  1121. case 'y':
  1122. $h = $alt ? 120 : 60;
  1123. break;
  1124. case 'g':
  1125. $h = $alt ? 180 : 120;
  1126. break;
  1127. case 'c':
  1128. $h = $alt ? 210 : 180;
  1129. break;
  1130. case 'b':
  1131. $h = 240;
  1132. break;
  1133. case 'm':
  1134. $h = 300;
  1135. break;
  1136. case 'r':
  1137. default:
  1138. $h = 0;
  1139. break;
  1140. }
  1141. }
  1142. $min_hue = $h + 360;
  1143. $max_hue = $h + 360;
  1144. if ($params['hue_range'])
  1145. {
  1146. $min_hue -= min(180, $params['hue_range']);
  1147. $max_hue += min(180, $params['hue_range']);
  1148. }
  1149. }
  1150. $h = mt_rand($min_hue, $max_hue);
  1151. $s = mt_rand($min_saturation, $max_saturation);
  1152. $v = mt_rand($min_value, $max_value);
  1153. return $this->allocate(array($h, $s, $v), $mode);
  1154. break;
  1155. }
  1156. }
  1157. /**
  1158. */
  1159. function colour_scheme($resource, $include_original = true)
  1160. {
  1161. $mode = 'hsv';
  1162. if (($pre = $this->get_resource($resource)) !== false)
  1163. {
  1164. $resource = $pre;
  1165. }
  1166. $colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode);
  1167. $results = ($include_original) ? array($resource) : array();
  1168. $colour2 = $colour3 = $colour4 = $colour;
  1169. $colour2[0] += 150;
  1170. $colour3[0] += 180;
  1171. $colour4[0] += 210;
  1172. $results[] = $this->allocate($colour2, $mode);
  1173. $results[] = $this->allocate($colour3, $mode);
  1174. $results[] = $this->allocate($colour4, $mode);
  1175. return $results;
  1176. }
  1177. /**
  1178. */
  1179. function mono_range($resource, $count = 5, $include_original = true)
  1180. {
  1181. if (is_array($resource))
  1182. {
  1183. $results = array();
  1184. for ($i = 0, $size = sizeof($resource); $i < $size; ++$i)
  1185. {
  1186. $results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original));
  1187. }
  1188. return $results;
  1189. }
  1190. $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv');
  1191. if (($pre = $this->get_resource($resource)) !== false)
  1192. {
  1193. $resource = $pre;
  1194. }
  1195. $colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode);
  1196. $results = array();
  1197. if ($include_original)
  1198. {
  1199. $results[] = $resource;
  1200. $count--;
  1201. }
  1202. // This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness.
  1203. while ($count > 0)
  1204. {
  1205. $colour[1] = ($colour[1] + mt_rand(40,60)) % 99;
  1206. $colour[2] = ($colour[2] + mt_rand(40,60));
  1207. $results[] = $this->allocate($colour, $mode);
  1208. $count--;
  1209. }
  1210. return $results;
  1211. }
  1212. /**
  1213. * Convert from one colour model to another
  1214. */
  1215. function model_convert($colour, $from_model, $to_model)
  1216. {
  1217. if ($from_model == $to_model)
  1218. {
  1219. return $colour;
  1220. }
  1221. switch ($to_model)
  1222. {
  1223. case 'hsv':
  1224. switch ($from_model)
  1225. {
  1226. case 'ahsv':
  1227. return colour_manager::ah2h($colour);
  1228. break;
  1229. case 'rgb':
  1230. return colour_manager::rgb2hsv($colour);
  1231. break;
  1232. }
  1233. break;
  1234. case 'ahsv':
  1235. switch ($from_model)
  1236. {
  1237. case 'hsv':
  1238. return colour_manager::h2ah($colour);
  1239. break;
  1240. case 'rgb':
  1241. return colour_manager::h2ah(colour_manager::rgb2hsv($colour));
  1242. break;
  1243. }
  1244. break;
  1245. case 'rgb':
  1246. switch ($from_model)
  1247. {
  1248. case 'hsv':
  1249. return colour_manager::hsv2rgb($colour);
  1250. break;
  1251. case 'ahsv':
  1252. return colour_manager::hsv2rgb(colour_manager::ah2h($colour));
  1253. break;
  1254. }
  1255. break;
  1256. }
  1257. return false;
  1258. }
  1259. /**
  1260. * Slightly altered from wikipedia's algorithm
  1261. */
  1262. function hsv2rgb($hsv)
  1263. {
  1264. colour_manager::normalize_hue($hsv[0]);
  1265. $h = $hsv[0];
  1266. $s = min(1, max(0, $hsv[1] / 100));
  1267. $v = min(1, max(0, $hsv[2] / 100));
  1268. // calculate hue sector
  1269. $hi = floor($hsv[0] / 60);
  1270. // calculate opposite colour
  1271. $p = $v * (1 - $s);
  1272. // calculate distance between hex vertices
  1273. $f = ($h / 60) - $hi;
  1274. // coming in or going out?
  1275. if (!($hi & 1))
  1276. {
  1277. $f = 1 - $f;
  1278. }
  1279. // calculate adjacent colour
  1280. $q = $v * (1 - ($f * $s));
  1281. switch ($hi)
  1282. {
  1283. case 0:
  1284. $rgb = array($v, $q, $p);
  1285. break;
  1286. case 1:
  1287. $rgb = array($q, $v, $p);
  1288. break;
  1289. case 2:
  1290. $rgb = array($p, $v, $q);
  1291. break;
  1292. case 3:
  1293. $rgb = array($p, $q, $v);
  1294. break;
  1295. case 4:
  1296. $rgb = array($q, $p, $v);
  1297. break;
  1298. case 5:
  1299. $rgb = array($v, $p, $q);
  1300. break;
  1301. default:
  1302. return array(0, 0, 0);
  1303. break;
  1304. }
  1305. return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]);
  1306. }
  1307. /**
  1308. * (more than) Slightly altered from wikipedia's algorithm
  1309. */
  1310. function rgb2hsv($rgb)
  1311. {
  1312. $r = min(255, max(0, $rgb[0]));
  1313. $g = min(255, max(0, $rgb[1]));
  1314. $b = min(255, max(0, $rgb[2]));
  1315. $max = max($r, $g, $b);
  1316. $min = min($r, $g, $b);
  1317. $v = $max / 255;
  1318. $s = (!$max) ? 0 : 1 - ($min / $max);
  1319. // if max - min is 0, we want hue to be 0 anyway.
  1320. $h = $max - $min;
  1321. if ($h)
  1322. {
  1323. switch ($max)
  1324. {
  1325. case $g:
  1326. $h = 120 + (60 * ($b - $r) / $h);
  1327. break;
  1328. case $b:
  1329. $h = 240 + (60 * ($r - $g) / $h);
  1330. break;
  1331. case $r:
  1332. $h = 360 + (60 * ($g - $b) / $h);
  1333. break;
  1334. }
  1335. }
  1336. colour_manager::normalize_hue($h);
  1337. return array($h, $s * 100, $v * 100);
  1338. }
  1339. /**
  1340. */
  1341. function normalize_hue(&$hue)
  1342. {
  1343. $hue %= 360;
  1344. if ($hue < 0)
  1345. {
  1346. $hue += 360;
  1347. }
  1348. }
  1349. /**
  1350. * Alternate hue to hue
  1351. */
  1352. function ah2h($ahue)
  1353. {
  1354. if (is_array($ahue))
  1355. {
  1356. $ahue[0] = colour_manager::ah2h($ahue[0]);
  1357. return $ahue;
  1358. }
  1359. colour_manager::normalize_hue($ahue);
  1360. // blue through red is already ok
  1361. if ($ahue >= 240)
  1362. {
  1363. return $ahue;
  1364. }
  1365. // ahue green is at 180
  1366. if ($ahue >= 180)
  1367. {
  1368. // return (240 - (2 * (240 - $ahue)));
  1369. return (2 * $ahue) - 240; // equivalent
  1370. }
  1371. // ahue yellow is at 120 (RYB rather than RGB)
  1372. if ($ahue >= 120)
  1373. {
  1374. return $ahue - 60;
  1375. }
  1376. return $ahue / 2;
  1377. }
  1378. /**
  1379. * hue to Alternate hue
  1380. */
  1381. function h2ah($hue)
  1382. {
  1383. if (is_array($hue))
  1384. {
  1385. $hue[0] = colour_manager::h2ah($hue[0]);
  1386. return $hue;
  1387. }
  1388. colour_manager::normalize_hue($hue);
  1389. // blue through red is already ok
  1390. if ($hue >= 240)
  1391. {
  1392. return $hue;
  1393. }
  1394. else if ($hue <= 60)
  1395. {
  1396. return $hue * 2;
  1397. }
  1398. else if ($hue <= 120)
  1399. {
  1400. return $hue + 60;
  1401. }
  1402. else
  1403. {
  1404. return ($hue + 240) / 2;
  1405. }
  1406. }
  1407. }
  1408. ?>