Packages
image
0.21.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/enum/blend_mode.ex
defmodule Image.BlendMode do
@moduledoc """
Functions to define and validate the blending
modes that can be applied when composing images.
"""
@default_blend_mode :VIPS_BLEND_MODE_OVER
@vips_blend_mode_list [
:VIPS_BLEND_MODE_CLEAR,
:VIPS_BLEND_MODE_SOURCE,
:VIPS_BLEND_MODE_OVER,
:VIPS_BLEND_MODE_IN,
:VIPS_BLEND_MODE_OUT,
:VIPS_BLEND_MODE_ATOP,
:VIPS_BLEND_MODE_DEST,
:VIPS_BLEND_MODE_DEST_OVER,
:VIPS_BLEND_MODE_DEST_IN,
:VIPS_BLEND_MODE_DEST_OUT,
:VIPS_BLEND_MODE_DEST_ATOP,
:VIPS_BLEND_MODE_XOR,
:VIPS_BLEND_MODE_ADD,
:VIPS_BLEND_MODE_SATURATE,
:VIPS_BLEND_MODE_MULTIPLY,
:VIPS_BLEND_MODE_SCREEN,
:VIPS_BLEND_MODE_OVERLAY,
:VIPS_BLEND_MODE_DARKEN,
:VIPS_BLEND_MODE_LIGHTEN,
:VIPS_BLEND_MODE_COLOUR_DODGE,
:VIPS_BLEND_MODE_COLOUR_BURN,
:VIPS_BLEND_MODE_HARD_LIGHT,
:VIPS_BLEND_MODE_SOFT_LIGHT,
:VIPS_BLEND_MODE_DIFFERENCE,
:VIPS_BLEND_MODE_EXCLUSION
]
# Convert the list of modes into a mapping
# from an "Elixir friendly" term to the
# underlying Vix/libvips terms
@blend_mode_map @vips_blend_mode_list
|> Enum.map(fn mode ->
["", key] =
mode
|> to_string
|> String.downcase()
|> String.split("vips_blend_mode_")
{String.to_atom(key), mode}
end)
|> Map.new()
@blend_modes Map.keys(@blend_mode_map)
@typedoc """
Blend mode to use when compositing images. See `Image.compose/3`.
* `:over` the image shows what you would expect if you held two
semi-transparent slides on top of each other. This is the default
when composing images
* `:clear` where the second image is drawn, the first is removed
* `:source` the second image is drawn as if nothing were below
* `:in` the first image is removed completely, the second is only
drawn where the first was
* `:out` the second is drawn only where the first isn't
* `:atop` this leaves the first image mostly intact, but mixes
both images in the overlapping area
* `:dest` leaves the first image untouched, the second is discarded
completely
* `:dest_over` like `:over`, but swaps the arguments
* `:dest_in` like `:in`, but swaps the arguments
* `:dest_out` like `:out`, but swaps the arguments
* `:dest_atop` like `:atop`, but swaps the arguments
* `:xor` something like a difference operator
* `:add` a bit like adding the two images
* `:saturate` a bit like the darker of the two
* `:multiply` at least as dark as the darker of the two inputs
* `:screen` at least as light as the lighter of the inputs
* `:overlay` multiplies or screens colors, depending on the lightness
* `:darken` the darker of each component
* `:lighten` the lighter of each component
* `:colour_dodge` brighten first by a factor second
* `:colour_burn` darken first by a factor of second
* `:hard_light` multiply or screen, depending on lightness
* `:soft_light` darken or lighten, depending on lightness
* `:difference` difference of the two
* `:exclusion` somewhat like :difference, but lower-contrast
"""
@type t :: unquote(Enum.reduce(@blend_modes, &{:|, [], [&1, &2]}))
@doc """
Returns the known blending modes.
See `t:Image.BlendMode.t/0` for a description
of each mode.
"""
def known_blend_modes do
@blend_modes
end
@doc """
Returns the default blend mode
### Example
iex> Image.BlendMode.default_blend_mode
:VIPS_BLEND_MODE_OVER
"""
def default_blend_mode do
@default_blend_mode
end
@doc """
Normalizes and validates a blend mode.
### Argument
* `blend_mode` is one of `Image.BlendMode.known_blend_modes/0`
as either a `t:String.t/0` or an `atom`.
### Returns
* `{:ok, atom_blend_mode}` where `atom_blend_mode` is
a valid blend mode for `libvips`
* `{:error, reason}`
### Examples
iex> Image.BlendMode.validate_blend_mode :clear
{:ok, :VIPS_BLEND_MODE_CLEAR}
iex> Image.BlendMode.validate_blend_mode "Over"
{:ok, :VIPS_BLEND_MODE_OVER}
iex> Image.BlendMode.validate_blend_mode :VIPS_BLEND_MODE_XOR
{:ok, :VIPS_BLEND_MODE_XOR}
iex> Image.BlendMode.validate_blend_mode :woops
{:error, {:error, "Unknown blend mode. Found :woops"}}
"""
@spec validate_blend_mode(t() | nil) :: {:ok, atom()} | {:error, Image.error_message()}
def validate_blend_mode(nil) do
{:ok, default_blend_mode()}
end
def validate_blend_mode(blend_mode) when blend_mode in @vips_blend_mode_list do
{:ok, blend_mode}
end
def validate_blend_mode(blend_mode) when is_atom(blend_mode) do
case Map.fetch(@blend_mode_map, blend_mode) do
{:ok, blend_mode} -> {:ok, blend_mode}
:error -> {:error, unknown_blend_mode_error(blend_mode)}
end
end
def validate_blend_mode(blend_mode) when is_binary(blend_mode) do
blend_mode
|> String.downcase()
|> String.to_existing_atom()
|> validate_blend_mode()
rescue
ArgumentError ->
{:error, unknown_blend_mode_error(blend_mode)}
end
defp unknown_blend_mode_error(blend_mode) do
{:error, "Unknown blend mode. Found #{inspect(blend_mode)}"}
end
end