diff --git a/.gitignore b/.gitignore index d9ead4a..ca3748d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ erl_crash.dump *.ez .DS_Store + +.tool-versions diff --git a/.tool-versions b/.tool-versions index 5c72cb8..d591843 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1,2 @@ -elixir 1.6.4 +elixir 1.10.4-otp-23 +erlang 23.0-rc3 diff --git a/lib/chameleon/color.ex b/lib/chameleon/color.ex index 0d85734..4e8c941 100644 --- a/lib/chameleon/color.ex +++ b/lib/chameleon/color.ex @@ -8,7 +8,8 @@ for protocol <- [ Chameleon.Color.HSL, Chameleon.Color.HSV, Chameleon.Color.Keyword, - Chameleon.Color.Pantone + Chameleon.Color.Pantone, + Chameleon.Color.RGB888 ] do defprotocol protocol do @fallback_to_any true diff --git a/lib/chameleon/rgb.ex b/lib/chameleon/rgb.ex index a040000..246b8fd 100644 --- a/lib/chameleon/rgb.ex +++ b/lib/chameleon/rgb.ex @@ -20,6 +20,10 @@ defmodule Chameleon.RGB do def from(rgb), do: rgb end + defimpl Chameleon.Color.RGB888 do + def from(rgb), do: RGB.to_rgb888(rgb) + end + defimpl Chameleon.Color.CMYK do def from(rgb), do: RGB.to_cmyk(rgb) end @@ -46,6 +50,12 @@ defmodule Chameleon.RGB do #### / Conversion Functions / ######################################## + @doc false + @spec to_rgb888(Chameleon.RGB.t()) :: Chameleon.RGB888.t() | {:error, String.t()} + def to_rgb888(rgb) do + Chameleon.RGB888.new(rgb.r, rgb.g, rgb.b) + end + @doc false @spec to_hex(Chameleon.RGB.t()) :: Chameleon.Hex.t() | {:error, String.t()} def to_hex(rgb) do diff --git a/lib/chameleon/rgb8.ex b/lib/chameleon/rgb8.ex new file mode 100644 index 0000000..42eba2a --- /dev/null +++ b/lib/chameleon/rgb8.ex @@ -0,0 +1,31 @@ +defmodule Chameleon.RGB888 do + alias Chameleon.RGB888 + + @enforce_keys [:r, :g, :b] + defstruct @enforce_keys + + @type t() :: %__MODULE__{r: integer(), g: integer(), b: integer()} + + @doc """ + Creates a new color struct. + + ## Examples + iex> _rgb888 = Chameleon.RGB888.new(25, 30, 80) + %Chameleon.RGB888{r: 25, g: 30, b: 80} + """ + @spec new(non_neg_integer(), non_neg_integer(), non_neg_integer()) :: + Chameleon.RGB888.t() + def new(r, g, b), do: %__MODULE__{r: r, g: g, b: b} + + defimpl Chameleon.Color.RGB do + def from(rgb888), do: RGB888.to_rgb(rgb888) + end + + #### / Conversion Functions / ######################################## + + @doc false + @spec to_rgb(Chameleon.RGB888.t()) :: Chameleon.RGB.t() | {:error, String.t()} + def to_rgb(%{r: r, g: g, b: b}) do + Chameleon.RGB.new(r, g, b) + end +end diff --git a/test/rgb8_test.exs b/test/rgb8_test.exs new file mode 100644 index 0000000..7bdba6a --- /dev/null +++ b/test/rgb8_test.exs @@ -0,0 +1,92 @@ +defmodule RGB888Test do + use ExUnit.Case + use ChameleonTest.Case + + alias Chameleon.{Color, Hex, HSL, HSV, Keyword, Pantone, RGB, RGB888} + + doctest Chameleon.RGB888 + + describe "RGB and RGB888 conversions" do + test "converts from RGB to RGB888" do + for %{rgb: [r, g, b]} <- color_table() do + assert RGB888.new(r, g, b) == Chameleon.convert(RGB.new(r, g, b), Color.RGB888) + end + end + + test "converts from RGB888 to RGB" do + for %{rgb: [r, g, b]} <- color_table() do + assert RGB.new(r, g, b) == Chameleon.convert(RGB888.new(r, g, b), Color.RGB) + end + end + end + + describe "Hex and RGB888 conversions" do + test "converts from HEX to RGB888" do + for %{hex: hex, rgb: [r, g, b]} <- color_table() do + assert RGB888.new(r, g, b) == Chameleon.convert(Hex.new(hex), Color.RGB888) + end + end + + test "converts from RGB888 to HEX" do + for %{hex: hex, rgb: [r, g, b]} <- color_table() do + assert Hex.new(hex) == Chameleon.convert(RGB888.new(r, g, b), Color.Hex) + end + end + end + + describe "HSL and RGB888 conversions" do + test "converts from HSL to RGB888" do + for %{hsl: [h, s, l], rgb: [r, g, b]} <- color_table() do + assert RGB888.new(r, g, b) == Chameleon.convert(HSL.new(h, s, l), Color.RGB888) + end + end + + test "converts from CMYK to HSL" do + for %{hsl: [h, s, l], rgb: [r, g, b]} <- color_table() do + assert HSL.new(h, s, l) == Chameleon.convert(RGB888.new(r, g, b), Color.HSL) + end + end + end + + describe "HSV and RGB888 conversions" do + test "converts from HSV to RGB888" do + for %{hsv: [h, s, v], rgb: [r, g, b]} <- color_table() do + assert RGB888.new(r, g, b) == Chameleon.convert(HSV.new(h, s, v), Color.RGB888) + end + end + + test "converts from RGB888 to HSV" do + for %{hsv: [h, s, v], rgb: [r, g, b]} <- color_table() do + assert HSV.new(h, s, v) == Chameleon.convert(RGB888.new(r, g, b), Color.HSV) + end + end + end + + describe "Keyword and RGB888 conversions" do + test "converts from Keyword to RGB888" do + for %{keyword: keyword, rgb: [r, g, b]} <- color_table() do + assert RGB888.new(r, g, b) == Chameleon.convert(Keyword.new(keyword), Color.RGB888) + end + end + + test "converts from CMYK to Keyword" do + for %{keyword: keyword, rgb: [r, g, b]} <- color_table() do + assert Keyword.new(keyword) == Chameleon.convert(RGB888.new(r, g, b), Color.Keyword) + end + end + end + + describe "Pantone and CMYK conversions" do + test "converts from Pantone to CMYK" do + for %{pantone: pantone, rgb: [r, g, b]} <- color_table(), not is_nil(pantone) do + assert RGB888.new(r, g, b) == Chameleon.convert(Pantone.new(pantone), Color.RGB888) + end + end + + test "converts from CMYK to Pantone" do + for %{pantone: pantone, rgb: [r, g, b]} <- color_table(), not is_nil(pantone) do + assert Pantone.new(pantone) == Chameleon.convert(RGB888.new(r, g, b), Color.Pantone) + end + end + end +end