defmodule Image.Options.Sharpen do
@moduledoc """
Options and option validation for `Image.sharpen/2`.
"""
@typedoc """
Valid options for `Image.sharpen/2`.
"""
@type sharpen_option ::
{:jagged_amount, float()}
| {:flat_amount, float()}
| {:max_darkening, float()}
| {:max_brightening, float()}
| {:threshold, float()}
| {:sigma, float()}
@typedoc """
Options applicable to Image.sharpen/2
"""
@type sharpen_options :: [sharpen_option()] | map()
@doc """
Validate the options for `Image.sharpen/2`.
See `t:Image.Options.Sharpen.sharpen_options/0`.
"""
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 ->
{:ok, Map.new(options)}
end
end
def validate_options(%{} = options) do
{:ok, options}
end
defp validate_option({:sigma, sigma}, options)
when is_number(sigma) and sigma > 0 and sigma <= 10 do
{:cont, options}
end
defp validate_option({:jagged_amount, jagged_amount}, options)
when is_number(jagged_amount) and jagged_amount >= 0 do
{:cont, options}
end
defp validate_option({:flat_amount, flat_amount}, options)
when is_number(flat_amount) and flat_amount >= 0 do
{:cont, options}
end
defp validate_option({:threshold, threshold}, options)
when is_number(threshold) and threshold >= 0 do
{:cont, options}
end
defp validate_option({:max_brightening, max_brightening}, options)
when is_number(max_brightening) and max_brightening >= 0 do
{:cont, options}
end
defp validate_option({:max_darkening, max_darkening}, options)
when is_number(max_darkening) and max_darkening >= 0 do
{:cont, options}
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
# These defaults are appropriate for screen sharpening
defp default_options do
[
jagged_amount: 3.0,
flat_amount: 0.0,
max_darkening: 20.0,
max_brightening: 10.0,
threshold: 2.0,
sigma: 1.0
]
end
end