Current section
Files
Jump to
Current section
Files
lib/tint.ex
defmodule Tint do
@moduledoc """
A library allowing calculations with colors and conversions between different
colorspaces.
"""
alias Tint.{CMYK, DIN99, HSV, Lab, RGB, XYZ}
@typedoc """
A type representing a color.
"""
@type color ::
CMYK.t()
| DIN99.t()
| HSV.t()
| Lab.t()
| RGB.t()
| XYZ.t()
@colorspace_aliases %{
cmyk: Tint.CMYK,
din99: Tint.DIN99,
hsv: Tint.HSV,
lab: Tint.Lab,
rgb: Tint.RGB,
xyz: Tint.XYZ
}
@typedoc """
A type representing a colorspace.
"""
@type colorspace :: atom | module
@doc """
Gets the converter module for the given colorspace atom or module.
"""
@doc since: "1.0.0"
@spec converter_for(colorspace) :: {:ok, module} | :error
def converter_for(colorspace) do
colorspace_mod = Map.get(@colorspace_aliases, colorspace, colorspace)
convertible_mod = Module.concat(colorspace_mod, Convertible)
if Code.ensure_loaded?(convertible_mod) &&
function_exported?(convertible_mod, :convert, 1) do
{:ok, convertible_mod}
else
:error
end
end
@doc """
Converts the given color to another colorspace.
## Examples
iex> Tint.convert(Tint.RGB.new(40, 66, 67), :cmyk)
{:ok, %Tint.CMYK{cyan: 0.403, magenta: 0.0149, yellow: 0.0, key: 0.7373}}
iex> Tint.convert(Tint.RGB.new(255, 127, 30), Tint.HSV)
{:ok, %Tint.HSV{hue: 25.9, saturation: 0.8824, value: 1.0}}
iex> Tint.convert(Tint.RGB.new(255, 127, 30), :invalid)
:error
"""
@doc since: "1.0.0"
@spec convert(color, colorspace) :: {:ok, color} | :error
def convert(color, colorspace) do
with {:ok, convertible_mod} <- converter_for(colorspace) do
{:ok, convertible_mod.convert(color)}
end
end
@doc """
Converts the given color to another colorspace. Raises when the colorspace
is invalid.
## Examples
iex> Tint.convert!(Tint.RGB.new(40, 66, 67), :cmyk)
%Tint.CMYK{cyan: 0.403, magenta: 0.0149, yellow: 0.0, key: 0.7373}
iex> Tint.convert!(Tint.RGB.new(255, 127, 30), Tint.HSV)
%Tint.HSV{hue: 25.9, saturation: 0.8824, value: 1.0}
iex> Tint.convert!(Tint.RGB.new(255, 127, 30), :foo)
** (ArgumentError) Unknown colorspace: :foo
"""
@doc since: "1.0.0"
@spec convert!(color, colorspace) :: color
def convert!(color, colorspace) do
case convert(color, colorspace) do
{:ok, color} ->
color
:error ->
raise ArgumentError, "Unknown colorspace: #{inspect(colorspace)}"
end
end
@doc """
Converts the given color to the CMYK colorspace.
## Example
iex> Tint.to_cmyk(Tint.RGB.new(40, 66, 67))
#Tint.CMYK<40.3%,1.49%,0.0%,73.73%>
"""
@doc since: "0.3.0"
@spec to_cmyk(color) :: CMYK.t()
defdelegate to_cmyk(color), to: CMYK.Convertible, as: :convert
@doc """
Converts the given color to the DIN99 colorspace.
"""
@doc since: "1.0.0"
@spec to_din99(color) :: DIN99.t()
defdelegate to_din99(color), to: DIN99.Convertible, as: :convert
@doc """
Converts the given color to the HSV colorspace.
## Example
iex> Tint.to_hsv(Tint.RGB.new(255, 127, 30))
#Tint.HSV<25.9°,88.24%,100.0%>
"""
@spec to_hsv(color) :: HSV.t()
defdelegate to_hsv(color), to: HSV.Convertible, as: :convert
@doc """
Converts the given color to the CIELAB colorspace.
"""
@doc since: "1.0.0"
@spec to_lab(color) :: Lab.t()
defdelegate to_lab(color), to: Lab.Convertible, as: :convert
@doc """
Converts the given color to the RGB colorspace.
## Example
iex> Tint.to_rgb(Tint.HSV.new(25.8, 0.882, 1))
#Tint.RGB<255,127,30 (#FF7F1E)>
"""
@spec to_rgb(color) :: RGB.t()
defdelegate to_rgb(color), to: RGB.Convertible, as: :convert
@doc """
Converts the given color to the XYZ (CIE 1931) colorspace.
"""
@doc since: "1.0.0"
@spec to_xyz(color) :: XYZ.t()
defdelegate to_xyz(color), to: XYZ.Convertible, as: :convert
end