1<?php
2// AVAST!  This be version 2007.05.22, 8:07pm DST.
3
4// Source code copyright (c) 2007, Ben Hendel-Doying
5// A few rights reserved...
6
7// Inspired by Don Park's original idea, and Charles Darke's PHP implementation
8// (I didn't happen to like Charles Darke's implementation, so this is my own)
9// (I kind of wish my name rhymed with Park and Darke...)
10
11// Generates a 9-square "ycon" using a seed out of a few (16) shapes.
12// Interesting seeds include names, IP addresses, e-mail addresses, the current
13// temperature where you live, the phase of the moon, your cat's name, or
14// anything else.  Some of these are arguably more interesting than others >_>
15
16// THIS SOFTWARE IS PROVIDED BY Ben Hendel-Doying ``AS IS'' AND ANY
17// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL Ben Hendel-Doying BE LIABLE FOR ANY
20// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27////////////////////////////////////////////////////////////////////////////////
28
29// this is an arbitrary prime number, nice to add before hashing if you want to
30// additionally secure the seed value (ex: IP, e-mail, internal userid, etc).
31// HEY!  DON'T USE THE PRIME PROVIDED HERE!  GO FIND YOUR OWN!  FOR SERIOUSLY!
32
33$ycon_salt = 263167;
34
35// some web sites that provide prime numbers:
36//  * http://www.rsok.com/~jrm/printprimes.html
37//  * http://en.wikipedia.org/wiki/List_of_prime_numbers
38
39////////////////////////////////////////////////////////////////////////////////
40
41// the actual function!  returns a true-color image resource, suitable for
42// imagepng'ing, or whatever else you'd like to do with it.
43
44// $hash is a 16-byte hash (for example, as generated from md5())
45// $size is the total width and height, in pixels, of the ycon to be generated
46// $bg_* describe the background (transparent) color to be used, [0..255]
47
48function ycon($hash, $size, $bg_red, $bg_green, $bg_blue)
49{
50  $draw_size = $size * 4;
51
52  $red = hexdec(substr($hash, 0, 3)) % 12;       // 0-192 for color
53  $green = hexdec(substr($hash, 3, 3)) % 12;     // (in increments of 16)
54  $blue = hexdec(substr($hash, 6, 3)) % 12;
55
56  $corners = hexdec(substr($hash, 9, 1)) % 16;   // 14 gylphs
57  $corners_i = hexdec(substr($hash, 10, 1)) % 2; // inverted?
58  $corners_a = hexdec(substr($hash, 11, 1)) % 4; // 4 rotations
59
60  $edges = hexdec(substr($hash, 12, 1)) % 16;
61  $edges_i = hexdec(substr($hash, 13, 1)) % 2;
62  $edges_a = hexdec(substr($hash, 14, 1)) % 4;
63
64  $center = hexdec(substr($hash, 15, 2)) % 6;    // 3 gylphs + 3 inverted
65
66  $square = $draw_size / 3;
67
68  $icon = imagecreatetruecolor($size, $size);
69  $draw_icon = imagecreatetruecolor($draw_size, $draw_size);
70
71  $background = imagecolorallocate($icon, $bg_red, $bg_green, $bg_blue);
72  $color = imagecolorallocate($icon, $red * 16, $green * 16, $blue * 16);
73
74  imagecolortransparent($icon, $background);
75
76  $shape = $corners;
77  $inverted = ($corners_i == 0);
78  $rotation = $corners_a;
79
80  draw_glpyh($draw_icon, 0, 0, $square, $color, $background, $shape, $rotation % 4, $inverted);
81  draw_glpyh($draw_icon, $square * 2, 0, $square, $color, $background, $shape, ($rotation + 1) % 4, $inverted);
82  draw_glpyh($draw_icon, $square * 2, $square * 2, $square, $color, $background, $shape, ($rotation + 2) % 4, $inverted);
83  draw_glpyh($draw_icon, 0, $square * 2, $square, $color, $background, $shape, ($rotation + 3) % 4, $inverted);
84
85  $shape = $edges;
86  $inverted = ($edges_i == 0);
87  $rotation = $edges_a;
88
89  draw_glpyh($draw_icon, $square, 0, $square, $color, $background, $shape, $rotation % 4, $inverted);
90  draw_glpyh($draw_icon, $square * 2, $square, $square, $color, $background, $shape, ($rotation + 1) % 4, $inverted);
91  draw_glpyh($draw_icon, $square, $square * 2, $square, $color, $background, $shape, ($rotation + 2) % 4, $inverted);
92  draw_glpyh($draw_icon, 0, $square, $square, $color, $background, $shape, ($rotation + 3) % 4, $inverted);
93
94  $shape = (int)($center / 2);
95  $inverted = (($center % 2) == 0);
96
97  draw_glpyh($draw_icon, $square, $square, $square, $color, $background, $shape, 0, $inverted);
98
99  imagecopyresampled($icon, $draw_icon, 0, 0, 0, 0, $size, $size, $draw_size, $draw_size);
100
101  imagedestroy($draw_icon);
102
103  return $icon;
104}
105
106////////////////////////////////////////////////////////////////////////////////
107
108// function used internally to draw an individual glyph; one of the little guys
109// that goes into one of the 9-squares of ycon.  you probably won't need to
110// call this yourself, but there it is...
111
112function draw_glpyh(&$image, $x, $y, $full, $fg_color, $bg_color, $shape, $rotation, $inverted)
113{
114  $quarter = $full / 4;
115  $half = $full / 2;
116
117  if($inverted)
118  {
119    imagefilledpolygon($image, array(0 + $x, 0 + $y, 0 + $x, $full + $y, $full + $x, $full + $y, $full + $x, 0 + $y), 4, $fg_color);
120    $drawing_color = $bg_color;
121  }
122  else
123  {
124    imagefilledpolygon($image, array(0 + $x, 0 + $y, 0 + $x, $full + $y, $full + $x, $full + $y, $full + $x, 0 + $y), 4, $bg_color);
125    $drawing_color = $fg_color;
126  }
127
128  switch($shape)
129  {
130    // the first few shapes are visually unchanged by 90� rotations, and thus
131    // suitable for the center glyph
132
133    case 0: // full square
134      $points = array(
135        0, 0,
136        $full, 0,
137        $full, $full,
138        0, $full);
139      break;
140
141    case 1: // large diamond
142      $points = array(
143        $half, 0,
144        $full, $half,
145        $half, $full,
146        0, $half);
147      break;
148
149    case 2: // center square
150      $points = array(
151        $quarter, $quarter,
152        $half + $quarter, $quarter,
153        $half + $quarter, $half + $quarter,
154        $quarter, $half + $quarter);
155      break;
156
157    // okay, now we start with the interesting ones that change with rotation
158
159    case 3: // tilted isosceles triangle
160      $points = array(
161        $full, 0,
162        $half, $full,
163        0, $half);
164      break;
165
166    case 4: // squat isosceles triangle
167      $points = array(
168        $half, $half,
169        $full, $full,
170        0, $full);
171      break;
172
173    case 5: // corner square
174      $points = array(
175        $half, $half,
176        $half, $full,
177        0, $full,
178        0, $half);
179      break;
180
181    case 6: // rectangle
182      $points = array(
183        0, $half,
184        $full, $half,
185        $full, $full,
186        0, $full);
187      break;
188
189    case 7: // skewed hourglass on its side
190      $points = array(
191        0, 0,
192        $full, $full,
193        $full, $half,
194        0, $half);
195      break;
196
197    case 8: // upsidedown squat isosceles triangle
198      $points = array(
199        0, $half,
200        $full, $half,
201        $half, $full);
202      break;
203
204    case 9: // corner square, except one corner is pulled to the kitty-corner
205      $points = array(
206        $full, 0,
207        $half, $full,
208        0, $full,
209        0, $half);
210      break;
211
212    case 10: // large isosceles triangle
213      $points = array(
214        $half, 0,
215        $full, $full,
216        0, $full);
217      break;
218
219    case 11: // large right triangle
220      $points = array(
221        0, 0,
222        $full, $full,
223        0, $full);
224      break;
225
226    case 12: // hourglass
227      $points = array(
228        0, 0,
229        $full, $full,
230        0, $full,
231        $full, 0);
232      break;
233
234    case 13: // squat diamond
235      $points = array(
236        $quarter, 0,
237        $half, $half,
238        $quarter, $full,
239        0, $half);
240      break;
241
242    case 14: // hourglass on its side (and kinda' squished...)
243      $points = array(
244        0, $half,
245        $full, $full,
246        $full, $half,
247        0, $full);
248      break;
249
250    case 15: // corner triangle
251      $points = array(
252        0, $half,
253        $half, $half,
254        $half, $full);
255      break;
256
257    default:
258      die('$shape must be in range [0..13] (' . $shape . ' is out of range)');
259  }
260
261  // for each point
262  for($p = 0; $p < count($points) / 2; ++$p)
263  {
264    // normalized
265    $normalized_x = $points[$p * 2] - $half;
266    $normalized_y = $points[$p * 2 + 1] - $half;
267
268    // then rotate
269    for($i = 0; $i < $rotation; ++$i)
270    {
271      $old_x = $normalized_x;
272
273      $normalized_x = -$normalized_y;
274      $normalized_y = $old_x;
275    }
276
277    // then de-normalize and offset
278    $points[$p * 2] = $normalized_x + $half + $x;
279    $points[$p * 2 + 1] = $normalized_y + $half + $y;
280  }
281
282  // draw the bastard
283  imagefilledpolygon($image, $points, count($points) / 2, $drawing_color);
284}
285
286?>