diff --git a/lib/color/col1b.ex b/lib/color/col1b.ex index 8c6cff3..8f5de1f 100644 --- a/lib/color/col1b.ex +++ b/lib/color/col1b.ex @@ -73,20 +73,18 @@ defmodule Exa.Color.Col1b do # binary conversions ---------- - @c1 [:gray, :index] - @behaviour Colorb @impl Colorb - def to_bin(i, pix \\ :gray) when pix in @c1 and is_col1b(i), + def to_bin(pix \\ :gray, i) when is_pix1(pix) and is_col1b(i), do: <> @impl Colorb - def append_bin(buf, pix \\ :gray, i) when pix in @c1 and is_binary(buf) and is_col1b(i), + def append_bin(pix \\ :gray, buf, i) when is_pix1(pix) and is_binary(buf) and is_col1b(i), do: <> @impl Colorb - def from_bin(<>, pix \\ :gray) when pix in @c1, + def from_bin(pix \\ :gray, <>) when is_pix1(pix), do: {i, rest} # ----------------- diff --git a/lib/color/col3b.ex b/lib/color/col3b.ex index 416d182..37b243c 100644 --- a/lib/color/col3b.ex +++ b/lib/color/col3b.ex @@ -184,15 +184,15 @@ defmodule Exa.Color.Col3b do @behaviour Colorb @impl Colorb - def to_bin(col, pix \\ :rgb) when is_pix3(pix), - do: append_bin(<<>>, pix, col) + def to_bin(pix \\ :rgb, col) when is_pix3(pix), + do: append_bin(pix, <<>>, col) @impl Colorb - def append_bin(buf, pix \\ :rgb, {c1, c2, c3}) when is_pix3(pix) and is_binary(buf), + def append_bin(pix \\ :rgb, buf, {c1, c2, c3}) when is_pix3(pix) and is_binary(buf), do: <> @impl Colorb - def from_bin(<>, pix \\ :rgb) when is_pix3(pix), + def from_bin(pix \\ :rgb, <>) when is_pix3(pix), do: {{c1, c2, c3}, rest} # ----------------- diff --git a/lib/color/col4b.ex b/lib/color/col4b.ex index a11ea47..196973c 100644 --- a/lib/color/col4b.ex +++ b/lib/color/col4b.ex @@ -10,6 +10,7 @@ defmodule Exa.Color.Col4b do require Logger import Exa.Types + import Exa.Color.Types alias Exa.Color.Types, as: C alias Exa.Math @@ -146,19 +147,17 @@ defmodule Exa.Color.Col4b do # unless the src and dst pixels are different # then need 2 args - @c4 [:rgba, :argb, :bgra, :abgr] - @behaviour Colorb @impl Colorb - def to_bin(col, pix \\ :rgba) when pix in @c4, - do: append_bin(<<>>, pix, col) + def to_bin(pix \\ :rgba, col) when is_pix4(pix), + do: append_bin(pix, <<>>, col) @impl Colorb - def append_bin(buf, pix \\ :rgba, {c1, c2, c3, c4}) when pix in @c4 and is_binary(buf), + def append_bin(pix \\ :rgba, buf, {c1, c2, c3, c4}) when is_pix4(pix) and is_binary(buf), do: <> @impl Colorb - def from_bin(<>, pix \\ :rgba) when pix in @c4, + def from_bin(pix \\ :rgba, <>) when is_pix4(pix), do: {{c1, c2, c3, c4}, rest} end diff --git a/lib/color/colorb.ex b/lib/color/colorb.ex index c796eab..d865ee0 100644 --- a/lib/color/colorb.ex +++ b/lib/color/colorb.ex @@ -1,48 +1,49 @@ defmodule Exa.Color.Colorb do - @moduledoc "A behaviour for byte colors." + @moduledoc """ + A behaviour for byte colors, + with a generic interface that dispatches + to concrete implementations. + """ - import Exa.Color.Types alias Exa.Color.Types, as: C alias Exa.Color.Col1b alias Exa.Color.Col3b alias Exa.Color.Col4b + # dispatch map from tags to implementation module + @disp %{ + :gray => Col1b, + :index => Col1b, + :rgb => Col3b, + :bgr => Col3b, + :rgba => Col4b, + :bgra => Col4b, + :argb => Col4b, + :abgr => Col4b, + } + + # it's more natural to have the buffer as first arg for piping + # but dispatching implementations must have the tag as 1st arg + @doc "Convert a color to a binary." - @callback to_bin(C.colorb(), C.pixel()) :: binary() + @callback to_bin(C.pixel(), C.colorb()) :: binary() @doc "Append a color to a binary." - @callback append_bin(binary(), C.pixel(), C.colorb()) :: binary() + @callback append_bin(C.pixel(), binary(), C.colorb()) :: binary() @doc "Read a color from a binary." - @callback from_bin(binary(), C.pixel()) :: {C.colorb(), binary()} - - # kinda like a protocol, but with tagged pixels instead of a struct... - - def from_bin(buf, :gray), do: Col1b.from_bin(buf, :gray) - def from_bin(buf, :index), do: Col1b.from_bin(buf, :index) - def from_bin(buf, :rgb), do: Col3b.from_bin(buf, :rgb) - def from_bin(buf, :bgr), do: Col3b.from_bin(buf, :bgr) - def from_bin(buf, :rgba), do: Col4b.from_bin(buf, :rgba) - def from_bin(buf, :bgra), do: Col4b.from_bin(buf, :bgra) - def from_bin(buf, :argb), do: Col4b.from_bin(buf, :argb) - def from_bin(buf, :abgr), do: Col4b.from_bin(buf, :abgr) - - def append_bin(buf, :gray, col), do: Col1b.append_bin(buf, :gray, col) - def append_bin(buf, :index, col), do: Col1b.append_bin(buf, :index, col) - def append_bin(buf, :rgb, col), do: Col3b.append_bin(buf, :rgb, col) - def append_bin(buf, :bgr, col), do: Col3b.append_bin(buf, :bgr, col) - def append_bin(buf, :rgba, col), do: Col4b.append_bin(buf, :rgba, col) - def append_bin(buf, :bgra, col), do: Col4b.append_bin(buf, :bgra, col) - def append_bin(buf, :argb, col), do: Col4b.append_bin(buf, :argb, col) - def append_bin(buf, :abgr, col), do: Col4b.append_bin(buf, :abgr, col) - - def to_bin(col, :gray) when is_col1b(col), do: Col1b.to_bin(col, :gray) - def to_bin(col, :index) when is_col1b(col), do: Col1b.to_bin(col, :index) - def to_bin(col, :rgb) when is_col3b(col), do: Col3b.to_bin(col, :rgb) - def to_bin(col, :bgr) when is_col3b(col), do: Col3b.to_bin(col, :bgr) - def to_bin(col, :argb) when is_col4b(col), do: Col4b.to_bin(col, :argb) - def to_bin(col, :abgr) when is_col4b(col), do: Col4b.to_bin(col, :abgr) - def to_bin(col, :rgba) when is_col4b(col), do: Col4b.to_bin(col, :rgba) - def to_bin(col, :bgra) when is_col4b(col), do: Col4b.to_bin(col, :bgra) + @callback from_bin(C.pixel(), binary()) :: {C.colorb(), binary()} + + def from_bin(pix, buf) do + Exa.Dispatch.dispatch(@disp, pix, :from_bin, [buf]) + end + + def append_bin(pix, buf, col) do + Exa.Dispatch.dispatch(@disp, pix, :append_bin, [buf, col]) + end + + def to_bin(pix, col) do + Exa.Dispatch.dispatch(@disp, pix, :to_bin, [col]) + end end