defmodule Image.Options.ChromaKey do
@moduledoc """
Options and option validation for `Image.chroma_key/2`.
"""
alias Image.Color
@typedoc """
Options applicable to Image.chroma_key/2
"""
@type chroma_key_options ::
[
{:color, Color.t() | :auto}
| {:threshold, non_neg_integer()}
| {:greater_than, Color.t()}
| {:less_than, Color.t()}
| {:sigma, float()}
| {:min_amplitude, float()}
]
| map()
@doc """
Validate the options for `Image.chroma_key/2`.
"""
def validate_options(options) when is_list(options) do
options = Keyword.merge(default_options(), options)
case Enum.reduce_while(options, options, &validate_option(&1, &2)) do
{:error, value} ->
{:error, value}
options ->
select_strategy(Map.new(options))
end
end
def validate_options(%{} = options) do
{:ok, options}
end
defp validate_option({:color, :auto}, options) do
{:cont, options}
end
defp validate_option({key, color} = option, options)
when key in [:greater_than, :less_than, :color] do
case Color.rgb_color(color) do
{:ok, hex: _hex, rgb: color} -> {:cont, Keyword.put(options, key, color)}
{:ok, color} -> {:cont, Keyword.put(options, key, color)}
_other -> {:halt, invalid_option(option)}
end
end
defp validate_option({:threshold, threshold}, options)
when is_integer(threshold) and threshold >= 0 do
{:cont, options}
end
defp validate_option({:sigma, sigma}, options) when is_number(sigma) and sigma > 0 do
{:cont, options}
end
defp validate_option({:min_amplitude, min_amplitude}, options) when is_float(min_amplitude) do
{:cont, Keyword.put(options, :min_amplitude, min_amplitude)}
end
defp validate_option(option, _options) do
{:halt, {:error, invalid_option(option)}}
end
defp invalid_option(option) do
"Invalid option or option value: #{inspect(option)}"
end
defp select_strategy(%{greater_than: _, less_than: _} = options) do
options =
options
|> Map.delete(:color)
|> Map.delete(:threshold)
{:ok, options}
end
defp select_strategy(%{color: _, threshold: _} = options) do
options =
options
|> Map.delete(:greater_than)
|> Map.delete(:less_than)
{:ok, options}
end
defp select_strategy(options) do
{
:error,
"Invalid options #{inspect(options)}. Options need to have either :greater_than " <>
" and :less_than or :color and :threshold."
}
end
defp default_options do
[
color: :auto,
threshold: 20
]
end
end