You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

identicon_engine.php 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /**
  3. * @license GNU GPLv3+
  4. * @author Aleksander Machniak <alec@alec.pl>
  5. */
  6. class identicon_engine
  7. {
  8. private $ident;
  9. private $width;
  10. private $height;
  11. private $margin;
  12. private $binary;
  13. private $color;
  14. private $bgcolor = '#F9F9F9';
  15. private $mimetype = 'image/png';
  16. private $palette = array(
  17. '#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3',
  18. '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39',
  19. '#FFEB3B', '#FFC107', '#FF9800', '#FF5722', '#795548', '#607D8B',
  20. );
  21. private $grid = array(
  22. 0, 1, 2, 1, 0,
  23. 3, 4, 5, 4, 3,
  24. 6, 7, 8, 7, 6,
  25. 9, 10, 11, 10, 9,
  26. 12, 13, 14, 13, 12,
  27. );
  28. const GRID_SIZE = 5;
  29. const ICON_SIZE = 150;
  30. /**
  31. * Class constructor
  32. *
  33. * @param string $ident Unique identifier (email address)
  34. * @param int $size Icon size in pixels
  35. */
  36. public function __construct($ident, $size = null)
  37. {
  38. if (!$size) {
  39. $size = self::ICON_SIZE;
  40. }
  41. $this->ident = $ident;
  42. $this->margin = (int) round($size / 10);
  43. $this->width = (int) round(($size - $this->margin * 2) / self::GRID_SIZE) * self::GRID_SIZE + $this->margin * 2;
  44. $this->height = $this->width;
  45. $this->generate();
  46. }
  47. /**
  48. * Returns image mimetype
  49. */
  50. public function getMimetype()
  51. {
  52. return $this->mimetype;
  53. }
  54. /**
  55. * Returns the image in binary form
  56. */
  57. public function getBinary()
  58. {
  59. return $this->binary;
  60. }
  61. /**
  62. * Sends the image to the browser
  63. */
  64. public function sendOutput()
  65. {
  66. if ($this->binary) {
  67. $rcmail = rcmail::get_instance();
  68. $rcmail->output->future_expire_header(10 * 60);
  69. header('Content-Type: ' . $this->mimetype);
  70. header('Content-Size: ' . strlen($this->binary));
  71. echo $this->binary;
  72. return true;
  73. }
  74. return false;
  75. }
  76. /**
  77. * Icon generator
  78. */
  79. private function generate()
  80. {
  81. $ident = md5($this->ident, true);
  82. // set icon color
  83. $div = intval(255/count($this->palette));
  84. $index = intval(ord($ident[0]) / $div);
  85. $this->color = $this->palette[$index] ?: $this->palette[0];
  86. // set cell size
  87. $cell_width = ($this->width - $this->margin * 2) / self::GRID_SIZE;
  88. $cell_height = ($this->height - $this->margin * 2) / self::GRID_SIZE;
  89. // create a grid
  90. foreach ($this->grid as $i => $idx) {
  91. $row_num = intval($i / self::GRID_SIZE);
  92. $cell_num_h = $i - $row_num * self::GRID_SIZE;
  93. $this->grid[$i] = array(
  94. 'active' => ord($ident[$idx]) % 2 > 0,
  95. 'x1' => $cell_width * $cell_num_h + $this->margin,
  96. 'y1' => $cell_height * $row_num + $this->margin,
  97. 'x2' => $cell_width * ($cell_num_h + 1) + $this->margin,
  98. 'y2' => $cell_height * ($row_num + 1) + $this->margin,
  99. );
  100. }
  101. // really generate the image using supported methods
  102. if (function_exists('imagepng')) {
  103. $this->generateGD();
  104. }
  105. else {
  106. // log an error
  107. $error = array(
  108. 'code' => 500,
  109. 'message' => "PHP-GD module not found. It's required by identicon plugin.",
  110. );
  111. rcube::raise_error($error, true, false);
  112. }
  113. }
  114. /**
  115. * GD-based icon generation worker
  116. */
  117. private function generateGD()
  118. {
  119. $color = $this->toRGB($this->color);
  120. $bgcolor = $this->toRGB($this->bgcolor);
  121. // create an image, setup colors
  122. $image = imagecreate($this->width, $this->height);
  123. $color = imagecolorallocate($image, $color[0], $color[1], $color[2]);
  124. $bgcolor = imagecolorallocate($image, $bgcolor[0], $bgcolor[1], $bgcolor[2]);
  125. imagefilledrectangle($image, 0, 0, $this->width, $this->height, $bgcolor);
  126. // draw the grid created in self::generate()
  127. foreach ($this->grid as $item) {
  128. if ($item['active']) {
  129. imagefilledrectangle($image, $item['x1'], $item['y1'], $item['x2'], $item['y2'], $color);
  130. }
  131. }
  132. // generate an image and save it to a variable
  133. ob_start();
  134. imagepng($image, null, 6, PNG_ALL_FILTERS);
  135. $this->binary = ob_get_contents();
  136. ob_end_clean();
  137. // cleanup
  138. imagedestroy($image);
  139. }
  140. /**
  141. * Convert #FFFFFF color format to 3-value RGB
  142. */
  143. private function toRGB($color)
  144. {
  145. preg_match('/^#?([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/i', $color, $m);
  146. return array(hexdec($m[1]), hexdec($m[2]), hexdec($m[3]));
  147. }
  148. }