DEV Community

Aymane Mimouni
Aymane Mimouni

Posted on

The Easiest Way To Generate Fancy Avatars In Python

This article is originally published in my personal blog.

This is a really short article, where I will show you how to generate cool avatars from a given string (email, username...) or from your logo using python.

The idea for this article came to mind while I was working on a project where I have to set a default avatar for each user from the backend because I was dealing with a backend feeding two frontends, and maybe more in the future.

So, if you're dealing with a single frontend, you would better consider doing it from the frontend, because it's a lot easier.

Before I start, I want to mention that the professional way to do it, is by not generating the avatar, but instead using static images for default avatars, because It's quicker, simpler, less error-prone, more future-proof, and ultimately looks better than generating them programmatically.

But, if you want to be really fancy like Google and have random colored circles and initials, you’re in the right place 😎

Let’s get started!

Avatars using initials

# BUILT-IN
import re
import random

# PIP
from cairosvg import svg2png
from xml.sax.saxutils import escape as xml_escape

COLORS = [
    ['#DF7FD7', '#DF7FD7', '#591854'],
    ['#E3CAC8', '#DF8A82', '#5E3A37'],
    ['#E6845E', '#E05118', '#61230B'],
    ['#E0B050', '#E6CB97', '#614C23'],
    ['#9878AD', '#492661', '#C59BE0'],
    ['#787BAD', '#141961', '#9B9FE0'],
    ['#78A2AD', '#104F61', '#9BD1E0'],
    ['#78AD8A', '#0A6129', '#9BE0B3'],
]

INITIALS_SVG_TEMPLATE = """
<svg xmlns="http://www.w3.org/2000/svg" 
    pointer-events="none" 
    width="200" height="200">
  <defs>
    <linearGradient id="grad">
    <stop offset="0%" stop-color="{color1}" />
    <stop offset="100%" stop-color="{color2}" />
    </linearGradient>
  </defs>
  <rect width="200" height="200" rx="0" ry="0" fill="url(#grad)"></rect>
  <text text-anchor="middle" y="50%" x="50%" dy="0.35em"
        pointer-events="auto" fill="{text_color}" font-family="sans-serif"
        style="font-weight: 400; font-size: 80px">{text}</text>
</svg>
""".strip()
INITIALS_SVG_TEMPLATE = re.sub('(\s+|\n)', ' ', INITIALS_SVG_TEMPLATE)

def get_png_avatar(text, output_file):

    initials = ':)'

    text = text.strip()
    if text:
        split_text = text.split(' ')
        if len(split_text) > 1:
            initials = split_text[0][0] + split_text[-1][0]
        else:
            initials = split_text[0][0]

    random_color = random.choice(COLORS)
    svg_avatar = INITIALS_SVG_TEMPLATE.format(**{
        'color1': random_color[0],
        'color2': random_color[1],
        'text_color': random_color[2],
        'text': xml_escape(initials.upper()),
    }).replace('\n', '')

    svg2png(svg_avatar, write_to=output_file)
Enter fullscreen mode Exit fullscreen mode

What I did here is that I take a pre-prepared SVG template, I fill it with the initials, and background color, and that is it!!

Let's test it,

import string
from io import BytesIO
from PIL import Image

from avatar_generator import get_png_avatar

rawIO = BytesIO()
get_png_avatar('AymaneMx', rawIO)
byteImg = Image.open(rawIO)
filename = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
byteImg.save(filename + '.png', 'PNG')
Enter fullscreen mode Exit fullscreen mode

Run, and the result will be a PNG image like this:

Alt Text

Alt Text

While playing with the SVG template, I discovered that I can make an icon or a logo instead of a text, which brings us to the next part.

Avatars using your Logo

To use your logo, you need only to change the text tag in the previous SVG template with a tag of your logo.

For example, I will use the Twitter logo, I downloaded the SVG version from Twitter Brand Resources.

After opening it with any editor you will see:

<svg xmlns="http://www.w3.org/2000/svg" id="Logo_FIXED" data-name="Logo — FIXED" viewBox="0 0 400 400">
    <defs>
        <style>.cls-1{fill:none;}.cls-2{fill:#1da1f2;}</style>
    </defs>
    <title>Twitter_Logo_Blue</title>
    <rect class="cls-1" width="400" height="400"/>
    <path class="cls-2"
          d="M153.62,301.59c94.34,0,145.94-78.16,145.94-145.94,0-2.22,0-4.43-.15-6.63A104.36,104.36,0,0,0,325,122.47a102.38,102.38,0,0,1-29.46,8.07,51.47,51.47,0,0,0,22.55-28.37,102.79,102.79,0,0,1-32.57,12.45,51.34,51.34,0,0,0-87.41,46.78A145.62,145.62,0,0,1,92.4,107.81a51.33,51.33,0,0,0,15.88,68.47A50.91,50.91,0,0,1,85,169.86c0,.21,0,.43,0,.65a51.31,51.31,0,0,0,41.15,50.28,51.21,51.21,0,0,1-23.16.88,51.35,51.35,0,0,0,47.92,35.62,102.92,102.92,0,0,1-63.7,22A104.41,104.41,0,0,1,75,278.55a145.21,145.21,0,0,0,78.62,23"/>
</svg>
Enter fullscreen mode Exit fullscreen mode

As you may notice, the path tag is the one responsible for the logo/icon.

Let's copy that in our SVG template, group it in a g tag, and add fill argument so we can change the color,

LOGO_SVG_TEMPLATE = """
<svg xmlns="http://www.w3.org/2000/svg" width="400px" height="400px" viewBox="0 0 400 400">
    <rect class="cls-1" width="400" height="400" fill="{color1}" />
    <g width="400px" height="400px">
        <path 
            fill="{logo_color}" 
            d="M153.62,301.59c94.34,0,145.94-78.16,145.94-145.94,0-2.22,0-4.43-.15-6.63A104.36,104.36,0,0,0,325,122.47a102.38,102.38,0,0,1-29.46,8.07,51.47,51.47,0,0,0,22.55-28.37,102.79,102.79,0,0,1-32.57,12.45,51.34,51.34,0,0,0-87.41,46.78A145.62,145.62,0,0,1,92.4,107.81a51.33,51.33,0,0,0,15.88,68.47A50.91,50.91,0,0,1,85,169.86c0,.21,0,.43,0,.65a51.31,51.31,0,0,0,41.15,50.28,51.21,51.21,0,0,1-23.16.88,51.35,51.35,0,0,0,47.92,35.62,102.92,102.92,0,0,1-63.7,22A104.41,104.41,0,0,1,75,278.55a145.21,145.21,0,0,0,78.62,23"
        />
    </g>

</svg>
""".strip()
LOGO_SVG_TEMPLATE = re.sub('(\s+|\n)', ' ', LOGO_SVG_TEMPLATE)

def get_png_avatar_from_logo(output_file):

    random_color = random.choice(COLORS)

    svg_avatar = LOGO_SVG_TEMPLATE.format(**{
        'color1': random_color[0],
        'logo_color': random_color[2],
    }).replace('\n', '')

    svg2png(svg_avatar, write_to=output_file)
Enter fullscreen mode Exit fullscreen mode

Run a test,

rawIO = BytesIO()
filename = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
get_png_avatar_from_logo(rawIO)
byteImg = Image.open(rawIO)
byteImg.save(filename + '.png', 'PNG')
Enter fullscreen mode Exit fullscreen mode

The result will be something like this:

Alt Text

Now, you are maybe wondering how can I get an SVG file of my logo?

The answer to that is that you can ask your designer gently for it, or you can do it yourself, using Photoshop/Illustrator by exporting your logo as an SVG file.

But the simple way, (which is why you're here) is by using an online tool as online-convert, I use it for my shitty logo, and here is the result.

Alt Text

Isn’t so fancy!!

That's it

Here you can check out the code, you will find also its Django integration.

👉 https://github.com/aymaneMx/default-avatars

Top comments (0)