Generating default Github avatars – InformTFB

Generating default Github avatars

Generating default Github avatars

In this article, I will show and tell you how to generate avatars as on Github.

Generation result for the nickname " test1"
Generation result for the nickname ” test1″

First, you need to understand how the github avatar works. At first glance, it’s just a random set of colored squares (hereinafter referred to as blocks) in a good order on a gray background.

How many squares are there in the avatar
How many squares are there in the avatar

Each avatar has 12 by 12 blocks.

Random autark from github
Random autark from github

Looking at the following picture, I think you understand that the images are symmetrical, so we will generate a matrix of blocks 6 by 12, and then reflect and concatenate two matrices, we get a matrix of 12 by 12.

Well, it looks like it’s time to code. I’ll be doing this in python.

Enabling libraries

from PIL import ImageDraw, Image
import numpy as np
import hashlib

Initializing variables

background_color = '#f2f1f2'
s = 'test1'

We get a set of pseudo-random bytes. I will use the hash function to get images from a specific string, so the result will be more interesting.

bytes = hashlib.md5(s.encode('utf-8')).digest()

Getting the color from the hash

main_color = bytes[:3]
main_color = tuple(channel // 2 + 128 for channel in main_color) # rgb

The generated matrix filling the blocks, take the following bytes. Since the matrix is 6 by 12, and we have one bit of information for each block, we will need:6 \cdot 12 \cdot 1\text{bits} = 72 \text{bits} = 9 \text{bytes}

# матрица блоков 6 на 12
need_color = np.array([bit == '1' for byte in bytes[3:3+9] for bit in bin(byte)[2:].zfill(8)]).reshape(6, 12)

# получаем матрицу 12 на 12 сконкатенировав оригинальную и отраженную матрицу
need_color = np.concatenate((need_color, need_color[::-1]), axis=0)

Drawing images using the fill matrix

img_size = (avatar_size, avatar_size)
block_size = avatar_size // 12 # размер квадрата

img = Image.new('RGB', img_size, background_color)
draw = ImageDraw.Draw(img)

for x in range(avatar_size):
    for y in range(avatar_size):
        need_to_paint = need_color[x // block_size, y // block_size]
        if need_to_paint:
            draw.point((x, y), main_color)

Let’s display what happened

img.show()

And result

The result
The result

Hmmm, something’s not right. Oh, Yes, I forgot, the most extreme blocks are always not colored.

Fix this by adding a frame of empty blocks.

for i in range(12):
    need_color[0, i] = 0
    need_color[11, i] = 0
    need_color[i, 0] = 0
    need_color[i, 11] = 0

Voila! Now let’s take a look at the generated avatars for other nicknames.

test2
test2
test3
test3
test4
test4
test5
test5

And finally, especially for Habr.

habr
ufo
ufo

That’s all. Thanks to those who finished reading, and those who want to experiment, I send to my repository with all the code.

Valery Radokhleb
Valery Radokhleb
Web developer, designer

Leave a Reply

Your email address will not be published. Required fields are marked *