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.
- checksums.yaml +4 -4
- data/abachrome.gemspec +1 -0
- data/devenv.nix +1 -1
- data/lib/abachrome/abc_decimal.rb +38 -35
- data/lib/abachrome/color.rb +37 -10
- data/lib/abachrome/color_mixins/blend.rb +7 -5
- data/lib/abachrome/color_mixins/lighten.rb +8 -6
- data/lib/abachrome/color_mixins/spectral_mix.rb +70 -0
- data/lib/abachrome/color_mixins/to_colorspace.rb +10 -8
- data/lib/abachrome/color_mixins/to_grayscale.rb +87 -0
- data/lib/abachrome/color_mixins/to_lrgb.rb +14 -12
- data/lib/abachrome/color_mixins/to_oklab.rb +16 -14
- data/lib/abachrome/color_mixins/to_oklch.rb +12 -10
- data/lib/abachrome/color_mixins/to_srgb.rb +17 -15
- data/lib/abachrome/color_models/cmyk.rb +159 -0
- data/lib/abachrome/color_models/hsv.rb +5 -3
- data/lib/abachrome/color_models/lms.rb +3 -1
- data/lib/abachrome/color_models/oklab.rb +3 -1
- data/lib/abachrome/color_models/oklch.rb +6 -4
- data/lib/abachrome/color_models/rgb.rb +4 -2
- data/lib/abachrome/color_models/xyz.rb +3 -1
- data/lib/abachrome/color_models/yiq.rb +37 -0
- data/lib/abachrome/color_space.rb +28 -14
- data/lib/abachrome/converter.rb +10 -8
- data/lib/abachrome/converters/base.rb +13 -11
- data/lib/abachrome/converters/cmyk_to_srgb.rb +42 -0
- data/lib/abachrome/converters/lms_to_lrgb.rb +5 -3
- data/lib/abachrome/converters/lms_to_srgb.rb +6 -4
- data/lib/abachrome/converters/lms_to_xyz.rb +5 -3
- data/lib/abachrome/converters/lrgb_to_lms.rb +3 -1
- data/lib/abachrome/converters/lrgb_to_oklab.rb +5 -3
- data/lib/abachrome/converters/lrgb_to_srgb.rb +6 -4
- data/lib/abachrome/converters/lrgb_to_xyz.rb +5 -3
- data/lib/abachrome/converters/oklab_to_lms.rb +9 -7
- data/lib/abachrome/converters/oklab_to_lrgb.rb +7 -7
- data/lib/abachrome/converters/oklab_to_oklch.rb +4 -2
- data/lib/abachrome/converters/oklab_to_srgb.rb +4 -2
- data/lib/abachrome/converters/oklch_to_lrgb.rb +5 -3
- data/lib/abachrome/converters/oklch_to_oklab.rb +5 -3
- data/lib/abachrome/converters/oklch_to_srgb.rb +6 -4
- data/lib/abachrome/converters/oklch_to_xyz.rb +6 -4
- data/lib/abachrome/converters/srgb_to_cmyk.rb +64 -0
- data/lib/abachrome/converters/srgb_to_lrgb.rb +5 -3
- data/lib/abachrome/converters/srgb_to_oklab.rb +4 -2
- data/lib/abachrome/converters/srgb_to_oklch.rb +5 -3
- data/lib/abachrome/converters/srgb_to_yiq.rb +49 -0
- data/lib/abachrome/converters/xyz_to_lms.rb +5 -3
- data/lib/abachrome/converters/xyz_to_oklab.rb +5 -3
- data/lib/abachrome/converters/yiq_to_srgb.rb +47 -0
- data/lib/abachrome/gamut/base.rb +3 -3
- data/lib/abachrome/gamut/p3.rb +3 -3
- data/lib/abachrome/gamut/rec2020.rb +2 -2
- data/lib/abachrome/gamut/srgb.rb +4 -2
- data/lib/abachrome/illuminants/base.rb +2 -2
- data/lib/abachrome/illuminants/d50.rb +2 -2
- data/lib/abachrome/illuminants/d55.rb +2 -2
- data/lib/abachrome/illuminants/d65.rb +2 -2
- data/lib/abachrome/illuminants/d75.rb +2 -2
- data/lib/abachrome/named/css.rb +149 -149
- data/lib/abachrome/named/tailwind.rb +265 -265
- data/lib/abachrome/outputs/css.rb +2 -2
- data/lib/abachrome/palette.rb +26 -25
- data/lib/abachrome/palette_mixins/interpolate.rb +3 -1
- data/lib/abachrome/palette_mixins/resample.rb +2 -2
- data/lib/abachrome/palette_mixins/stretch_luminance.rb +2 -2
- data/lib/abachrome/parsers/css.rb +86 -71
- data/lib/abachrome/parsers/hex.rb +2 -2
- data/lib/abachrome/parsers/tailwind.rb +8 -8
- data/lib/abachrome/spectral.rb +277 -0
- data/lib/abachrome/to_abcd.rb +4 -4
- data/lib/abachrome/version.rb +2 -2
- data/lib/abachrome.rb +66 -10
- 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"))) #
|
|
43
|
-
s_prime = AbcDecimal(l_ok - (a_ok * AD("0.089484182094965759684")) - (b_ok * AD("1.2914855378640917399"))) #
|
|
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"))
|
|
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"))
|
|
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"))
|
|
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
|
data/lib/abachrome/gamut/base.rb
CHANGED
|
@@ -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
|
|
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.
|
data/lib/abachrome/gamut/p3.rb
CHANGED
|
@@ -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
|
|
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.
|
data/lib/abachrome/gamut/srgb.rb
CHANGED
|
@@ -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
|
|
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.
|