Генерация дефолтных Github аватарок

  • Tutorial

В данной статье я покажу и расскажу, как можно сгенерировать аватарки как на Github.

Результат генерации для ника "test1"
Результат генерации для ника "test1"

Для начала нужно понять, как устроена аватарка с Github'а. На первый взгляд, это просто случайный набор закрашенных квадратов (далее, блоков) в удачном порядке на сером фоне.

Сколько квадратов в аватарке
Сколько квадратов в аватарке

В каждой аватарке 12 на 12 блоков.

Случайная автарка с просторов Github
Случайная автарка с просторов Github

Взглянув на следующую картинку, думаю, вы поняли что изображения симметричны, поэтому будем генерировать матрицу блоков 6 на 12, а затем отразим и сконкатенируем две матрицы, получим матрицу 12 на 12.

Ну что ж, похоже, пора кодировать. Я буду делать это на python.

Подключим библиотеки

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

Инициализируем переменные

background_color = '#f2f1f2'
s = 'test1'

Получаем набор псевдослучайных байт. Я буду использовать хеш-функцию для того, чтобы получать картинки от конкретной строки, так результат получится интереснее.

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

Получаем цвет из хеша

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

Генерируем матрицу заполнения блоков, для этого берем следующие байты. Так как матрица 6 на 12, а информации на каждый блок у нас один бит, то нам понадобится:

6 \cdot 12 \cdot 1\text{бит} = 72 \text{бит} = 9 \text{байт}
# матрица блоков 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)

Рисуем изображения по матрице заполнения

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)

Отобразим то, что получилось

img.show()

И хоба

Результат
Результат

Хммм, что-то не то. Ах, да, забыл, самые крайние блоки всегда не цветные.

Исправим это, добавив рамку из пустых блоков.

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

Вуаля. Давайте теперь посмотрим на сгенерированные аватарки для других никнеймов.

test2
test2
test3
test3
test4
test4
test5
test5

И напоследок, специально для Хабра.

habr
habr
ufo
ufo

На этом все. Спасибо тем, кто дочитал, а тех, кто хочет экспериментировать, отправляю в свой репозиторий со всем кодом.

Средняя зарплата в IT

120 000 ₽/мес.
Средняя зарплата по всем IT-специализациям на основании 3 754 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
Реклама
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее

Комментарии 13

    +9
    По такому же принципу можно не только прямоугольники закрашивать, но и использовать хеш как рандомизатор для более сложных геометрических объектов. Я как-то с мордашками такое сделал на JS, может кому-то будет полезно/интересно.
      +2

      Классная статья, мне понравилась! Давай такую же про авы на SOF;)

        +3

        Рад, что понравилось. Если никто не опередит, то может быть сделаю.

          0

          Ещё забавные аватарки генерирует ресурс multiavatar.com

            0
            +1. Статья отличная!)
              0
              Мне тоже приглянулись эти мордочки. Если использовать хэш не только для закрашивания пикселей а и для выбора цвета из палитры, то можно получить более разнообразные узоры. Мы использовали это как «аватарки» для ключевых пар в нашем приложении

              image
                0
                Есть маленькая проблема:
                на строчке
                need_to_paint = need_color[x // block_size, y // block_size]

                выдает ошибку
                IndexError: index 12 is out of bounds for axis 1 with size 12
                если добавить по -1 к координатам, ошибка пропадает, однако изображение смещается вправо вниз на 1 блок
                  0

                  Такое происходит из-за того, что размер генерируемой картинки не кратен 12 (блоки должны быть одинакового размера). Если установить размер кратным 12, например, 420 или 240 пикселей, то ошибки не будет.

                    0
                    Разобрался сам… Таки да — размер не кратен был…
                    Однако все равно спасибо.
                  0

                  Github немного по другому генерирует аватарки, там не просто блоки закрашиваются, но и граница на 1 пиксель вокруг них. Это можно заметить, если посмотреть на то, как на оригинальных аватарках квадраты смыкаются по углам.

                    0

                    на php может кто-то перенести?

                      +1

                      Там же, вроде, Identicon используется. Разве нет?

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое