Class: Abachrome::Converters::OklabToLrgb

Inherits:
Base
  • Object
show all
Defined in:
lib/abachrome/converters/oklab_to_lrgb.rb

Instance Attribute Summary

Attributes inherited from Base

#from_space, #to_space

Class Method Summary collapse

Methods inherited from Base

#can_convert?, #convert, find_converter, #initialize, raise_unless, register

Constructor Details

This class inherits a constructor from Abachrome::Converters::Base

Class Method Details

.convert(oklab_color) ⇒ Abachrome::Color

Converts a color from OKLAB color space to linear RGB (LRGB) color space.

This method performs a two-step conversion:

  1. OKLAB to LMS (cone response space)

  2. LMS to LRGB (linear RGB)

the same alpha as the input color

Parameters:

Returns:

Raises:

  • (ArgumentError)

    If the input color is not in OKLAB color space



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/abachrome/converters/oklab_to_lrgb.rb', line 34

def self.convert(oklab_color)
  raise_unless oklab_color, :oklab

  l_ok, a_ok, b_ok = oklab_color.coordinates.map { |_| AbcDecimal(_) }

  # Step 1: OKLAB to L'M'S' (cone responses, non-linear)
  # These are the M_lms_prime_from_oklab matrix operations.
  l_prime = AbcDecimal(l_ok + (AD("0.39633779217376785678") * a_ok) + (AD("0.21580375806075880339") * b_ok))
  m_prime = AbcDecimal(l_ok - (a_ok * AD("0.1055613423236563494")) - (b_ok * AD("0.063854174771705903402"))) # Note: original OklabToLms had + (b * AD("-0.063..."))
  s_prime = AbcDecimal(l_ok - (a_ok * AD("0.089484182094965759684")) - (b_ok * AD("1.2914855378640917399"))) # Note: original OklabToLms had + (b * AD("-1.291..."))


  # Step 2: L'M'S' to LMS (cubing)
  l_lms = l_prime**3
  m_lms = m_prime**3
  s_lms = s_prime**3

  # Step 3: LMS to LRGB
  # Using matrix M_lrgb_from_lms (OKLAB specific)
  r_lrgb = (l_lms * AD("4.07674166134799"))   + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
  g_lrgb = (l_lms * AD("-1.2684380040921763")) + (m_lms * AD("2.6097574006633715")) + (s_lms * AD("-0.3413193963102197"))
  b_lrgb = (l_lms * AD("-0.004196086541837188"))+ (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))

  # Clamp LRGB values to be non-negative (as done in LmsToLrgb.rb)
  # It's also common to clamp to [0, 1] range after conversion from a wider gamut space
  # For LRGB, often just ensuring non-negative is done, and further clamping happens
  # when converting to sRGB or other display spaces.
  # Here, we'll ensure non-negative as per LmsToLrgb.
  output_coords = [r_lrgb, g_lrgb, b_lrgb].map { |it| [it, AD(0)].max }


  Color.new(ColorSpace.find(:lrgb), output_coords, oklab_color.alpha)
end