abachrome 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/abachrome.gemspec +1 -0
  3. data/devenv.nix +1 -1
  4. data/lib/abachrome/abc_decimal.rb +38 -35
  5. data/lib/abachrome/color.rb +37 -10
  6. data/lib/abachrome/color_mixins/blend.rb +7 -5
  7. data/lib/abachrome/color_mixins/lighten.rb +8 -6
  8. data/lib/abachrome/color_mixins/spectral_mix.rb +70 -0
  9. data/lib/abachrome/color_mixins/to_colorspace.rb +10 -8
  10. data/lib/abachrome/color_mixins/to_grayscale.rb +87 -0
  11. data/lib/abachrome/color_mixins/to_lrgb.rb +14 -12
  12. data/lib/abachrome/color_mixins/to_oklab.rb +16 -14
  13. data/lib/abachrome/color_mixins/to_oklch.rb +12 -10
  14. data/lib/abachrome/color_mixins/to_srgb.rb +17 -15
  15. data/lib/abachrome/color_models/cmyk.rb +159 -0
  16. data/lib/abachrome/color_models/hsv.rb +5 -3
  17. data/lib/abachrome/color_models/lms.rb +3 -1
  18. data/lib/abachrome/color_models/oklab.rb +3 -1
  19. data/lib/abachrome/color_models/oklch.rb +6 -4
  20. data/lib/abachrome/color_models/rgb.rb +4 -2
  21. data/lib/abachrome/color_models/xyz.rb +3 -1
  22. data/lib/abachrome/color_models/yiq.rb +37 -0
  23. data/lib/abachrome/color_space.rb +28 -14
  24. data/lib/abachrome/converter.rb +10 -8
  25. data/lib/abachrome/converters/base.rb +13 -11
  26. data/lib/abachrome/converters/cmyk_to_srgb.rb +42 -0
  27. data/lib/abachrome/converters/lms_to_lrgb.rb +5 -3
  28. data/lib/abachrome/converters/lms_to_srgb.rb +6 -4
  29. data/lib/abachrome/converters/lms_to_xyz.rb +5 -3
  30. data/lib/abachrome/converters/lrgb_to_lms.rb +3 -1
  31. data/lib/abachrome/converters/lrgb_to_oklab.rb +5 -3
  32. data/lib/abachrome/converters/lrgb_to_srgb.rb +6 -4
  33. data/lib/abachrome/converters/lrgb_to_xyz.rb +5 -3
  34. data/lib/abachrome/converters/oklab_to_lms.rb +9 -7
  35. data/lib/abachrome/converters/oklab_to_lrgb.rb +7 -7
  36. data/lib/abachrome/converters/oklab_to_oklch.rb +4 -2
  37. data/lib/abachrome/converters/oklab_to_srgb.rb +4 -2
  38. data/lib/abachrome/converters/oklch_to_lrgb.rb +5 -3
  39. data/lib/abachrome/converters/oklch_to_oklab.rb +5 -3
  40. data/lib/abachrome/converters/oklch_to_srgb.rb +6 -4
  41. data/lib/abachrome/converters/oklch_to_xyz.rb +6 -4
  42. data/lib/abachrome/converters/srgb_to_cmyk.rb +64 -0
  43. data/lib/abachrome/converters/srgb_to_lrgb.rb +5 -3
  44. data/lib/abachrome/converters/srgb_to_oklab.rb +4 -2
  45. data/lib/abachrome/converters/srgb_to_oklch.rb +5 -3
  46. data/lib/abachrome/converters/srgb_to_yiq.rb +49 -0
  47. data/lib/abachrome/converters/xyz_to_lms.rb +5 -3
  48. data/lib/abachrome/converters/xyz_to_oklab.rb +5 -3
  49. data/lib/abachrome/converters/yiq_to_srgb.rb +47 -0
  50. data/lib/abachrome/gamut/base.rb +3 -3
  51. data/lib/abachrome/gamut/p3.rb +3 -3
  52. data/lib/abachrome/gamut/rec2020.rb +2 -2
  53. data/lib/abachrome/gamut/srgb.rb +4 -2
  54. data/lib/abachrome/illuminants/base.rb +2 -2
  55. data/lib/abachrome/illuminants/d50.rb +2 -2
  56. data/lib/abachrome/illuminants/d55.rb +2 -2
  57. data/lib/abachrome/illuminants/d65.rb +2 -2
  58. data/lib/abachrome/illuminants/d75.rb +2 -2
  59. data/lib/abachrome/named/css.rb +149 -149
  60. data/lib/abachrome/named/tailwind.rb +265 -265
  61. data/lib/abachrome/outputs/css.rb +2 -2
  62. data/lib/abachrome/palette.rb +26 -25
  63. data/lib/abachrome/palette_mixins/interpolate.rb +3 -1
  64. data/lib/abachrome/palette_mixins/resample.rb +2 -2
  65. data/lib/abachrome/palette_mixins/stretch_luminance.rb +2 -2
  66. data/lib/abachrome/parsers/css.rb +86 -71
  67. data/lib/abachrome/parsers/hex.rb +2 -2
  68. data/lib/abachrome/parsers/tailwind.rb +8 -8
  69. data/lib/abachrome/spectral.rb +277 -0
  70. data/lib/abachrome/to_abcd.rb +4 -4
  71. data/lib/abachrome/version.rb +2 -2
  72. data/lib/abachrome.rb +66 -10
  73. metadata +29 -3
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklabToLrgb - OKLAB to Linear RGB color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLAB color space to the linear RGB (LRGB) color space
@@ -39,9 +41,8 @@ module Abachrome
39
41
  # Step 1: OKLAB to L'M'S' (cone responses, non-linear)
40
42
  # These are the M_lms_prime_from_oklab matrix operations.
41
43
  l_prime = AbcDecimal(l_ok + (AD("0.39633779217376785678") * a_ok) + (AD("0.21580375806075880339") * b_ok))
42
- m_prime = AbcDecimal(l_ok - (a_ok * AD("0.1055613423236563494")) - (b_ok * AD("0.063854174771705903402"))) # Note: original OklabToLms had + (b * AD("-0.063..."))
43
- s_prime = AbcDecimal(l_ok - (a_ok * AD("0.089484182094965759684")) - (b_ok * AD("1.2914855378640917399"))) # Note: original OklabToLms had + (b * AD("-1.291..."))
44
-
44
+ m_prime = AbcDecimal(l_ok - (a_ok * AD("0.1055613423236563494")) - (b_ok * AD("0.063854174771705903402"))) # NOTE: original OklabToLms had + (b * AD("-0.063..."))
45
+ s_prime = AbcDecimal(l_ok - (a_ok * AD("0.089484182094965759684")) - (b_ok * AD("1.2914855378640917399"))) # NOTE: original OklabToLms had + (b * AD("-1.291..."))
45
46
 
46
47
  # Step 2: L'M'S' to LMS (cubing)
47
48
  l_lms = l_prime**3
@@ -50,9 +51,9 @@ module Abachrome
50
51
 
51
52
  # Step 3: LMS to LRGB
52
53
  # Using matrix M_lrgb_from_lms (OKLAB specific)
53
- r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
54
+ r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
54
55
  g_lrgb = (l_lms * AD("-1.2684380040921763")) + (m_lms * AD("2.6097574006633715")) + (s_lms * AD("-0.3413193963102197"))
55
- b_lrgb = (l_lms * AD("-0.004196086541837188"))+ (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
56
+ b_lrgb = (l_lms * AD("-0.004196086541837188")) + (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
56
57
 
57
58
  # Clamp LRGB values to be non-negative (as done in LmsToLrgb.rb)
58
59
  # It's also common to clamp to [0, 1] range after conversion from a wider gamut space
@@ -61,11 +62,10 @@ module Abachrome
61
62
  # Here, we'll ensure non-negative as per LmsToLrgb.
62
63
  output_coords = [r_lrgb, g_lrgb, b_lrgb].map { |it| [it, AD(0)].max }
63
64
 
64
-
65
65
  Color.new(ColorSpace.find(:lrgb), output_coords, oklab_color.alpha)
66
66
  end
67
67
  end
68
68
  end
69
69
  end
70
70
 
71
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
71
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklabToOklch - OKLAB to OKLCH color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLAB color space to the OKLCH color space
@@ -28,7 +30,7 @@ module Abachrome
28
30
  # - L (lightness) remains the same
29
31
  # - C (chroma) is calculated as the Euclidean distance from the origin in the a-b plane
30
32
  # - h (hue) is calculated as the angle in the a-b plane
31
- #
33
+ #
32
34
  # @param oklab_color [Abachrome::Color] A color in the OKLAB color space
33
35
  # @raise [ArgumentError] If the provided color is not in OKLAB color space
34
36
  # @return [Abachrome::Color] The equivalent color in OKLCH color space with the same alpha value
@@ -51,4 +53,4 @@ module Abachrome
51
53
  end
52
54
  end
53
55
 
54
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
56
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklabToSrgb - OKLAB to sRGB color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLAB color space to the standard RGB (sRGB) color space
@@ -24,7 +26,7 @@ module Abachrome
24
26
  # This conversion is performed in two steps:
25
27
  # 1. First converts from Oklab to linear RGB
26
28
  # 2. Then converts from linear RGB to sRGB
27
- #
29
+ #
28
30
  # @param oklab_color [Color] A color in the Oklab color space
29
31
  # @raise [ArgumentError] If the provided color is not in the Oklab color space
30
32
  # @return [Color] The converted color in the sRGB color space
@@ -41,4 +43,4 @@ module Abachrome
41
43
  end
42
44
  end
43
45
 
44
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
46
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklchToLrgb - OKLCH to Linear RGB color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLCH color space to the linear RGB (LRGB) color space.
@@ -54,9 +56,9 @@ module Abachrome
54
56
 
55
57
  # Step 4: LMS to LRGB
56
58
  # Using matrix M_lrgb_from_lms (OKLAB specific)
57
- r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
59
+ r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
58
60
  g_lrgb = (l_lms * AD("-1.2684380040921763")) + (m_lms * AD("2.6097574006633715")) + (s_lms * AD("-0.3413193963102197"))
59
- b_lrgb = (l_lms * AD("-0.004196086541837188"))+ (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
61
+ b_lrgb = (l_lms * AD("-0.004196086541837188")) + (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
60
62
 
61
63
  # Clamp LRGB values to be non-negative.
62
64
  # LRGB values can be outside [0,1] but should be >= 0.
@@ -74,4 +76,4 @@ module Abachrome
74
76
  end
75
77
  end
76
78
 
77
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
79
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklchToOklab - OKLCH to OKLAB color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLCH color space to the OKLAB color space
@@ -24,7 +26,7 @@ module Abachrome
24
26
  module Converters
25
27
  class OklchToOklab < Abachrome::Converters::Base
26
28
  # Converts a color from OKLCH color space to OKLAB color space.
27
- #
29
+ #
28
30
  # @param oklch_color [Abachrome::Color] The color in OKLCH format to convert
29
31
  # @return [Abachrome::Color] The converted color in OKLAB format
30
32
  # @raise [StandardError] If the provided color is not in OKLCH color space
@@ -33,7 +35,7 @@ module Abachrome
33
35
 
34
36
  l, c, h = oklch_color.coordinates.map { |_| AbcDecimal(_) }
35
37
 
36
- h_rad = (h * Math::PI)/ AD(180)
38
+ h_rad = (h * Math::PI) / AD(180)
37
39
  a = c * AD(Math.cos(h_rad.value))
38
40
  b = c * AD(Math.sin(h_rad.value))
39
41
 
@@ -47,4 +49,4 @@ module Abachrome
47
49
  end
48
50
  end
49
51
 
50
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
52
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::OklchToSrgb - OKLCH to sRGB color space converter
2
4
  #
3
5
  # This converter transforms colors from the OKLCH color space to the standard RGB (sRGB) color space
@@ -27,18 +29,18 @@ module Abachrome
27
29
  # Converts a color from OKLCH color space to sRGB color space.
28
30
  # This is done by first converting from OKLCH to OKLAB,
29
31
  # then from OKLAB to sRGB.
30
- #
32
+ #
31
33
  # @param oklch_color [Abachrome::Color] Color in OKLCH color space
32
34
  # @return [Abachrome::Color] The converted color in sRGB color space
33
35
  def self.convert(oklch_color)
34
36
  # Convert OKLCh to OKLab first
35
37
  oklab_color = OklchToOklab.convert(oklch_color)
36
-
37
- # Then convert OKLab to sRGB
38
+
39
+ # Then convert OKLab to sRGB
38
40
  OklabToSrgb.convert(oklab_color)
39
41
  end
40
42
  end
41
43
  end
42
44
  end
43
45
 
44
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
46
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Abachrome
2
4
  module Converters
3
5
  class OklchToXyz < Abachrome::Converters::Base
@@ -40,9 +42,9 @@ module Abachrome
40
42
  # Step 4: LMS to LRGB
41
43
  # (r_lrgb, g_lrgb, b_lrgb)
42
44
  # Using matrix M_lrgb_from_lms (OKLAB specific)
43
- r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
45
+ r_lrgb = (l_lms * AD("4.07674166134799")) + (m_lms * AD("-3.307711590408193")) + (s_lms * AD("0.230969928729428"))
44
46
  g_lrgb = (l_lms * AD("-1.2684380040921763")) + (m_lms * AD("2.6097574006633715")) + (s_lms * AD("-0.3413193963102197"))
45
- b_lrgb = (l_lms * AD("-0.004196086541837188"))+ (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
47
+ b_lrgb = (l_lms * AD("-0.004196086541837188")) + (m_lms * AD("-0.7034186144594493")) + (s_lms * AD("1.7076147009309444"))
46
48
 
47
49
  # Clamp LRGB values to be non-negative (as done in LmsToLrgb.rb)
48
50
  # Using the pattern [AbcDecimal, Integer].max which relies on AbcDecimal's <=> coercion.
@@ -51,7 +53,7 @@ module Abachrome
51
53
  r_lrgb_clamped = [r_lrgb, zero_ad].max
52
54
  g_lrgb_clamped = [g_lrgb, zero_ad].max
53
55
  b_lrgb_clamped = [b_lrgb, zero_ad].max
54
-
56
+
55
57
  # Step 5: LRGB to XYZ
56
58
  # (x_xyz, y_xyz, z_xyz)
57
59
  # Using matrix M_xyz_from_lrgb (sRGB D65)
@@ -65,4 +67,4 @@ module Abachrome
65
67
  end
66
68
  end
67
69
 
68
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
70
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Abachrome::Converters::SrgbToCmyk - sRGB to CMYK color space converter
4
+ #
5
+ # This converter transforms colors from the standard RGB (sRGB) color space to the CMYK
6
+ # (Cyan, Magenta, Yellow, Key/Black) color space using Gray Component Replacement (GCR)
7
+ # for optimal ink usage in print production.
8
+ #
9
+ # Key features:
10
+ # - Implements GCR/UCR for efficient ink usage and better print quality
11
+ # - Converts from additive (light) to subtractive (ink) color model
12
+ # - Configurable GCR amount for different printing requirements
13
+ # - Uses BigDecimal for precise ink percentage calculations
14
+ # - Maintains alpha channel transparency values during conversion
15
+ # - Produces professional-quality CMYK separations
16
+ #
17
+ # The conversion uses Gray Component Replacement by default, which extracts the neutral
18
+ # gray component from CMY inks and assigns it to the cheaper and more stable Black (K) ink.
19
+ # This reduces Total Area Coverage (TAC) and improves print quality.
20
+
21
+ module Abachrome
22
+ module Converters
23
+ class SrgbToCmyk
24
+ # Converts a color from sRGB color space to CMYK color space.
25
+ # Uses full GCR (Gray Component Replacement) by default for optimal ink usage.
26
+ #
27
+ # @param srgb_color [Abachrome::Color] A color object in the sRGB color space
28
+ # @param gcr_amount [Numeric] The amount of GCR to apply (0.0 to 1.0), default 1.0 for full GCR
29
+ # @return [Abachrome::Color] A new color object in the CMYK color space
30
+ # with the same alpha value as the input color
31
+ def self.convert(srgb_color, gcr_amount: 1.0)
32
+ r, g, b = srgb_color.coordinates.map { |c| AbcDecimal(c) }
33
+
34
+ # Use GCR conversion from the CMYK color model
35
+ c, m, y, k = ColorModels::CMYK.from_rgb_gcr(r, g, b, gcr_amount)
36
+
37
+ Color.new(
38
+ ColorSpace.find(:cmyk),
39
+ [c, m, y, k],
40
+ srgb_color.alpha
41
+ )
42
+ end
43
+
44
+ # Converts a color from sRGB to CMYK using the naive method (no UCR/GCR).
45
+ # This produces higher ink coverage but simpler conversion.
46
+ # Generally not recommended for production printing.
47
+ #
48
+ # @param srgb_color [Abachrome::Color] A color object in the sRGB color space
49
+ # @return [Abachrome::Color] A new color object in the CMYK color space
50
+ def self.convert_naive(srgb_color)
51
+ r, g, b = srgb_color.coordinates.map { |c| AbcDecimal(c) }
52
+
53
+ # Use naive conversion from the CMYK color model
54
+ c, m, y, k = ColorModels::CMYK.from_rgb_naive(r, g, b)
55
+
56
+ Color.new(
57
+ ColorSpace.find(:cmyk),
58
+ [c, m, y, k],
59
+ srgb_color.alpha
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::SrgbToLrgb - sRGB to Linear RGB color space converter
2
4
  #
3
5
  # This converter transforms colors from the standard RGB (sRGB) color space to the linear RGB (LRGB) color space by removing gamma correction. The conversion process applies the inverse sRGB transfer function which uses different formulas for small and large values to convert from the gamma-corrected sRGB representation to linear light intensity values.
@@ -17,7 +19,7 @@ module Abachrome
17
19
  class SrgbToLrgb
18
20
  # Converts a color from sRGB color space to linear RGB color space.
19
21
  # This method performs gamma correction by linearizing each sRGB coordinate.
20
- #
22
+ #
21
23
  # @param srgb_color [Abachrome::Color] A color object in the sRGB color space
22
24
  # @return [Abachrome::Color] A new color object in the linear RGB (LRGB) color space
23
25
  # with the same alpha value as the input color
@@ -34,7 +36,7 @@ module Abachrome
34
36
  # Converts a sRGB component to its linear RGB equivalent.
35
37
  # This conversion applies the appropriate gamma correction to transform an sRGB value
36
38
  # into a linear RGB value.
37
- #
39
+ #
38
40
  # @param v [AbcDecimal, Numeric] The sRGB component value to convert (typically in range 0-1)
39
41
  # @return [AbcDecimal] The corresponding linear RGB component value
40
42
  def self.to_linear(v)
@@ -50,4 +52,4 @@ module Abachrome
50
52
  end
51
53
  end
52
54
 
53
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
55
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::SrgbToOklab - sRGB to OKLAB color space converter
2
4
  #
3
5
  # This converter transforms colors from the standard RGB (sRGB) color space to the OKLAB color space
@@ -26,7 +28,7 @@ module Abachrome
26
28
  # The conversion happens in two steps:
27
29
  # 1. sRGB is first converted to linear RGB
28
30
  # 2. Linear RGB is then converted to Oklab
29
- #
31
+ #
30
32
  # @param srgb_color [Abachrome::Color] The color in sRGB color space to convert
31
33
  # @return [Abachrome::Color] The converted color in Oklab color space
32
34
  def self.convert(srgb_color)
@@ -40,4 +42,4 @@ module Abachrome
40
42
  end
41
43
  end
42
44
 
43
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
45
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Converters::SrgbToOklch - sRGB to OKLCH color space converter
2
4
  #
3
5
  # This converter transforms colors from the standard RGB (sRGB) color space to the OKLCH color space
@@ -25,7 +27,7 @@ module Abachrome
25
27
  module Converters
26
28
  class SrgbToOklch < Abachrome::Converters::Base
27
29
  # Converts an sRGB color to OKLCH color space
28
- #
30
+ #
29
31
  # @param srgb_color [Abachrome::Color] The color in sRGB color space to convert
30
32
  # @return [Abachrome::Color] The converted color in OKLCH color space
31
33
  # @note This is a two-step conversion process: first from sRGB to OKLab, then from OKLab to OKLCH
@@ -34,7 +36,7 @@ module Abachrome
34
36
  def self.convert(srgb_color)
35
37
  # First convert sRGB to OKLab
36
38
  oklab_color = SrgbToOklab.convert(srgb_color)
37
-
39
+
38
40
  # Then convert OKLab to OKLCh
39
41
  OklabToOklch.convert(oklab_color)
40
42
  end
@@ -42,4 +44,4 @@ module Abachrome
42
44
  end
43
45
  end
44
46
 
45
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
47
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Abachrome::Converters::SrgbToYiq - sRGB to YIQ color space converter
4
+ #
5
+ # This converter transforms colors from the standard RGB (sRGB) color space to the YIQ
6
+ # color space using the NTSC standard transformation matrix. The conversion applies the
7
+ # Rec. 601 luma coefficients to separate luminance (Y) from chrominance (I and Q).
8
+ #
9
+ # Key features:
10
+ # - Implements the standard NTSC RGB to YIQ conversion using matrix transformation
11
+ # - Separates brightness (Y) from color information (I, Q)
12
+ # - Uses Rec. 601 luma coefficients: Y = 0.299R + 0.587G + 0.114B
13
+ # - I axis represents orange-to-blue chrominance
14
+ # - Q axis represents purple-to-green chrominance
15
+ # - Maintains alpha channel transparency values during conversion
16
+ # - Uses AbcDecimal arithmetic for precise color science calculations
17
+ #
18
+ # The YIQ color space is historically significant for broadcast television and remains
19
+ # relevant for image processing tasks that require luminance/chrominance separation.
20
+
21
+ module Abachrome
22
+ module Converters
23
+ class SrgbToYiq
24
+ # Converts a color from sRGB color space to YIQ color space.
25
+ # This method applies the NTSC standard transformation matrix.
26
+ #
27
+ # @param srgb_color [Abachrome::Color] A color object in the sRGB color space
28
+ # @return [Abachrome::Color] A new color object in the YIQ color space
29
+ # with the same alpha value as the input color
30
+ def self.convert(srgb_color)
31
+ r, g, b = srgb_color.coordinates.map { |c| AbcDecimal(c) }
32
+
33
+ # NTSC RGB to YIQ transformation matrix
34
+ # Y = 0.299R + 0.587G + 0.114B (Rec. 601 luma)
35
+ # I = 0.596R - 0.275G - 0.321B (In-phase: orange-blue)
36
+ # Q = 0.212R - 0.523G + 0.311B (Quadrature: purple-green)
37
+ y = (AD("0.299") * r) + (AD("0.587") * g) + (AD("0.114") * b)
38
+ i = (AD("0.5959") * r) - (AD("0.2746") * g) - (AD("0.3213") * b)
39
+ q = (AD("0.2115") * r) - (AD("0.5227") * g) + (AD("0.3112") * b)
40
+
41
+ Color.new(
42
+ ColorSpace.find(:yiq),
43
+ [y, i, q],
44
+ srgb_color.alpha
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Abachrome
2
4
  module Converters
3
5
  class XyzToLms < Abachrome::Converters::Base
4
6
  # Converts a color from XYZ color space to LMS color space.
5
- #
7
+ #
6
8
  # This method implements the XYZ to LMS transformation using the standard
7
9
  # transformation matrix. The LMS color space represents the response of
8
10
  # the three types of cone cells in the human eye (Long, Medium, Short),
9
11
  # while XYZ is the CIE 1931 color space that forms the basis for most
10
12
  # other color space definitions.
11
- #
13
+ #
12
14
  # @param xyz_color [Abachrome::Color] The color in XYZ color space
13
15
  # @raise [ArgumentError] If the input color is not in XYZ color space
14
16
  # @return [Abachrome::Color] The resulting color in LMS color space with
@@ -29,4 +31,4 @@ module Abachrome
29
31
  end
30
32
  end
31
33
 
32
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
34
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Abachrome
2
4
  module Converters
3
5
  class XyzToOklab < Abachrome::Converters::Base
4
6
  # Converts a color from XYZ color space to OKLAB color space.
5
- #
7
+ #
6
8
  # This method implements the XYZ to OKLAB transformation by first
7
9
  # converting XYZ coordinates to the intermediate LMS (Long, Medium, Short)
8
10
  # color space, then applying the LMS to OKLAB transformation matrix.
9
- #
11
+ #
10
12
  # @param xyz_color [Abachrome::Color] The color in XYZ color space
11
13
  # @raise [ArgumentError] If the input color is not in XYZ color space
12
14
  # @return [Abachrome::Color] The resulting color in OKLAB color space with
@@ -37,4 +39,4 @@ module Abachrome
37
39
  end
38
40
  end
39
41
 
40
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
42
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Abachrome::Converters::YiqToSrgb - YIQ to sRGB color space converter
4
+ #
5
+ # This converter transforms colors from the YIQ color space back to the standard RGB
6
+ # (sRGB) color space using the inverse NTSC transformation matrix. The conversion
7
+ # recombines luminance (Y) and chrominance (I, Q) into RGB components.
8
+ #
9
+ # Key features:
10
+ # - Implements the inverse NTSC YIQ to RGB conversion using matrix transformation
11
+ # - Recombines brightness (Y) and color information (I, Q) into RGB
12
+ # - Maintains alpha channel transparency values during conversion
13
+ # - Uses AbcDecimal arithmetic for precise color science calculations
14
+ # - May produce RGB values outside [0,1] range for out-of-gamut YIQ values
15
+ #
16
+ # The inverse transformation allows colors manipulated in YIQ space (e.g., brightness
17
+ # adjustments on the Y channel) to be converted back to RGB for display.
18
+
19
+ module Abachrome
20
+ module Converters
21
+ class YiqToSrgb
22
+ # Converts a color from YIQ color space to sRGB color space.
23
+ # This method applies the inverse NTSC transformation matrix.
24
+ #
25
+ # @param yiq_color [Abachrome::Color] A color object in the YIQ color space
26
+ # @return [Abachrome::Color] A new color object in the sRGB color space
27
+ # with the same alpha value as the input color
28
+ def self.convert(yiq_color)
29
+ y, i, q = yiq_color.coordinates.map { |c| AbcDecimal(c) }
30
+
31
+ # Inverse NTSC YIQ to RGB transformation matrix
32
+ # R = Y + 0.956I + 0.619Q
33
+ # G = Y - 0.272I - 0.647Q
34
+ # B = Y - 1.106I + 1.703Q
35
+ r = y + (AD("0.9563") * i) + (AD("0.6210") * q)
36
+ g = y - (AD("0.2721") * i) - (AD("0.6474") * q)
37
+ b = y - (AD("1.1070") * i) + (AD("1.7046") * q)
38
+
39
+ Color.new(
40
+ ColorSpace.find(:srgb),
41
+ [r, g, b],
42
+ yiq_color.alpha
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Gamut
@@ -28,7 +28,7 @@ module Abachrome
28
28
  # TODO: - make this work properly
29
29
  def contains?(coordinates)
30
30
  x, y, z = coordinates
31
- x >= 0 && x <= 1 &&
31
+ x.between?(0, 1) &&
32
32
  y >= 0 && y <= 1 &&
33
33
  z >= 0 && z <= 1
34
34
  end
@@ -71,4 +71,4 @@ module Abachrome
71
71
  end
72
72
  end
73
73
 
74
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
74
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Gamut
@@ -14,7 +14,7 @@ module Abachrome
14
14
 
15
15
  def contains?(coordinates)
16
16
  r, g, b = coordinates
17
- r >= 0 && r <= 1 &&
17
+ r.between?(0, 1) &&
18
18
  g >= 0 && g <= 1 &&
19
19
  b >= 0 && b <= 1
20
20
  end
@@ -24,4 +24,4 @@ module Abachrome
24
24
  end
25
25
  end
26
26
 
27
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
27
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  lib
4
4
  abachrome
@@ -22,4 +22,4 @@ module Abachrome
22
22
  end
23
23
  end
24
24
 
25
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
25
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Abachrome::Gamut::SRGB - sRGB color gamut definition and validation
2
4
  #
3
5
  # This module defines the sRGB color gamut within the Abachrome color manipulation library.
@@ -34,7 +36,7 @@ module Abachrome
34
36
 
35
37
  def contains?(coordinates)
36
38
  r, g, b = coordinates
37
- r >= 0 && r <= 1 &&
39
+ r.between?(0, 1) &&
38
40
  g >= 0 && g <= 1 &&
39
41
  b >= 0 && b <= 1
40
42
  end
@@ -44,4 +46,4 @@ module Abachrome
44
46
  end
45
47
  end
46
48
 
47
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
49
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Illuminants
@@ -32,4 +32,4 @@ module Abachrome
32
32
  end
33
33
  end
34
34
 
35
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
35
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Illuminants
@@ -30,4 +30,4 @@ module Abachrome
30
30
  end
31
31
  end
32
32
 
33
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
33
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Illuminants
@@ -26,4 +26,4 @@ module Abachrome
26
26
  end
27
27
  end
28
28
 
29
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
29
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Illuminants
@@ -34,4 +34,4 @@ module Abachrome
34
34
  end
35
35
  end
36
36
 
37
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
37
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
@@ -1,4 +1,4 @@
1
- #
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Abachrome
4
4
  module Illuminants
@@ -26,4 +26,4 @@ module Abachrome
26
26
  end
27
27
  end
28
28
 
29
- # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.
29
+ # Copyright (c) 2025 Durable Programming, LLC. All rights reserved.