defmodule IdenticonGenerator do
@moduledoc """
Rules for generating an identicon.
250x250px image composed by 25 50x50px squares.
The left side of the identicon is always mirrored to the right side.
"""
def main(input) do
input
|> create_seed
|> pick_color
|> build_grid
|> filter_odds
|> build_pixel_map
|> draw_image
|> save_image(input)
end
@doc """
Saves the `image` with the `filename` given.
"""
def save_image(image, filename) do
File.write("#{filename}.png", image)
end
@doc """
"""
def draw_image(%IdenticonGenerator.Image{color: color, pixel_map: pixel_map}) do
image = :egd.create(250, 250)
fill = :egd.color(color)
Enum.each pixel_map, fn({start, stop}) ->
:egd.filledRectangle(image, start, stop, fill)
end
:egd.render(image)
end
def build_pixel_map(%IdenticonGenerator.Image{grid: grid} = image) do
pixel_map = Enum.map grid, fn({_code, index}) ->
x = rem(index, 5) * 50
y = div(index, 5) * 50
start_point = {x, y}
end_point = {x+50, y+50}
{start_point, end_point}
end
%IdenticonGenerator.Image{image | pixel_map: pixel_map}
end
def filter_odds(%IdenticonGenerator.Image{grid: grid} = image) do
grid =
Enum.filter grid, fn({code, _index}) ->
rem(code, 2) == 0 #if true Enum.filter will keep
end
%IdenticonGenerator.Image{image | grid: grid}
end
@doc """
Returns a list of lists representing a grid.
"""
def build_grid(%IdenticonGenerator.Image{seed: seed} = image) do
grid =
seed
|> Enum.chunk_every(3, 3, :discard)
|> Enum.map(&mirror_row/1)
|> List.flatten
|> Enum.with_index
%IdenticonGenerator.Image{image | grid: grid}
end
@doc """
Returns a list. The second index of `row` is appended as the third index. The first index of `row` is appended as the fourth index.
"""
def mirror_row(row) do
[first, second | _tail] = row
row ++ [second, first]
end
@doc """
Returns a new struct from `image` and `color`.
"""
def pick_color(%IdenticonGenerator.Image{seed: [r, g, b | _tail]} = image) do
%IdenticonGenerator.Image{image | color: {r, g, b}}
end
@doc """
Returns a list generated from the `input` given.
## Examples
iex> IdenticonGenerator.create_hash("John")
[97, 64, 154, 161, 253, 71, 212, 165, 51, 45, 226, 60, 191, 89, 163, 111]
"""
def create_seed(input) do
seed =
:crypto.hash(:md5, input)
|> :binary.bin_to_list
%IdenticonGenerator.Image{seed: seed}
end
end