Packages
image
0.7.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/color.ex
defmodule Image.Color do
@moduledoc """
Functions to manage image color and color conversion.
"""
@typedoc """
An rbg color expressed as a list of numbers.
The number of list elements and the type
varies depending on the image format, colorspace
and dimensions.
For a common `sRGB` image it will be a list of
three of four images. If the fourth number is provided
it will be considered as an alpha transparency band.
"""
@type rgb_color :: [number()]
@typedoc """
A color can be expressed as a list of numbers or
as a CSS color name in atom or string format.
"""
@type t :: rgb_color | atom() | String.t()
@typedoc """
Reference to an ICC color profile
* `:none` means no profile
* `:cmyk`, `:srgb` and `:p3` refer to the built-in color profiles
* `Path.t()` means any file system path. If the path is a relative
path then is will be loaded from the systems profile directory.
"""
@type icc_profile :: :none | :cmyk | :srgb | :p3 | Path.t()
@inbuilt_profiles [:none, :srgb, :cmyk, :p3]
@doc """
Guards whether a given value can be interpreted
as a color value.
"""
defguard is_color(color)
when (is_number(color) and color >= 0) or (is_list(color) and length(color) in 3..5)
@doc """
Guards whether a given profile is one of the inbuilt
profiles.
"""
defguard is_inbuilt_profile(profile) when profile in @inbuilt_profiles
@doc """
Returns the list of color profiles built into
`libvips`.
"""
def inbuilt_profiles, do: @inbuilt_profiles
@doc """
Returns a boolean indicating if the given
profile is known and can be used for image
operations.
"""
def known_icc_profile?(profile) when profile in @inbuilt_profiles do
true
end
def known_icc_profile?(path) do
case Vix.Vips.Operation.profile_load(path) do
{:ok, _} -> true
_other -> false
end
end
@priv_dir :code.priv_dir(:image) |> List.to_string()
@path Path.join(@priv_dir, "color_map.csv")
@color_map File.read!(@path)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, ", "))
|> Enum.map(fn [name, hex] ->
<<"#", r::bytes-2, g::bytes-2, b::bytes-2>> = hex
rgb = [String.to_integer(r, 16), String.to_integer(g, 16), String.to_integer(b, 16)]
{String.downcase(name), hex: hex, rgb: rgb}
end)
|> Map.new()
@doc """
Returns a mapping from CSS color names to CSS hex values
and RGB triplets as a list.
"""
def color_map do
@color_map
end
def rgb_color(color) when is_binary(color) or is_atom(color) do
case color do
<<"#", r::bytes-2, g::bytes-2, b::bytes-2>> ->
[String.to_integer(r, 16), String.to_integer(g, 16), String.to_integer(b, 16)]
color ->
case Map.fetch(color_map(), normalize(color)) do
{:ok, color} -> {:ok, color}
:error -> {:error, "Invalid color #{inspect color}"}
end
end
end
def rgb_color(color) when is_color(color) do
{:ok, color}
end
def rgb_color!(color) do
case rgb_color(color) do
{:ok, color} -> color
{:error, reason} -> raise ArgumentError, reason
end
end
@opacity 255
def rgba_color!(color, a \\ @opacity)
def rgba_color!(color, _a) when color in [:none, :transparent] do
[0.0, 0.0, 0.0, 1.0]
end
def rgba_color!(color, a) when is_binary(color) and is_integer(a) do
[r, g, b] = rgb_color!(color)
[r, g, b, a]
end
def rgba_color!(color, a)
when (is_binary(color) or is_atom(color)) and is_float(a) and a >= 0.0 and a <= 1.0 do
a = round(@opacity * a)
[r, g, b] = Keyword.get(rgb_color!(color), :rgb, color)
[r, g, b, a]
end
def rgba_color!([r, g, b], a) do
[r, g, b, a]
end
def normalize(color) do
color
|> to_string()
|> String.downcase()
|> String.replace(["_", "-", " "], "")
end
end