Current section
Files
Jump to
Current section
Files
lib/identicon.ex
defmodule Identicon do
@moduledoc """
This library generates GitHub-like identicons. Unlike
GitHub's identicons, the identicons this library generates
are not symmetrical.
Given an input of a string you will receive a base64
encoded png of 5x5 identicon for that string.
"""
defstruct color: nil, hex_code: nil, grid: nil, md5: nil, pixels: nil
def render(input) do
input
|> hash_input
|> extract_color
|> build_grid
|> calculate_pixels
|> draw_image
end
defp hash_input(string) do
hex_code = :crypto.hash(:md5, string) |> :binary.bin_to_list
md5 = Enum.flat_map(hex_code, &(:io_lib.format("~2.16.0b", [&1]))) |> Enum.join("")
%Identicon{hex_code: hex_code, md5: md5}
end
defp extract_color(%Identicon{hex_code: [r, g, b | _]} = identicon) do
%Identicon{identicon | color: {r, g, b}}
end
defp build_grid(%Identicon{md5: md5} = identicon) do
grid = String.slice(md5, 6..30)
|> String.split("", trim: true)
|> Enum.map(&(:erlang.binary_to_integer(&1, 16)))
|> Enum.with_index
|> Enum.filter(fn({code, _index}) -> rem(code, 2) == 0 end)
%Identicon{identicon | grid: grid}
end
defp calculate_pixels(%Identicon{grid: grid} = identicon) do
pixels = Enum.map(grid, fn({_code, index}) ->
row = div(index, 5)
column = rem(index, 5)
top_left = {row * 50, column * 50}
bottom_right = {row * 50 + 50, column * 50 + 50}
{top_left, bottom_right}
end)
%Identicon{identicon | pixels: pixels}
end
defp draw_image(%Identicon{color: color, pixels: pixels}) do
image = :egd.create(250, 250)
fill = :egd.color(color)
Enum.each(pixels, fn({start, stop}) ->
:egd.filledRectangle(image, start, stop, fill)
end)
:egd.render(image, :png) |> Base.encode64
end
end