color_converters 0.1.3 → 0.1.4
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/README.md +190 -176
- data/lib/color_converters/base_converter.rb +184 -179
- data/lib/color_converters/color.rb +18 -16
- data/lib/color_converters/converters/cielab_converter.rb +95 -92
- data/lib/color_converters/converters/cielch_converter.rb +61 -58
- data/lib/color_converters/converters/cmyk_converter.rb +59 -56
- data/lib/color_converters/converters/hex_converter.rb +45 -32
- data/lib/color_converters/converters/hsl_converter.rb +68 -65
- data/lib/color_converters/converters/hsl_string_converter.rb +46 -27
- data/lib/color_converters/converters/hsv_converter.rb +60 -58
- data/lib/color_converters/converters/name_converter.rb +67 -185
- data/lib/color_converters/converters/null_converter.rb +19 -17
- data/lib/color_converters/converters/oklab_converter.rb +102 -98
- data/lib/color_converters/converters/oklch_converter.rb +61 -58
- data/lib/color_converters/converters/rgb_converter.rb +109 -106
- data/lib/color_converters/converters/rgb_string_converter.rb +49 -32
- data/lib/color_converters/converters/xyz_converter.rb +110 -107
- data/lib/color_converters/version.rb +1 -1
- data/lib/color_converters.rb +31 -30
- metadata +18 -4
@@ -1,185 +1,67 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
67
|
-
|
68
|
-
darksalmon: [233, 150, 122],
|
69
|
-
darkseagreen: [143, 188, 143],
|
70
|
-
darkslateblue: [72, 61, 139],
|
71
|
-
darkslategray: [47, 79, 79],
|
72
|
-
darkslategrey: [47, 79, 79],
|
73
|
-
darkturquoise: [0, 206, 209],
|
74
|
-
darkviolet: [148, 0, 211],
|
75
|
-
deeppink: [255, 20, 147],
|
76
|
-
deepskyblue: [0, 191, 255],
|
77
|
-
dimgray: [105, 105, 105],
|
78
|
-
dimgrey: [105, 105, 105],
|
79
|
-
dodgerblue: [30, 144, 255],
|
80
|
-
firebrick: [178, 34, 34],
|
81
|
-
floralwhite: [255, 250, 240],
|
82
|
-
forestgreen: [34, 139, 34],
|
83
|
-
fuchsia: [255, 0, 255],
|
84
|
-
gainsboro: [220, 220, 220],
|
85
|
-
ghostwhite: [248, 248, 255],
|
86
|
-
gold: [255, 215, 0],
|
87
|
-
goldenrod: [218, 165, 32],
|
88
|
-
gray: [128, 128, 128],
|
89
|
-
green: [0, 128, 0],
|
90
|
-
greenyellow: [173, 255, 47],
|
91
|
-
grey: [128, 128, 128],
|
92
|
-
honeydew: [240, 255, 240],
|
93
|
-
hotpink: [255, 105, 180],
|
94
|
-
indianred: [205, 92, 92],
|
95
|
-
indigo: [75, 0, 130],
|
96
|
-
ivory: [255, 255, 240],
|
97
|
-
khaki: [240, 230, 140],
|
98
|
-
lavender: [230, 230, 250],
|
99
|
-
lavenderblush: [255, 240, 245],
|
100
|
-
lawngreen: [124, 252, 0],
|
101
|
-
lemonchiffon: [255, 250, 205],
|
102
|
-
lightblue: [173, 216, 230],
|
103
|
-
lightcoral: [240, 128, 128],
|
104
|
-
lightcyan: [224, 255, 255],
|
105
|
-
lightgoldenrodyellow: [250, 250, 210],
|
106
|
-
lightgray: [211, 211, 211],
|
107
|
-
lightgreen: [144, 238, 144],
|
108
|
-
lightgrey: [211, 211, 211],
|
109
|
-
lightpink: [255, 182, 193],
|
110
|
-
lightsalmon: [255, 160, 122],
|
111
|
-
lightseagreen: [32, 178, 170],
|
112
|
-
lightskyblue: [135, 206, 250],
|
113
|
-
lightslategray: [119, 136, 153],
|
114
|
-
lightslategrey: [119, 136, 153],
|
115
|
-
lightsteelblue: [176, 196, 222],
|
116
|
-
lightyellow: [255, 255, 224],
|
117
|
-
lime: [0, 255, 0],
|
118
|
-
limegreen: [50, 205, 50],
|
119
|
-
linen: [250, 240, 230],
|
120
|
-
magenta: [255, 0, 255],
|
121
|
-
maroon: [128, 0, 0],
|
122
|
-
mediumaquamarine: [102, 205, 170],
|
123
|
-
mediumblue: [0, 0, 205],
|
124
|
-
mediumorchid: [186, 85, 211],
|
125
|
-
mediumpurple: [147, 112, 219],
|
126
|
-
mediumseagreen: [60, 179, 113],
|
127
|
-
mediumslateblue: [123, 104, 238],
|
128
|
-
mediumspringgreen: [0, 250, 154],
|
129
|
-
mediumturquoise: [72, 209, 204],
|
130
|
-
mediumvioletred: [199, 21, 133],
|
131
|
-
midnightblue: [25, 25, 112],
|
132
|
-
mintcream: [245, 255, 250],
|
133
|
-
mistyrose: [255, 228, 225],
|
134
|
-
moccasin: [255, 228, 181],
|
135
|
-
navajowhite: [255, 222, 173],
|
136
|
-
navy: [0, 0, 128],
|
137
|
-
oldlace: [253, 245, 230],
|
138
|
-
olive: [128, 128, 0],
|
139
|
-
olivedrab: [107, 142, 35],
|
140
|
-
orange: [255, 165, 0],
|
141
|
-
orangered: [255, 69, 0],
|
142
|
-
orchid: [218, 112, 214],
|
143
|
-
palegoldenrod: [238, 232, 170],
|
144
|
-
palegreen: [152, 251, 152],
|
145
|
-
paleturquoise: [175, 238, 238],
|
146
|
-
palevioletred: [219, 112, 147],
|
147
|
-
papayawhip: [255, 239, 213],
|
148
|
-
peachpuff: [255, 218, 185],
|
149
|
-
peru: [205, 133, 63],
|
150
|
-
pink: [255, 192, 203],
|
151
|
-
plum: [221, 160, 221],
|
152
|
-
powderblue: [176, 224, 230],
|
153
|
-
purple: [128, 0, 128],
|
154
|
-
red: [255, 0, 0],
|
155
|
-
rosybrown: [188, 143, 143],
|
156
|
-
royalblue: [65, 105, 225],
|
157
|
-
saddlebrown: [139, 69, 19],
|
158
|
-
salmon: [250, 128, 114],
|
159
|
-
sandybrown: [244, 164, 96],
|
160
|
-
seagreen: [46, 139, 87],
|
161
|
-
seashell: [255, 245, 238],
|
162
|
-
sienna: [160, 82, 45],
|
163
|
-
silver: [192, 192, 192],
|
164
|
-
skyblue: [135, 206, 235],
|
165
|
-
slateblue: [106, 90, 205],
|
166
|
-
slategray: [112, 128, 144],
|
167
|
-
slategrey: [112, 128, 144],
|
168
|
-
snow: [255, 250, 250],
|
169
|
-
springgreen: [0, 255, 127],
|
170
|
-
steelblue: [70, 130, 180],
|
171
|
-
tan: [210, 180, 140],
|
172
|
-
teal: [0, 128, 128],
|
173
|
-
thistle: [216, 191, 216],
|
174
|
-
tomato: [255, 99, 71],
|
175
|
-
turquoise: [64, 224, 208],
|
176
|
-
violet: [238, 130, 238],
|
177
|
-
wheat: [245, 222, 179],
|
178
|
-
white: [255, 255, 255],
|
179
|
-
whitesmoke: [245, 245, 245],
|
180
|
-
yellow: [255, 255, 0],
|
181
|
-
yellowgreen: [154, 205, 50]
|
182
|
-
}
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_swatch_collection'
|
4
|
+
|
5
|
+
module ColorConverters
|
6
|
+
class NameConverter < BaseConverter
|
7
|
+
def self.matches?(colour_input)
|
8
|
+
return false unless colour_input.is_a?(String)
|
9
|
+
|
10
|
+
!colour_input.include?('#') && !colour_input.include?('rgb') && !colour_input.include?('hsl')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.rgb_to_name(rgb_array, fuzzy = false)
|
14
|
+
if fuzzy
|
15
|
+
source_colour = ColorConverters::Color.new({ r: rgb_array[0], g: rgb_array[1], b: rgb_array[2] })
|
16
|
+
|
17
|
+
collection_colours = []
|
18
|
+
|
19
|
+
::ColorSwatchCollection.list_collections.each do |collection_name|
|
20
|
+
collection_colours += self.add_colour_distances_to_collection(Object.const_get("::ColorSwatchCollection::#{collection_name.capitalize}").colours, source_colour)
|
21
|
+
end
|
22
|
+
|
23
|
+
collection_colours.min_by { |swatch| swatch[:distance] }.dig(:name)
|
24
|
+
else
|
25
|
+
::ColorSwatchCollection.get_from_hex(HexConverter.rgb_to_hex(rgb_array)).dig(:name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_input(colour_input)
|
32
|
+
self.class.match_name_from_palettes(colour_input).present? ? [] : ['name could not be found across colour collections']
|
33
|
+
end
|
34
|
+
|
35
|
+
def input_to_rgba(colour_input)
|
36
|
+
found_colour = self.class.match_name_from_palettes(colour_input)
|
37
|
+
|
38
|
+
raise InvalidColorError unless found_colour.present?
|
39
|
+
|
40
|
+
HexConverter.hex_to_rgba(found_colour)
|
41
|
+
end
|
42
|
+
|
43
|
+
# this is a checking for a direct naming match against the ColorSwatchCollection
|
44
|
+
def self.match_name_from_palettes(colour_name)
|
45
|
+
::ColorSwatchCollection.get_from_name(colour_name).dig(:hex)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.add_colour_distances_to_collection(collection_colours, source_colour)
|
49
|
+
collection_colours.map do |swatch|
|
50
|
+
swatch[:distance] = self.distance_between_colours(ColorConverters::Color.new(swatch.dig(:hex)), source_colour)
|
51
|
+
end
|
52
|
+
|
53
|
+
collection_colours
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.distance_between_colours(comparison_colour, source_colour)
|
57
|
+
# https://en.wikipedia.org/wiki/Euclidean_distance#Higher_dimensions
|
58
|
+
# https://www.baeldung.com/cs/compute-similarity-of-colours
|
59
|
+
# TODO: allow the type of matching to be set via config. Use HSL for now as it's far faster than CIELab
|
60
|
+
conversion_1 = comparison_colour.hsl
|
61
|
+
conversion_2 = source_colour.hsl
|
62
|
+
|
63
|
+
keys = conversion_1.keys
|
64
|
+
Math.sqrt((conversion_1[keys[0]] - conversion_2[keys[0]])**2 + (conversion_1[keys[1]] - conversion_2[keys[1]])**2 + (conversion_1[keys[2]] - conversion_2[keys[2]])**2)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,17 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ColorConverters
|
4
|
+
class NullConverter < BaseConverter
|
5
|
+
def self.matches?(_colour_input)
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def validate_input(_colour_input)
|
12
|
+
['did not recognise colour input']
|
13
|
+
end
|
14
|
+
|
15
|
+
def input_to_rgba(_colour_input)
|
16
|
+
raise InvalidColorError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,98 +1,102 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
m_lms
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
y
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
x
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
m_lms
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ColorConverters
|
4
|
+
class OklabConverter < BaseConverter
|
5
|
+
def self.matches?(colour_input)
|
6
|
+
return false unless colour_input.is_a?(Hash)
|
7
|
+
|
8
|
+
colour_input.keys - [:l, :a, :b, :space] == [] && colour_input[:space].to_s == 'ok'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.bounds
|
12
|
+
{ l: [0.0, 100.0], a: [-0.5, 0.5], b: [-0.5, 0.5] }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_input(colour_input)
|
18
|
+
OklabConverter.bounds.collect do |key, range|
|
19
|
+
"#{key} must be between #{range[0]} and #{range[1]}" unless colour_input[key].to_f.between?(*range)
|
20
|
+
end.compact
|
21
|
+
end
|
22
|
+
|
23
|
+
def input_to_rgba(colour_input)
|
24
|
+
x, y, z = OklabConverter.oklab_to_xyz(colour_input)
|
25
|
+
r, g, b = XyzConverter.xyz_to_rgb({ x: x, y: y, z: z })
|
26
|
+
|
27
|
+
[r, g, b, 1.0]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.oklab_to_xyz(colour_input)
|
31
|
+
l = colour_input[:l].to_d
|
32
|
+
a = colour_input[:a].to_d
|
33
|
+
b = colour_input[:b].to_d
|
34
|
+
|
35
|
+
# Now, scale l to a decimal
|
36
|
+
l /= 100.0.to_d
|
37
|
+
|
38
|
+
# Convert Oklab (L*a*b*) to LMS'
|
39
|
+
lab_to_lms_matrix = ::Matrix[
|
40
|
+
[1.0000000000000000.to_d, 0.3963377773761749.to_d, 0.2158037573099136.to_d],
|
41
|
+
[1.0000000000000000.to_d, -0.1055613458156586.to_d, -0.0638541728258133.to_d],
|
42
|
+
[1.0000000000000000.to_d, -0.0894841775298119.to_d, -1.2914855480194092.to_d]
|
43
|
+
]
|
44
|
+
|
45
|
+
l_lms, m_lms, s_lms = (lab_to_lms_matrix * ::Matrix.column_vector([l, a, b])).to_a.flatten
|
46
|
+
|
47
|
+
l_lms **= 3.0.to_d
|
48
|
+
m_lms **= 3.0.to_d
|
49
|
+
s_lms **= 3.0.to_d
|
50
|
+
|
51
|
+
lms_to_xyz_matrix = ::Matrix[
|
52
|
+
[1.2268798758459243.to_d, -0.5578149944602171.to_d, 0.2813910456659647.to_d],
|
53
|
+
[-0.0405757452148008.to_d, 1.1122868032803170.to_d, -0.0717110580655164.to_d],
|
54
|
+
[-0.0763729366746601.to_d, -0.4214933324022432.to_d, 1.5869240198367816.to_d]
|
55
|
+
]
|
56
|
+
|
57
|
+
x, y, z = (lms_to_xyz_matrix * ::Matrix.column_vector([l_lms, m_lms, s_lms])).to_a.flatten
|
58
|
+
|
59
|
+
x *= 100.0.to_d
|
60
|
+
y *= 100.0.to_d
|
61
|
+
z *= 100.0.to_d
|
62
|
+
|
63
|
+
[x, y, z]
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.xyz_to_oklab(xyz_array)
|
67
|
+
x, y, z = xyz_array.map(&:to_d)
|
68
|
+
|
69
|
+
# The transformation matrix expects normalised X, Y, Z values.
|
70
|
+
x /= 100.0.to_d
|
71
|
+
y /= 100.0.to_d
|
72
|
+
z /= 100.0.to_d
|
73
|
+
|
74
|
+
# Given XYZ relative to D65, convert to OKLab
|
75
|
+
xyz_to_lms_matrix = ::Matrix[
|
76
|
+
[0.8190224379967030.to_d, 0.3619062600528904.to_d, -0.1288737815209879.to_d],
|
77
|
+
[0.0329836539323885.to_d, 0.9292868615863434.to_d, 0.0361446663506424.to_d],
|
78
|
+
[0.0481771893596242.to_d, 0.2642395317527308.to_d, 0.6335478284694309.to_d]
|
79
|
+
]
|
80
|
+
|
81
|
+
l_lms, m_lms, s_lms = (xyz_to_lms_matrix * ::Matrix.column_vector([x, y, z])).to_a.flatten
|
82
|
+
|
83
|
+
cube_root = (1.0.to_d / 3.0.to_d)
|
84
|
+
l_lms **= cube_root
|
85
|
+
m_lms **= cube_root
|
86
|
+
s_lms **= cube_root
|
87
|
+
|
88
|
+
lms_to_lab_matrix = ::Matrix[
|
89
|
+
[0.2104542683093140.to_d, 0.7936177747023054.to_d, -0.0040720430116193.to_d],
|
90
|
+
[1.9779985324311684.to_d, -2.4285922420485799.to_d, 0.4505937096174110.to_d],
|
91
|
+
[0.0259040424655478.to_d, 0.7827717124575296.to_d, -0.8086757549230774.to_d]
|
92
|
+
]
|
93
|
+
|
94
|
+
l_lab, a_lab, b_lab = (lms_to_lab_matrix * ::Matrix.column_vector([l_lms, m_lms, s_lms])).to_a.flatten
|
95
|
+
|
96
|
+
# Now, scale l to a percentage
|
97
|
+
l_lab *= 100.0.to_d
|
98
|
+
|
99
|
+
[l_lab, a_lab, b_lab]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,58 +1,61 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ColorConverters
|
4
|
+
class OklchConverter < BaseConverter
|
5
|
+
def self.matches?(colour_input)
|
6
|
+
return false unless colour_input.is_a?(Hash)
|
7
|
+
|
8
|
+
colour_input.keys - [:l, :c, :h, :space] == [] && colour_input[:space].to_s == 'ok'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.bounds
|
12
|
+
{ l: [0.0, 100.0], c: [0.0, 500.0], h: [0.0, 360.0] }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_input(colour_input)
|
18
|
+
OklchConverter.bounds.collect do |key, range|
|
19
|
+
"#{key} must be between #{range[0]} and #{range[1]}" unless colour_input[key].to_f.between?(*range)
|
20
|
+
end.compact
|
21
|
+
end
|
22
|
+
|
23
|
+
def input_to_rgba(colour_input)
|
24
|
+
l, a, b = OklchConverter.oklch_to_oklab(colour_input)
|
25
|
+
x, y, z = OklabConverter.oklab_to_xyz({ l: l, a: a, b: b })
|
26
|
+
r, g, b = XyzConverter.xyz_to_rgb({ x: x, y: y, z: z })
|
27
|
+
|
28
|
+
[r, g, b, 1.0]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.oklch_to_oklab(colour_input)
|
32
|
+
l = colour_input[:l].to_d
|
33
|
+
c = colour_input[:c].to_d
|
34
|
+
h = colour_input[:h].to_d
|
35
|
+
|
36
|
+
h_rad = h * (Math::PI.to_d / 180.0.to_d)
|
37
|
+
|
38
|
+
a = c * Math.cos(h_rad).to_d
|
39
|
+
b = c * Math.sin(h_rad).to_d
|
40
|
+
|
41
|
+
[l, a, b]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.oklab_to_oklch(lab_array)
|
45
|
+
l, aa, bb = lab_array.map(&:to_d)
|
46
|
+
|
47
|
+
e = 0.000015.to_d; # if chroma is smaller than this, set hue to 0 similar to CIELch
|
48
|
+
|
49
|
+
c = ((aa**2.to_d) + (bb**2.to_d))**0.5.to_d
|
50
|
+
|
51
|
+
h_rad = Math.atan2(bb, aa).to_d
|
52
|
+
h = h_rad * (180.0.to_d / Math::PI.to_d)
|
53
|
+
|
54
|
+
h %= 360
|
55
|
+
|
56
|
+
h = 0 if c < e
|
57
|
+
|
58
|
+
[l, c, h]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|