Packages
image
0.71.0
0.72.0
0.71.0
0.70.0
0.69.0
0.68.0
0.67.0
0.67.0-dev
retired
0.66.0
0.65.0
0.64.0
0.63.0
0.62.1
0.62.0
0.61.1
0.61.0
0.60.0
0.59.3
0.59.2
0.59.1
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.2
0.55.1
retired
0.55.0
0.54.4
0.54.3
0.54.2
0.54.1
0.54.0
0.53.0
0.52.3
0.52.2
0.52.1
0.52.0
retired
0.51.0
0.50.0
0.49.0
0.48.1
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.2
0.43.1
0.43.0
0.42.0
0.41.0
0.40.0
0.39.3
0.39.2
0.39.1
0.39.0
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.0
0.36.2
0.36.1
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.0
0.25.1
0.25.0
0.24.1
0.24.0
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
retired
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.4
0.14.2
0.14.1
0.14.0
retired
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.10.0-rc.0
retired
0.9.0
retired
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
An approachable image processing library primarily based upon Vix and libvips that is NIF-based, fast, multi-threaded, pipelined and has a low memory footprint.
Current section
Files
Jump to
Current section
Files
lib/image/options/affine.ex
defmodule Image.Options.Affine do
@moduledoc """
Options and option validation for `Image.affine/3`.
These options are shared by the affine family of
transformations: `Image.affine/3`, `Image.translate/4`
and `Image.shear/4`.
"""
alias Vix.Vips.Image, as: Vimage
alias Vix.Vips.Interpolate
alias Image.Pixel
@typedoc """
The interpolators that may be selected with the `:interpolate`
option (descriptions from `vips -l interpolate`):
* `:nearest` - nearest-neighbour interpolation
* `:bilinear` (default) - bilinear interpolation
* `:bicubic` - bicubic interpolation (Catmull-Rom)
* `:lbb` - reduced halo bicubic
* `:nohalo` - edge sharpening resampler with halo reduction
* `:vsqbs` - B-Splines with antialiasing smoothing
"""
@type interpolate ::
:nearest
| :bilinear
| :bicubic
| :lbb
| :nohalo
| :vsqbs
@typedoc """
The options applicable to an affine transformation.
"""
@type affine_options :: [
{:idx, number()}
| {:idy, number()}
| {:odx, number()}
| {:ody, number()}
| {:interpolate, interpolate()}
| {:background, Pixel.t() | :average}
| {:output_area, [integer()]}
| {:extend_mode, Image.ExtendMode.t()}
]
# The libvips nickname for each interpolator is identical to the
# public atom, so resolution is a simple `Atom.to_string/1`.
@valid_interpolators ~w(nearest bilinear bicubic lbb nohalo vsqbs)a
@displacement_options [:idx, :idy, :odx, :ody]
@doc """
Validate the options for `Image.affine/3`.
The `image` is required to resolve the `:background` option
into a pixel matching the image's bands and color space.
See `t:Image.Options.Affine.affine_options/0`.
"""
@spec validate_options(Vimage.t(), Keyword.t()) ::
{:ok, Keyword.t()} | {:error, Image.error()}
def validate_options(image, options) do
options = Keyword.merge(default_options(), options)
case Enum.reduce_while(options, options, &validate_option(&1, image, &2)) do
{:error, value} ->
{:error, value}
options ->
{:ok, options}
end
end
defp validate_option({:interpolate, interpolate}, _image, options)
when interpolate in @valid_interpolators do
case Interpolate.new(Atom.to_string(interpolate)) do
{:ok, interpolator} ->
{:cont, Keyword.put(options, :interpolate, interpolator)}
{:error, reason} ->
{:halt, {:error, reason}}
end
end
# The public option is `:extend_mode`, renamed internally to `:extend` for `libvips`
defp validate_option({:extend_mode, extend}, _image, options)
when is_atom(extend) or is_binary(extend) do
case Image.ExtendMode.validate_extend(extend) do
{:ok, extend} ->
options =
options
|> Keyword.delete(:extend_mode)
|> Keyword.put(:extend, extend)
{:cont, options}
{:error, reason} ->
{:halt,
{:error, %Image.Error{reason: :invalid_extend_mode, value: extend, message: reason}}}
end
end
defp validate_option({:background, background}, image, options) do
case Image.BackgroundColor.resolve(image, background) do
{:ok, pixel} -> {:cont, Keyword.put(options, :background, pixel)}
{:error, reason} -> {:halt, {:error, reason}}
end
end
# The public option is `:output_area`, libvips names it `oarea`.
defp validate_option({:output_area, [left, top, width, height] = area}, _image, options)
when is_integer(left) and is_integer(top) and is_integer(width) and is_integer(height) do
options =
options
|> Keyword.delete(:output_area)
|> Keyword.put(:oarea, area)
{:cont, options}
end
defp validate_option({option, value}, _image, options)
when option in @displacement_options and is_number(value) do
{:cont, Keyword.put(options, option, value * 1.0)}
end
defp validate_option(option, _image, _options) do
{:halt, {:error, invalid_option(option)}}
end
defp invalid_option(option) do
%Image.Error{
reason: :invalid_option,
value: option,
message: "Invalid option or option value: #{inspect(option)}"
}
end
# `:extend_mode` defaults to `:background` rather than `:black`: since
# extend only governs the antialiased edge fringe (not the canvas fill),
# `:background` blends the fringe toward the fill color, whereas `:black`
# would leave a dark fringe on a non-black background.
defp default_options do
[extend_mode: :background, interpolate: :bilinear]
end
end