1<?php 2 3namespace splitbrain\RingIcon; 4 5/** 6 * Class RingIcon 7 * 8 * Generates a identicon/visiglyph like image based on concentric rings 9 * 10 * @todo add a mono color version 11 * @author Andreas Gohr <andi@splitbrain.org> 12 * @license MIT 13 * @package splitbrain\RingIcon 14 */ 15class RingIcon 16{ 17 protected $size; 18 protected $fullsize; 19 protected $rings = 4; 20 protected $center; 21 protected $ringwidth; 22 protected $seed; 23 protected $ismono = false; 24 protected $monocolor; 25 26 /** 27 * RingIcon constructor. 28 * @param int $size width and height of the resulting image 29 * @param int $rings number of rings 30 */ 31 public function __construct($size, $rings = 3) 32 { 33 $this->size = $size; 34 $this->fullsize = $this->size * 5; 35 36 $this->center = floor($this->fullsize / 2); 37 $this->ringwidth = floor($this->fullsize / $rings); 38 39 $this->seed = random_int(0, mt_getrandmax()) . time(); 40 } 41 42 /** 43 * Generates an ring image 44 * 45 * If a seed is given, the image will be based on that seed 46 * 47 * @param string $seed initialize the genrator with this string 48 * @param string $file if given, the image is saved at that path, otherwise is printed to browser 49 */ 50 public function createImage($seed = '', $file = '') 51 { 52 if (!$seed) { 53 $seed = random_int(0, mt_getrandmax()) . time(); 54 } 55 $this->seed = $seed; 56 57 // monochrome wanted? 58 if ($this->ismono) { 59 $this->monocolor = [$this->rand(20, 255), $this->rand(20, 255), $this->rand(20, 255)]; 60 } else { 61 $this->monocolor = null; 62 } 63 64 // create 65 $image = $this->createTransparentImage($this->fullsize, $this->fullsize); 66 $arcwidth = $this->fullsize; 67 for ($i = $this->rings; $i > 0; $i--) { 68 $this->drawRing($image, $arcwidth); 69 $arcwidth -= $this->ringwidth; 70 } 71 72 // resample for antialiasing 73 $out = $this->createTransparentImage($this->size, $this->size); 74 imagecopyresampled($out, $image, 0, 0, 0, 0, $this->size, $this->size, $this->fullsize, $this->fullsize); 75 if ($file) { 76 imagepng($out, $file); 77 } else { 78 header("Content-type: image/png"); 79 imagepng($out); 80 } 81 imagedestroy($out); 82 imagedestroy($image); 83 } 84 85 /** 86 * When set to true a monochrome version is returned 87 * 88 * @param bool $ismono 89 */ 90 public function setMono($ismono) 91 { 92 $this->ismono = $ismono; 93 } 94 95 /** 96 * Generate number from seed 97 * 98 * Each call runs MD5 on the seed again 99 * 100 * @param int $min 101 * @param int $max 102 * @return int 103 */ 104 protected function rand($min, $max) 105 { 106 $this->seed = md5($this->seed); 107 $rand = hexdec(substr($this->seed, 0, 8)); 108 return ($rand % ($max - $min + 1)) + $min; 109 } 110 111 /** 112 * Drawas a single ring 113 * 114 * @param resource $image 115 * @param int $arcwidth outer width of the ring 116 */ 117 protected function drawRing($image, $arcwidth) 118 { 119 $color = $this->randomColor($image); 120 $transparency = $this->transparentColor($image); 121 122 $start = $this->rand(20, 360); 123 $stop = $this->rand(20, 360); 124 if ($stop < $start) [$start, $stop] = [$stop, $start]; 125 126 imagefilledarc($image, $this->center, $this->center, $arcwidth, $arcwidth, $stop, $start, $color, IMG_ARC_PIE); 127 imagefilledellipse( 128 $image, 129 $this->center, 130 $this->center, 131 $arcwidth - $this->ringwidth, 132 $arcwidth - $this->ringwidth, 133 $transparency 134 ); 135 136 imagecolordeallocate($image, $color); 137 imagecolordeallocate($image, $transparency); 138 } 139 140 /** 141 * Allocate a transparent color 142 * 143 * @param resource $image 144 * @return int 145 */ 146 protected function transparentColor($image) 147 { 148 return imagecolorallocatealpha($image, 0, 0, 0, 127); 149 } 150 151 /** 152 * Allocate a random color 153 * 154 * @param $image 155 * @return int 156 */ 157 protected function randomColor($image) 158 { 159 if ($this->ismono) { 160 return imagecolorallocatealpha( 161 $image, 162 $this->monocolor[0], 163 $this->monocolor[1], 164 $this->monocolor[2], 165 $this->rand(0, 96) 166 ); 167 } 168 return imagecolorallocate( 169 $image, 170 $this->rand(0, 255), 171 $this->rand(0, 255), 172 $this->rand(0, 255) 173 ); 174 } 175 176 /** 177 * Create a transparent image 178 * 179 * @param int $width 180 * @param int $height 181 * @return resource 182 * @throws \Exception 183 */ 184 protected function createTransparentImage($width, $height) 185 { 186 $image = @imagecreatetruecolor($width, $height); 187 if (!$image) { 188 throw new \Exception('Missing libgd support'); 189 } 190 imagealphablending($image, false); 191 $transparency = $this->transparentColor($image); 192 imagefill($image, 0, 0, $transparency); 193 imagecolordeallocate($image, $transparency); 194 imagesavealpha($image, true); 195 return $image; 196 } 197} 198