Module: Users::AvatarHelper

Includes:
Magick
Defined in:
app/helpers/users/avatar_helper.rb

Instance Method Summary collapse

Instance Method Details

#user_auto_avatar(size, user: nil) ⇒ Magick::Image #user_auto_avatar(size, letter: nil, color: nil) ⇒ Magick::Image

Creates an avatar image based either on a user account or on provided values.

Examples:

Generate an avatar for the current user:

helpers.user_auto_avatar(64, user: current_user)

Generate a generic avatar:

helpers.user_auto_avatar(32, letter: 'A', color: '#3C0FFEE5')

Overloads:

  • #user_auto_avatar(size, user: nil) ⇒ Magick::Image

    Parameters:

    • size (Integer)

      The side length of the final image, in pixels. O(n^2) at minimum - large values will take exponentially longer to generate.

    • user (User) (defaults to: nil)

      A user object from which to take the avatar letter and color

  • #user_auto_avatar(size, letter: nil, color: nil) ⇒ Magick::Image

    Parameters:

    • size (Integer)

      The side length of the final image, in pixels. O(n^2) at minimum - large values will take exponentially longer to generate.

    • letter (String) (defaults to: nil)

      A single character to display on the avatar if user is not set

    • color (String) (defaults to: nil)

      An 8-digit hex code, with leading #, to color the avatar background if user is not set

Returns:

  • (Magick::Image)

    The generated avatar

Raises:

  • (ArgumentError)

    If a user or letter-color combination is not provided.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/helpers/users/avatar_helper.rb', line 23

def user_auto_avatar(size, user: nil, letter: nil, color: nil)
  raise ArgumentError, 'Either user or letter must be set' if user.nil? && letter.nil?
  raise ArgumentError, 'Color must be set if user is not provided' if user.nil? && color.nil?

  if letter.nil?
    letter = user.username[0]
  end
  if color.nil?
    color = "##{Digest::MD5.hexdigest(user.username)[0...6]}FF"
  end

  cache_key = if user.present?
                "network/avatars/#{user.id}/#{size}px"
              else
                "network/avatars/#{letter}+#{color}/#{size}px"
              end

  Rails.cache.fetch cache_key, include_community: false, expires_in: 24.hours do
    ava = Image.new(size, size)
    text_color = yiq_contrast(color, 'black', 'white')

    bg = Draw.new
    bg.fill color
    bg.rectangle 0, 0, size, size
    bg.draw ava

    let = Draw.new
    let.font_family = 'Roboto'
    let.font_weight = 400
    let.font = './app/assets/imgfonts/Roboto.ttf'
    let.pointsize = size * 0.75
    let.gravity = CenterGravity
    let.annotate ava, size, size * 1.16, 0, 0, letter.upcase do |s|
      s.fill = text_color
    end

    ava.format = 'PNG'
    ava
  end
end

#yiq_contrast(base, on_light, on_dark) ⇒ String

Returns on_light if the given base color is light, and vice versa. Useful for picking a text color to use on a dynamic background. Uses the YIQ color space.

Parameters:

  • base (String)

    The base/background color on which to base the calculation.

  • on_light (String)

    The text color to use on a light background.

  • on_dark (String)

    The text color to use on a dark background.

Returns:

  • (String)

    The text color to use, either on_light or on_dark.



71
72
73
74
75
76
77
78
# File 'app/helpers/users/avatar_helper.rb', line 71

def yiq_contrast(base, on_light, on_dark)
  base = base[1..]
  red = base[0...2].to_i(16)
  green = base[2...4].to_i(16)
  blue = base[4...6].to_i(16)
  yiq = ((red * 299) + (green * 587) + (blue * 114)) / 1000
  yiq >= 128 ? on_light : on_dark
end