defmodule Graditar do require ColorUtils require XmlBuilder alias ColorUtils.{ RGB } alias Graditar.{ Avatar, Options } @moduledoc ~S""" Generate avatars made of an angled gradient ## Examples Generate a generic svg iex> Graditar.generate "\n\n\t\n\t\t\n\t\t\n\t\n\t\n" Generate from a string iex> Graditar.generate("bobthebuilder@canwefix.it") "\n\n\t\n\t\t\n\t\t\n\t\n\t\n" Add options iex> Graditar.generate("bobthebuilder@canwefix.it", %{ size: 128 }) "\n\n\t\n\t\t\n\t\t\n\t\n\t\n" """ defp gen_hash(string, _opts) do hashlist = :crypto.hash(:md5, string) |> :binary.bin_to_list %Avatar{ hex: hashlist } end defp gen_primary_color(%Avatar{ hex: [r, g, b | _] } = avatar, _opts) do color = %RGB{ red: r, green: g, blue: b } %Avatar{ avatar | primary_color: color } end defp gen_secondary_color(%Avatar{ primary_color: primary_color } = avatar, _opts) do [_, color] = ColorUtils.get_triad_colors primary_color %Avatar{ avatar | secondary_color: color } end defp gen_angle(%Avatar{ hex: [num | _] } = avatar, _opts) do # Generate an angle, one of 45, 135, 225, or 315 angle = (round(Float.floor(num / 64)) + 1) * 45 * 2 - 45 %Avatar{ avatar | angle: angle } end defp gen_svg(avatar, %{ size: size } = _opts) do %Avatar{ primary_color: primary_color, secondary_color: secondary_color, angle: angle } = avatar %RGB{ red: p_r, blue: p_b, green: p_g } = primary_color %RGB{ red: s_r, blue: s_b, green: s_g } = secondary_color primary_color_stop = XmlBuilder.element(:stop, %{ offset: "0%", "stop-color": "rgb(#{p_r}, #{p_g}, #{p_b})", "stop-opacity": "1", }) secondary_color_stop = XmlBuilder.element(:stop, %{ offset: "100%", "stop-color": "rgb(#{s_r}, #{s_g}, #{s_b})", "stop-opacity": "1", }) gradient = XmlBuilder.element(:linearGradient, %{ id: "gradient", gradientUnits: "userSpaceOnUse", gradientTransform: "rotate(#{angle} .5 .5)", x1: "0%", x2: "0%", y1: "0%", y2: "100%", }, [primary_color_stop, secondary_color_stop]) rect = XmlBuilder.element(:rect, %{ x: 0, y: 0, width: 1, height: 1, fill: "url(#gradient)", }) svg = XmlBuilder.element(:svg, %{ xmlns: "http://www.w3.org/2000/svg", width: "#{size}px", height: "#{size}px", viewBox: "0 0 1 1", preserveAspectRatio: "none", }, [gradient, rect]) XmlBuilder.doc svg end def generate(string \\ "", opts \\ %Options{}) do string |> gen_hash(opts) |> gen_primary_color(opts) |> gen_secondary_color(opts) |> gen_angle(opts) |> gen_svg(opts) end end