abachrome

How do I convert between color spaces in Ruby?

Different color spaces serve different purposes, and we often need to move between them. sRGB is what browsers and CSS understand. OKLab and OKLCH are perceptually uniform, making them better suited for blending and lightness adjustments. Linear RGB is what rendering math expects before gamma correction applies. Abachrome lets us move between all of these without managing the conversion graph ourselves.

Every Abachrome color object exposes to_srgb, to_oklab, to_oklch, and other conversion methods. You might wonder what happens when you convert between spaces that are not directly connected — conversions chain automatically through intermediate spaces, so you get the right result regardless of which space you start from.

Direct Conversion

require 'abachrome'

color = Abachrome.from_hex('#e63946')

srgb  = color.to_srgb
lab   = color.to_oklab
lch   = color.to_oklch

puts lch.coordinates.map { |c| c.round(4) }.inspect
# => [0.5543, 0.2018, 26.7]   (lightness, chroma, hue°)

The three OKLCH coordinates — lightness, chroma, and hue — give you intuitive handles on the color’s perceptual properties. You can inspect them to understand a color, or modify them directly to adjust it.

Using the Generic Converter

Abachrome.convert accepts any color and a target space name as a symbol:

color    = Abachrome.from_hex('#06d6a0')
in_lch   = Abachrome.convert(color, :oklch)
in_lab   = Abachrome.convert(color, :oklab)
in_lrgb  = Abachrome.convert(color, :lrgb)

This is useful when the target space is determined at runtime rather than hard-coded.

Available Color Spaces

SymbolDescription
:srgbStandard RGB (web/display)
:lrgbLinear RGB (gamma-decoded)
:oklabPerceptually uniform Lab (OKLab)
:oklchCylindrical OKLab (lightness/chroma/hue)
:xyzCIE XYZ absolute color space
:lmsCone response (basis for OKLab)
:hsvHue-Saturation-Value

Registering a Custom Color Space

If your workflow uses a proprietary or nonstandard space, you can register it at startup:

Abachrome.register_color_space(:my_space) do |space|
  # define axes, ranges, etc.
end

Abachrome.register_converter(:srgb, :my_space, MySpaceConverter.new)

This extensibility is worth knowing about if you work in fields like print production or broadcast, where industry-specific color spaces are common.

Notes

  • Conversions go through intermediate spaces (e.g., sRGB → Linear RGB → XYZ → LMS → OKLab) but the path is resolved automatically.
  • Abachrome uses BigDecimal internally to minimise floating-point drift across multi-step conversions.