-module(glidicon). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([color/1, hash/1, image/1, create/1]). -export_type([identicon/0]). -opaque identicon() :: {identicon, bitstring(), {integer(), integer(), integer()}, binary()}. -spec color(identicon()) -> {integer(), integer(), integer()}. color(Identicon) -> erlang:element(3, Identicon). -spec hash(identicon()) -> bitstring(). hash(Identicon) -> erlang:element(2, Identicon). -spec image(identicon()) -> binary(). image(Identicon) -> erlang:element(4, Identicon). -spec identicon() -> identicon(). identicon() -> {identicon, <<>>, {0, 0, 0}, <<""/utf8>>}. -spec set_hash(identicon(), binary()) -> identicon(). set_hash(Identicon, Input) -> erlang:setelement( 2, Identicon, gleam_crypto_ffi:hash(md5, gleam_stdlib:identity(Input)) ). -spec set_color(identicon()) -> identicon(). set_color(Identicon) -> _assert_subject = erlang:element(2, Identicon), <> = case _assert_subject of <<_, _, _, _/bitstring>> -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glidicon"/utf8>>, function => <<"set_color"/utf8>>, line => 45}) end, erlang:setelement(3, Identicon, {R, G, B}). -spec chunk(bitstring()) -> list({integer(), integer(), integer()}). chunk(Bits) -> case Bits of <> -> [{A, B, C} | chunk(Rest)]; _ -> [] end. -spec mirror_chunks(list({integer(), integer(), integer()})) -> list(list(integer())). mirror_chunks(Chunks) -> gleam@list:map( Chunks, fun(Chunk) -> {A, B, C} = Chunk, [A, B, C, B, A] end ). -spec add_indices(list(integer())) -> list({integer(), integer()}). add_indices(Bits) -> _pipe = Bits, gleam@list:index_map(_pipe, fun(Val, Index) -> {Index, Val} end). -spec remove_odd_values(list({integer(), integer()})) -> list({integer(), integer()}). remove_odd_values(Bits) -> gleam@list:filter( Bits, fun(Bit) -> gleam@int:is_even(erlang:element(2, Bit)) end ). -spec calculate_diagonals(list({integer(), integer()})) -> list({{integer(), integer()}, {integer(), integer()}}). calculate_diagonals(Bits) -> gleam@list:map( Bits, fun(Bit) -> {Index, _} = Bit, Horizontal = (Index rem 5) * 50, Vertical = (Index div 5) * 50, Top_left = {Horizontal, Vertical}, Bottom_right = {Horizontal + 50, Vertical + 50}, {Top_left, Bottom_right} end ). -spec draw_image( list({{integer(), integer()}, {integer(), integer()}}), {integer(), integer(), integer()} ) -> binary(). draw_image(Diagonals, Color) -> Image = egd:create(250, 250), Fill_color = egd:color(Color), gleam@list:each( Diagonals, fun(Diagonal) -> {Top_left, Bottom_right} = Diagonal, egd:'filledRectangle'(Image, Top_left, Bottom_right, Fill_color) end ), egd:render(Image). -spec set_image(identicon()) -> identicon(). set_image(Identicon) -> erlang:setelement( 4, Identicon, begin _pipe = erlang:element(2, Identicon), _pipe@1 = chunk(_pipe), _pipe@2 = mirror_chunks(_pipe@1), _pipe@3 = gleam@list:flatten(_pipe@2), _pipe@4 = add_indices(_pipe@3), _pipe@5 = remove_odd_values(_pipe@4), _pipe@6 = calculate_diagonals(_pipe@5), draw_image(_pipe@6, erlang:element(3, Identicon)) end ). -spec create(binary()) -> identicon(). create(Input) -> _pipe = identicon(), _pipe@1 = set_hash(_pipe, Input), _pipe@2 = set_color(_pipe@1), set_image(_pipe@2).