]> git.ipfire.org Git - ipfire.org.git/commitdiff
people: Render an avatar with letter if no avatar exists
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 21 Nov 2019 21:09:57 +0000 (21:09 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 21 Nov 2019 21:09:57 +0000 (21:09 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/web/people.py

index 893a80634fab060d722bb305e7750fc1277f35a1..1da6c27553cb3fb075097e7c23f0533cb2a37b93 100644 (file)
@@ -1,9 +1,12 @@
 #!/usr/bin/python
 
+import PIL
 import datetime
+import imghdr
+import io
 import ldap
 import logging
-import imghdr
+import os.path
 import tornado.web
 import urllib.parse
 
@@ -13,6 +16,9 @@ from . import auth
 from . import base
 from . import ui_modules
 
+COLOUR_LIGHT = (237,232,232)
+COLOUR_DARK  = (49,53,60)
+
 class IndexHandler(auth.CacheMixin, base.BaseHandler):
        @tornado.web.authenticated
        def get(self):
@@ -56,7 +62,8 @@ class AvatarHandler(base.BaseHandler):
                if not avatar:
                        logging.debug("No avatar uploaded for %s" % account)
 
-                       return self.redirect(self.static_url("img/default-avatar.jpg"))
+                       # Generate a random avatar with only one letter
+                       avatar = self._get_avatar(account, size=size)
 
                # Guess content type
                type = imghdr.what(None, avatar)
@@ -68,6 +75,62 @@ class AvatarHandler(base.BaseHandler):
                # Deliver payload
                self.finish(avatar)
 
+       def _get_avatar(self, account, size=None, **args):
+               letter = ("%s" % account)[0].upper()
+
+               if size is None:
+                       size = 256
+
+               # The generated avatar cannot be larger than 1024px
+               if size >= 2048:
+                       size = 2048
+
+               # Cache key
+               key = "avatar:letter:%s:%s" % (letter, size)
+
+               # Fetch avatar from the cache
+               avatar = self.memcached.get(key)
+               if not avatar:
+                       avatar = self._make_avatar(letter, size=size, **args)
+
+                       # Cache for forever
+                       self.memcached.set(key, avatar)
+
+               return avatar
+
+       def _make_avatar(self, letter, format="PNG", size=None, **args):
+               # Generate an image of the correct size
+               image = PIL.Image.new("RGBA", (size, size), COLOUR_LIGHT)
+
+               # Have a canvas
+               draw = PIL.ImageDraw.Draw(image)
+
+               # Load font
+               font = PIL.ImageFont.truetype(os.path.join(
+                       self.application.settings.get("static_path", ""),
+                       "fonts/Mukta-Bold.ttf"
+               ), size, encoding="unic")
+
+               # Determine size of the printed letter
+               w, h = font.getsize(letter)
+
+               # Mukta seems to be very broken and the height needs to be corrected
+               h //= 0.7
+
+               # Draw the letter in the center
+               draw.text(((size - w) / 2, (size - h) / 2), letter,
+                       font=font, fill=COLOUR_DARK)
+
+               with io.BytesIO() as f:
+                       # If writing out the image does not work with optimization,
+                       # we try to write it out without any optimization.
+                       try:
+                               image.save(f, format, optimize=True, **args)
+                       except:
+                               image.save(f, format, **args)
+
+                       return f.getvalue()
+
 
 class CallsHandler(auth.CacheMixin, base.BaseHandler):
        @tornado.web.authenticated