diff --git a/lib/color/col3b.ex b/lib/color/col3b.ex index 64ff341..416d182 100644 --- a/lib/color/col3b.ex +++ b/lib/color/col3b.ex @@ -181,20 +181,18 @@ defmodule Exa.Color.Col3b do # unless the src and dst pixels are different # then need 2 args - @c3 [:rgb, :bgr] - @behaviour Colorb @impl Colorb - def to_bin(col, pix \\ :rgb) when pix in @c3, + def to_bin(col, pix \\ :rgb) when is_pix3(pix), do: append_bin(<<>>, pix, col) @impl Colorb - def append_bin(buf, pix \\ :rgb, {c1, c2, c3}) when pix in @c3 and is_binary(buf), + def append_bin(buf, pix \\ :rgb, {c1, c2, c3}) when is_pix3(pix) and is_binary(buf), do: <> @impl Colorb - def from_bin(<>, pix \\ :rgb) when pix in @c3, + def from_bin(<>, pix \\ :rgb) when is_pix3(pix), do: {{c1, c2, c3}, rest} # ----------------- diff --git a/lib/color/colormap3b.ex b/lib/color/colormap3b.ex index 75f397c..e2fa0b5 100644 --- a/lib/color/colormap3b.ex +++ b/lib/color/colormap3b.ex @@ -1,6 +1,6 @@ defmodule Exa.Color.Colormap3b do @moduledoc """ - A map of a 1-byte index to 3-byte RGB or 4-byte RGBA colors. + A map of a 1-byte index to 3-byte RGB colors. """ require Logger @@ -17,6 +17,19 @@ defmodule Exa.Color.Colormap3b do alias Exa.Color.Col3f alias Exa.Color.ColorSpace + # intermediate colormap in col3f format + @typep cmap3f() :: %{byte() => C.col3f()} + + # special 3-component pixel type + # only for colormap arguments + + @typep pix_cmap() :: :rgb | :hsl + defguard is_pix_cmap(px) when px in [:rgb, :hsl] + + # TODO - other colormap pixel formats, gray, rgba, ... + + # TODO - factor out the gradients + # --------- # constants # --------- @@ -63,18 +76,18 @@ defmodule Exa.Color.Colormap3b do # ------------ @doc """ - Build a colormap with a list of colors. + Build a colormap with a list of 3-byte colors. The list of colors can be any size. The colors will formed into a zero-based colormap, with a contiguous range of integers `0..(length(cols)-1)`. - The pixel specifies the color format of the input colors. + The color specifies the color format of the input colors. If the pixel is HSL, the colors are converted from HSL to RGB. The final colormap is always in RGB byte format. """ - @spec new([C.col3f()], :rgb | :hsl) :: C.colormap3b() - def new(cols, pix \\ :rgb) when is_cols3f(cols) do + @spec new([C.col3f()], pix_cmap()) :: C.colormap3b() + def new(cols, pix \\ :rgb) when is_cols3f(cols) and is_pix_cmap(pix) do imax = length(cols) {^imax, cmap} = @@ -183,7 +196,7 @@ defmodule Exa.Color.Colormap3b do # private methods # --------------- - # TOCO - fix HSL interpolation + # TODO - implement HSL interpolation # when H should be nil (s == 0 or l == 0) # then keep the other H fixed as s and l are interpolated @@ -212,7 +225,7 @@ defmodule Exa.Color.Colormap3b do end # convert colormap from HSL to RGB 3f to RGB 3b - @spec convert(C.cmap3b(), C.pixel()) :: C.cmap3b() + @spec convert(cmap3f(), pix_cmap()) :: C.cmap3b() defp convert(cmap, :rgb) do for({i, c} <- cmap, into: %{}, do: {i, Col3f.to_col3b(c)}) diff --git a/lib/color/types.ex b/lib/color/types.ex index b960d54..bde0dd7 100644 --- a/lib/color/types.ex +++ b/lib/color/types.ex @@ -143,35 +143,27 @@ defmodule Exa.Color.Types do @typedoc "Color channel components." @type channel() :: :index | :gray | :a | :r | :g | :b | :h | :s | :l + defguard is_chan(ch) when ch in [:index, :gray, :a, :r, :g, :b, :h, :s, :l] @typedoc "1-channel pixel formats." @type pixel1() :: :index | :gray | :alpha + defguard is_pix1(px) when px in [:index, :gray, :alpha] @typedoc "2-channel pixel formats." @type pixel2() :: :gray_alpha | :alpha_gray + defguard is_pix2(px) when px in [:gray_alpha, :alpha_gray] @typedoc "3-channel pixel formats." @type pixel3() :: :rgb | :bgr + defguard is_pix3(px) when px in [:rgb, :bgr] @typedoc "4-channel pixel formats." @type pixel4() :: :rgba | :argb | :bgra | :abgr + defguard is_pix4(px) when px in [:rgba, :argb, :bgra, :abgr] @typedoc "All pixel formats." @type pixel() :: pixel1() | pixel2() | pixel3() | pixel4() - defguard is_pix(px) - when px in [ - :gray, - :index, - :rgb, - :rgba, - :bgr, - :argb, - :abgr, - :bgra, - :gray_alpha, - :alpha_gray, - :alpha - ] + defguard is_pix(px) when is_pix1(px) or is_pix3(px) or is_pix4(px) or is_pix2(px) @typedoc "A component of a color: byte (0..255) or unit float (0.0-1.0)." @type component() :: byte() | E.unit() @@ -281,8 +273,8 @@ defmodule Exa.Color.Types do # colormap # -------- - @typedoc "A control point to specify an indexed colormap gradient." - @type icol3f() :: {byte(), col3f()} + @typedoc "A colormap to lookup a 1-byte grayscale for a byte index." + @type cmap1b() :: %{byte() => col1b()} @typedoc "A colormap to lookup a 3-byte color for a byte index." @type cmap3b() :: %{byte() => col3b()} @@ -290,12 +282,18 @@ defmodule Exa.Color.Types do @typedoc "A colormap to lookup a 4-byte color for a byte index." @type cmap4b() :: %{byte() => col4b()} + @typedoc "A full colormap with pixel types and 1-byte lookup table." + @type colormap1b() :: {:colormap, :index, :gray, cmap1b()} + @typedoc "A full colormap with pixel types and 3-byte lookup table." @type colormap3b() :: {:colormap, :index, :rgb, cmap3b()} @typedoc "A full colormap with pixel types and 4-byte lookup table." @type colormap4b() :: {:colormap, :index, :rgba, cmap4b()} - @typedoc "Any 3- or 4-byte colormap." - @type colormap() :: colormap3b() | colormap4b() + @typedoc "Any 1,3,4-byte colormap." + @type colormap() :: colormap1b() | colormap3b() | colormap4b() + + @typedoc "A control point to specify an indexed colormap gradient." + @type icol3f() :: {byte(), col3f()} end