~azzar1/unity/add-show-desktop-key

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