defmodule Image.Options.LocalContrast do @moduledoc """ Options and option validation for `Image.local_contrast/2`. """ @typedoc """ Options applicable to `Image.local_contrast/2`. """ @type local_contrast_option :: {:window_size, pos_integer()} | {:max_slope, non_neg_integer()} @typedoc """ Options list or map for `Image.local_contrast/2`. """ @type local_contrast_options :: [local_contrast_option()] | map() # Default window size in pixels over which the # local contrast is evaluated @default_window_size 3 # Integral level of brightening, between 0 and # 100, where 0 (the default) disables contrast limiting. @default_max_slope 0 @doc """ Validate the options for `Image.local_contrast/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 -> {:ok, Map.new(options)} end end defp validate_option({:window_size, window_size}, options) when is_integer(window_size) and window_size > 0 do {:cont, options} end defp validate_option({:max_slope, max_slope}, options) when is_integer(max_slope) and max_slope >= 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 defp default_options do [ window_size: @default_window_size, max_slope: @default_max_slope ] end end