Color

Hex.pmHex DocsCILicense

A comprehensive Elixir library for representing, converting, and analysing color, with no runtime dependencies.

Color covers the CIE color spaces, the modern perceptual spaces (Oklab, JzAzBz, ICtCp, IPT, CAM16-UCS), the standard RGB working spaces (sRGB, Adobe RGB, Display P3, Rec. 709, Rec. 2020, ProPhoto, …), the non-linear UI spaces (HSL, HSV, HSLuv, HPLuv), CMYK, YCbCr (BT.601 / 709 / 2020) and the spectral pipeline (CIE 1931 and 1964 standard observers, illuminants, reflectance integration). Conversions are based on the canonical formulas published by Bruce Lindbloom.

Beyond conversions, the library provides chromatic adaptation (Bradford, von Kries, CAT02, …), four ΔE color-difference metrics (CIE76, CIE94, CIEDE2000, CMC l:c), WCAG and APCA contrast, gamut checking and CSS Color 4 perceptual gamut mapping, color mixing and gradient generation, harmonies, color temperature, blend modes, CSS Color 4 / 5 parsing and serialisation, an ICC matrix-profile reader, and a ~COLOR sigil.

Features

Supported Elixir and OTP Releases

Color is supported on Elixir 1.17+ and OTP 26+.

Quick Start

Add :color to your mix.exs dependencies:

def deps do
  [
    {:color, "~> 0.1.0"}
  ]
end

Then run mix deps.get.

Building colors

# From a hex string or CSS named color:
{:ok, red}    = Color.new("#ff0000")
{:ok, purple} = Color.new("rebeccapurple")
{:ok, also}   = Color.new(:misty_rose)

# From a list of unit-range floats (assumed sRGB):
{:ok, srgb}   = Color.new([1.0, 0.5, 0.0])

# From a list of 0..255 integers (assumed sRGB):
{:ok, srgb}   = Color.new([255, 128, 0])

# In any supported space:
{:ok, lab}    = Color.new([53.24, 80.09, 67.20], :lab)
{:ok, oklch}  = Color.new([0.7, 0.2, 30.0], :oklch)
{:ok, cmyk}   = Color.new([0.0, 0.5, 1.0, 0.0], :cmyk)

Converting

{:ok, lab}     = Color.convert("#ff0000", Color.Lab)
{:ok, oklch}   = Color.convert([1.0, 0.0, 0.0], Color.Oklch)
{:ok, cmyk}    = Color.convert(:rebecca_purple, Color.CMYK)
{:ok, p3}      = Color.convert(red, Color.RGB, :P3_D65)

# Wide-gamut Display P3 colors gamut-mapped into sRGB
# using the CSS Color 4 Oklch perceptual algorithm:
{:ok, mapped}  = Color.convert(p3, Color.SRGB, intent: :perceptual)

# Batch convert a list:
{:ok, labs}    = Color.convert_many(["red", "green", "blue"], Color.Lab)

Difference and contrast

Color.Distance.delta_e_2000(red, purple)        # CIEDE2000
Color.Contrast.wcag_ratio("white", "#777")      # 4.48
Color.Contrast.wcag_level("black", "white")     # :aaa
Color.Contrast.apca("black", "white")           # 106.04

Mixing, gradients, harmonies

{:ok, mid}    = Color.Mix.mix("red", "blue", 0.5, in: Color.Oklch)
{:ok, ramp}   = Color.Mix.gradient("black", "white", 8)
{:ok, [_a, _b]}    = Color.Harmony.complementary("red")
{:ok, [_a, _b, _c]} = Color.Harmony.triadic("red")

CSS Color 4 / 5

{:ok, c} = Color.CSS.parse("oklch(70% 0.15 180 / 50%)")
Color.CSS.to_css(c)
# => "oklch(70% 0.15 180 / 0.5)"

{:ok, c} = Color.CSS.parse("color-mix(in oklch, red 30%, blue)")
{:ok, c} = Color.CSS.parse("rgb(from oklch(0.7 0.15 180) calc(r * 0.9) g b)")

~COLOR Sigil

import Color.Sigil

~COLOR[#ff0000]            # Color.SRGB
~COLOR[rebeccapurple]      # Color.SRGB via CSS name
~COLOR[1.0, 0.5, 0.0]r     # unit sRGB
~COLOR[255, 128, 0]b       # 0..255 sRGB
~COLOR[53.24, 80.09, 67.2]l   # Color.Lab
~COLOR[0.63, 0.22, 0.13]o     # Color.Oklab

Spectral

d65 = Color.Spectral.illuminant(:D65)
{:ok, white_xyz} = Color.Spectral.to_xyz(d65)
# => Color.XYZ at D65 white point

# Reflectance under an illuminant:
sample = %Color.Spectral{wavelengths: ws, values: rs}
{:ok, xyz} = Color.Spectral.reflectance_to_xyz(sample, :D65)

# Detect a metamer pair:
{:ok, delta_e} = Color.Spectral.metamerism(sample_a, sample_b, :D65, :A)

ICC profiles

{:ok, profile} = Color.ICC.Profile.load("/path/to/Display P3.icc")
profile.description
# => "Display P3"

{x, y, z} = Color.ICC.Profile.to_xyz(profile, {1.0, 0.0, 0.0})
# => XYZ in PCS (D50, 2°)

{r, g, b} = Color.ICC.Profile.from_xyz(profile, {0.9642, 1.0, 0.8249})
# => encoded RGB in the profile's colour space

Documentation

See the module documentation on HexDocs.

License

Apache 2.0. See LICENSE.md for the full text.