dynamic.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. from hashlib import md5
  2. from importlib import import_module
  3. import math
  4. import os
  5. from PIL import Image, ImageDraw, ImageColor, ImageFont, ImageFilter
  6. from misago.conf import settings
  7. from misago.users.avatars import store
  8. def set_avatar(user):
  9. name_bits = settings.MISAGO_DYNAMIC_AVATAR_DRAWER.split('.')
  10. drawer_module = '.'.join(name_bits[:-1])
  11. drawer_module = import_module(drawer_module)
  12. drawer_function = getattr(drawer_module, name_bits[-1])
  13. image = drawer_function(user)
  14. store.store_new_avatar(user, image)
  15. """
  16. Default drawer
  17. """
  18. def draw_default(user):
  19. image_size = max(settings.MISAGO_AVATARS_SIZES)
  20. image = Image.new("RGBA", (image_size, image_size), 0)
  21. image = draw_avatar_bg(user, image)
  22. image = draw_avatar_flavour(user, image)
  23. return image
  24. COLOR_WHEEL = ('#1abc9c', '#2ecc71', '#3498db', '#9b59b6',
  25. '#f1c40f', '#e67e22', '#e74c3c')
  26. COLOR_WHEEL_LEN = len(COLOR_WHEEL)
  27. def draw_avatar_bg(user, image):
  28. image_size = image.size
  29. color_index = user.pk - COLOR_WHEEL_LEN * (user.pk / COLOR_WHEEL_LEN)
  30. main_color = COLOR_WHEEL[color_index]
  31. rgb = ImageColor.getrgb(main_color)
  32. bg_drawer = ImageDraw.Draw(image)
  33. bg_drawer.rectangle([(0, 0), image_size], rgb)
  34. image_steps = 4
  35. step_size = math.ceil(float(image_size[0]) / image_steps)
  36. for x in xrange(image_steps):
  37. x_step = float(x + 2) / image_steps
  38. for y in xrange(image_steps):
  39. y_step = float(y + 2) / image_steps
  40. bit_rgb = (int(c * (1 - (x_step * y_step) / 5)) for c in rgb)
  41. bit_pos = (x * step_size, y * step_size)
  42. bit_size = (x * step_size + step_size, y * step_size + step_size)
  43. bg_drawer.rectangle([bit_pos, bit_size], tuple(bit_rgb))
  44. image = image.filter(ImageFilter.SHARPEN)
  45. return image
  46. FONT_FILE = os.path.join(os.path.dirname(__file__), 'font.ttf')
  47. def draw_avatar_flavour(user, image):
  48. string = user.username[0]
  49. image_size = image.size[0]
  50. max_string_size = image_size * .8
  51. size = int(max_string_size)
  52. font = ImageFont.truetype(FONT_FILE, size=size)
  53. while max(font.getsize(string)) > max_string_size:
  54. size -= 1
  55. font = ImageFont.truetype(FONT_FILE, size=size)
  56. text_size = font.getsize(string)
  57. text_pos = ((image_size - text_size[0]) / 2,
  58. (image_size - text_size[1]) / 2)
  59. text_shadow = Image.new('RGBA', image.size)
  60. shadow_color = image.getpixel((image_size - 1, image_size - 1))
  61. shadow_blur = ImageFilter.GaussianBlur(int(image_size / 5))
  62. writer = ImageDraw.Draw(text_shadow)
  63. writer.text(text_pos, string, shadow_color, font=font)
  64. text_shadow = text_shadow.filter(shadow_blur)
  65. image = Image.alpha_composite(image, text_shadow)
  66. writer = ImageDraw.Draw(image)
  67. writer.text(text_pos, string, font=font)
  68. return image
  69. """
  70. Some utils for drawring avatar programmatically
  71. """
  72. CHARS = 'qwertyuiopasdfghjklzxcvbnm1234567890'
  73. def string_to_int(string):
  74. value = 0
  75. for p, c in enumerate(string.lower()):
  76. value += p * (CHARS.find(c))
  77. return value