diff plugins/identicon/identicon_engine.php @ 0:1e000243b222

vanilla 1.3.3 distro, I hope
author Charlie Root
date Thu, 04 Jan 2018 15:50:29 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/identicon/identicon_engine.php	Thu Jan 04 15:50:29 2018 -0500
@@ -0,0 +1,175 @@
+<?php
+
+/**
+ * @license GNU GPLv3+
+ * @author Aleksander Machniak <alec@alec.pl>
+ */
+class identicon_engine
+{
+    private $ident;
+    private $width;
+    private $height;
+    private $margin;
+    private $binary;
+    private $color;
+    private $bgcolor  = '#F9F9F9';
+    private $mimetype = 'image/png';
+    private $palette  = array(
+        '#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3',
+        '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39',
+        '#FFEB3B', '#FFC107', '#FF9800', '#FF5722', '#795548', '#607D8B',
+    );
+    private $grid = array(
+         0,  1,  2,  1,  0,
+         3,  4,  5,  4,  3,
+         6,  7,  8,  7,  6,
+         9, 10, 11, 10,  9,
+        12, 13, 14, 13, 12,
+    );
+
+    const GRID_SIZE = 5;
+    const ICON_SIZE = 150;
+
+
+    /**
+     * Class constructor
+     *
+     * @param string $ident Unique identifier (email address)
+     * @param int    $size  Icon size in pixels
+     */
+    public function __construct($ident, $size = null)
+    {
+        if (!$size) {
+            $size = self::ICON_SIZE;
+        }
+
+        $this->ident  = $ident;
+        $this->margin = (int) round($size / 10);
+        $this->width  = (int) round(($size - $this->margin * 2) / self::GRID_SIZE) * self::GRID_SIZE + $this->margin * 2;
+        $this->height = $this->width;
+
+        $this->generate();
+    }
+
+    /**
+     * Returns image mimetype
+     */
+    public function getMimetype()
+    {
+        return $this->mimetype;
+    }
+
+    /**
+     * Returns the image in binary form
+     */
+    public function getBinary()
+    {
+        return $this->binary;
+    }
+
+    /**
+     * Sends the image to the browser
+     */
+    public function sendOutput()
+    {
+        if ($this->binary) {
+            $rcmail = rcmail::get_instance();
+            $rcmail->output->future_expire_header(10 * 60);
+
+            header('Content-Type: ' . $this->mimetype);
+            header('Content-Size: ' . strlen($this->binary));
+            echo $this->binary;
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Icon generator
+     */
+    private function generate()
+    {
+        $ident = md5($this->ident, true);
+
+        // set icon color
+        $div         = intval(255/count($this->palette));
+        $index       = intval(ord($ident[0]) / $div);
+        $this->color = $this->palette[$index] ?: $this->palette[0];
+
+        // set cell size
+        $cell_width  = ($this->width - $this->margin * 2) / self::GRID_SIZE;
+        $cell_height = ($this->height - $this->margin * 2) / self::GRID_SIZE;
+
+        // create a grid
+        foreach ($this->grid as $i => $idx) {
+            $row_num    = intval($i / self::GRID_SIZE);
+            $cell_num_h = $i - $row_num * self::GRID_SIZE;
+
+            $this->grid[$i] = array(
+                'active' => ord($ident[$idx]) % 2 > 0,
+                'x1'     => $cell_width * $cell_num_h + $this->margin,
+                'y1'     => $cell_height * $row_num + $this->margin,
+                'x2'     => $cell_width * ($cell_num_h + 1) + $this->margin,
+                'y2'     => $cell_height * ($row_num + 1) + $this->margin,
+            );
+        }
+
+        // really generate the image using supported methods
+        if (function_exists('imagepng')) {
+            $this->generateGD();
+        }
+        else {
+            // log an error
+            $error = array(
+                'code'    => 500,
+                'message' => "PHP-GD module not found. It's required by identicon plugin.",
+            );
+
+            rcube::raise_error($error, true, false);
+        }
+    }
+
+    /**
+     * GD-based icon generation worker
+     */
+    private function generateGD()
+    {
+        $color   = $this->toRGB($this->color);
+        $bgcolor = $this->toRGB($this->bgcolor);
+
+        // create an image, setup colors
+        $image   = imagecreate($this->width, $this->height);
+        $color   = imagecolorallocate($image, $color[0], $color[1], $color[2]);
+        $bgcolor = imagecolorallocate($image, $bgcolor[0], $bgcolor[1], $bgcolor[2]);
+
+        imagefilledrectangle($image, 0, 0, $this->width, $this->height, $bgcolor);
+
+        // draw the grid created in self::generate()
+        foreach ($this->grid as $item) {
+            if ($item['active']) {
+                imagefilledrectangle($image, $item['x1'], $item['y1'], $item['x2'], $item['y2'], $color);
+            }
+        }
+
+        // generate an image and save it to a variable
+        ob_start();
+        imagepng($image, null, 6, PNG_ALL_FILTERS);
+        $this->binary = ob_get_contents();
+        ob_end_clean();
+
+        // cleanup
+        imagedestroy($image);
+    }
+
+    /**
+     * Convert #FFFFFF color format to 3-value RGB
+     */
+    private function toRGB($color)
+    {
+        preg_match('/^#?([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/i', $color, $m);
+
+        return array(hexdec($m[1]), hexdec($m[2]), hexdec($m[3]));
+    }
+}