red-colors 0.1.0 → 0.3.0
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 +3 -0
- data/data/colormaps/cividis.json +258 -0
- data/data/colormaps/coolwarm.json +107 -0
- data/data/colormaps/crest.json +258 -0
- data/data/colormaps/flare.json +258 -0
- data/data/colormaps/gist_earth.json +49 -0
- data/data/colormaps/gist_ncar.json +55 -0
- data/data/colormaps/icefire.json +258 -0
- data/data/colormaps/inferno.json +258 -0
- data/data/colormaps/magma.json +258 -0
- data/data/colormaps/mako.json +258 -0
- data/data/colormaps/nipy_spectral.json +71 -0
- data/data/colormaps/pink.json +200 -0
- data/data/colormaps/plasma.json +258 -0
- data/data/colormaps/rocket.json +258 -0
- data/data/colormaps/turbo.json +258 -0
- data/data/colormaps/twilight.json +512 -0
- data/data/colormaps/viridis.json +258 -0
- data/data/colormaps/vlag.json +258 -0
- data/lib/colors.rb +17 -5
- data/lib/colors/abstract_color.rb +4 -0
- data/lib/colors/colormap.rb +143 -0
- data/lib/colors/colormap_data.rb +44 -0
- data/lib/colors/colormap_data/matplotlib_builtin.rb +990 -0
- data/lib/colors/colormap_data/seaborn_builtin.rb +10 -0
- data/lib/colors/colormap_registry.rb +62 -0
- data/lib/colors/convert.rb +269 -0
- data/lib/colors/helper.rb +2 -1
- data/lib/colors/husl.rb +7 -100
- data/lib/colors/linear_segmented_colormap.rb +137 -0
- data/lib/colors/listed_colormap.rb +45 -0
- data/lib/colors/named_colors.rb +10 -20
- data/lib/colors/rgb.rb +20 -10
- data/lib/colors/rgba.rb +14 -8
- data/lib/colors/utils.rb +18 -0
- data/lib/colors/version.rb +1 -1
- data/lib/colors/xterm256.rb +56 -0
- data/lib/colors/xyy.rb +48 -0
- data/lib/colors/xyz.rb +2 -55
- data/red-colors.gemspec +3 -1
- data/test/test-husl.rb +45 -53
- data/test/test-linear-segmented-colormap.rb +138 -0
- data/test/test-listed-colormap.rb +134 -0
- data/test/test-rgb.rb +76 -1
- data/test/test-xterm256.rb +76 -0
- data/test/test-xyz.rb +1 -1
- metadata +50 -15
@@ -0,0 +1,10 @@
|
|
1
|
+
module Colors
|
2
|
+
module ColormapRegistry
|
3
|
+
register_listed_colormap("rocket")
|
4
|
+
register_listed_colormap("mako")
|
5
|
+
register_listed_colormap("icefire")
|
6
|
+
register_listed_colormap("vlag")
|
7
|
+
register_listed_colormap("flare")
|
8
|
+
register_listed_colormap("crest")
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Colors
|
2
|
+
module ColormapRegistry
|
3
|
+
@registry = {}
|
4
|
+
|
5
|
+
def self.[](name)
|
6
|
+
return name if name.is_a?(Colormap)
|
7
|
+
|
8
|
+
name = String.try_convert(name)
|
9
|
+
if @registry.key?(name)
|
10
|
+
return @registry[name]
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Unknown colormap name: %p" % name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.register(cmap, name: nil, override_builtin: false)
|
17
|
+
case name
|
18
|
+
when String, Symbol
|
19
|
+
name = name.to_s
|
20
|
+
when nil
|
21
|
+
name = cmap.name
|
22
|
+
if name.nil?
|
23
|
+
raise ArgumentError, "`name` cannot be omitted for unnamed colormaps"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
name = String.try_convert(name)
|
27
|
+
if name.nil?
|
28
|
+
raise ArgumentError, "`name` must be convertible to a String by to_str"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if @registry.key?(name)
|
33
|
+
existing = @registry[name]
|
34
|
+
if BUILTIN_COLORMAPS.key?(name)
|
35
|
+
unless override_builtin
|
36
|
+
raise ArgumentError,
|
37
|
+
"Trying to re-register a builtin colormap: %p" % name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
warn "Trying to re-register the colormap %p which already exists" % name
|
41
|
+
end
|
42
|
+
|
43
|
+
unless cmap.is_a?(Colormap)
|
44
|
+
raise ArgumentError,
|
45
|
+
"Invalid value for registering a colormap (%p for a Colormap)" % cmap
|
46
|
+
end
|
47
|
+
|
48
|
+
@registry[name] = cmap
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.unregister(name)
|
52
|
+
if @registry.key?(name)
|
53
|
+
if BUILTIN_COLORMAPS.key?(name)
|
54
|
+
raise ArgumentError,
|
55
|
+
"Unable to unregister the colormap %p which is a builtin colormap" % name
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@registry.delete(name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
require "matrix"
|
2
|
+
|
3
|
+
module Colors
|
4
|
+
module Convert
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Sort alphabetically by FROM name such as degree, LCh, LUV and so on.
|
8
|
+
|
9
|
+
# Utilities
|
10
|
+
|
11
|
+
private def dot_product(matrix, vector)
|
12
|
+
matrix.map do |row|
|
13
|
+
product = 0.0
|
14
|
+
row.zip(vector) do |value1, value2|
|
15
|
+
product += value1 * value2
|
16
|
+
end
|
17
|
+
product
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private def matrix_inv(matrix)
|
22
|
+
matrix = Matrix[*matrix]
|
23
|
+
matrix.inv.to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
def max_chroma(l, h)
|
27
|
+
h_rad = degree_to_radian(h)
|
28
|
+
sin_h = Math.sin(h_rad).to_r
|
29
|
+
cos_h = Math.cos(h_rad).to_r
|
30
|
+
|
31
|
+
max = Float::INFINITY
|
32
|
+
luminance_bounds(l).each do |line|
|
33
|
+
len = line[1] / (sin_h - line[0] * cos_h)
|
34
|
+
max = len if 0 <= len && len < max
|
35
|
+
end
|
36
|
+
max
|
37
|
+
end
|
38
|
+
|
39
|
+
private def luminance_bounds(l)
|
40
|
+
sub1 = (l + 16)**3 / 1560896r
|
41
|
+
sub2 = sub1 > XYZ::EPSILON ? sub1 : l/XYZ::KAPPA
|
42
|
+
|
43
|
+
bounds = Array.new(6) { [0r, 0r] }
|
44
|
+
0.upto(2) do |ch|
|
45
|
+
m1 = M_XYZ_RGB[ch][0].to_r
|
46
|
+
m2 = M_XYZ_RGB[ch][1].to_r
|
47
|
+
m3 = M_XYZ_RGB[ch][2].to_r
|
48
|
+
|
49
|
+
[0, 1].each do |t|
|
50
|
+
top1 = (284517r * m1 - 94839r * m3) * sub2
|
51
|
+
top2 = (838422r * m3 + 769860r * m2 + 731718r * m1) * l * sub2 - 769860r * t * l
|
52
|
+
bottom = (632260r * m3 - 126452r * m2) * sub2 + 126452r * t
|
53
|
+
|
54
|
+
bounds[ch*2 + t][0] = top1 / bottom
|
55
|
+
bounds[ch*2 + t][1] = top2 / bottom
|
56
|
+
end
|
57
|
+
end
|
58
|
+
bounds
|
59
|
+
end
|
60
|
+
|
61
|
+
# degree -> ???
|
62
|
+
|
63
|
+
DEG2RAD = 0.01745329251994329577r # 2 * pi / 360
|
64
|
+
def degree_to_radian(d)
|
65
|
+
d * DEG2RAD
|
66
|
+
end
|
67
|
+
|
68
|
+
# LCh -> ???
|
69
|
+
|
70
|
+
def lch_to_husl(l, c, h)
|
71
|
+
if l > 99.9999999 || l < 1e-8
|
72
|
+
s = 0r
|
73
|
+
else
|
74
|
+
mx = max_chroma(l, h)
|
75
|
+
s = c / mx * 100r
|
76
|
+
end
|
77
|
+
|
78
|
+
h = 0r if c < 1e-8
|
79
|
+
|
80
|
+
[h, s/100r, l/100r]
|
81
|
+
end
|
82
|
+
|
83
|
+
def lch_to_luv(l, c, h)
|
84
|
+
h_rad = degree_to_radian(h)
|
85
|
+
u = Math.cos(h_rad).to_r * c
|
86
|
+
v = Math.sin(h_rad).to_r * c
|
87
|
+
[l, u, v]
|
88
|
+
end
|
89
|
+
|
90
|
+
def lch_to_xyz(l, c, h)
|
91
|
+
luv_to_xyz(*lch_to_luv(l, c, h))
|
92
|
+
end
|
93
|
+
|
94
|
+
# linear-sRGB -> ???
|
95
|
+
|
96
|
+
def linear_srgb_to_srgb(r, g, b)
|
97
|
+
[r, g, b].map do |v|
|
98
|
+
# the following is an optimization technique for `1.055*v**(1/2.4) - 0.055`.
|
99
|
+
# x^y ~= exp(y*log(x)) ~= exp2(y*log2(y)); the middle form is faster
|
100
|
+
#
|
101
|
+
# See https://github.com/JuliaGraphics/Colors.jl/issues/351#issuecomment-532073196
|
102
|
+
# for more detail benchmark in Julia language.
|
103
|
+
if v <= 0.0031308
|
104
|
+
12.92*v
|
105
|
+
else
|
106
|
+
1.055 * Math.exp(1/2.4 * Math.log(v)) - 0.055
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Luv -> ???
|
112
|
+
|
113
|
+
def luv_to_husl(l, u, v)
|
114
|
+
lch_to_husl(*luv_to_lch(l, u, v))
|
115
|
+
end
|
116
|
+
|
117
|
+
def luv_to_lch(l, u, v)
|
118
|
+
c = Math.sqrt(u*u + v*v).to_r
|
119
|
+
hard = Math.atan2(v, u).to_r
|
120
|
+
h = hard * 180 / Math::PI.to_r
|
121
|
+
h += 360r if h < 0
|
122
|
+
[l, c, h]
|
123
|
+
end
|
124
|
+
|
125
|
+
def luv_to_xyz(l, u, v)
|
126
|
+
return [0r, 0r, 0r] if l <= 1e-8
|
127
|
+
|
128
|
+
wp_u, wp_v = WHITE_POINT_D65.uv_values
|
129
|
+
var_u = u / (13 * l) + wp_u
|
130
|
+
var_v = v / (13 * l) + wp_v
|
131
|
+
y = if l < 8
|
132
|
+
l / XYZ::KAPPA
|
133
|
+
else
|
134
|
+
((l + 16r) / 116r)**3
|
135
|
+
end
|
136
|
+
x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v)
|
137
|
+
z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3 * var_v)
|
138
|
+
[x, y, z]
|
139
|
+
end
|
140
|
+
|
141
|
+
# RGB -> ???
|
142
|
+
|
143
|
+
RGB2XYZ = [
|
144
|
+
[ 0.41239079926595948129, 0.35758433938387796373, 0.18048078840183428751 ],
|
145
|
+
[ 0.21263900587151035754, 0.71516867876775592746, 0.07219231536073371500 ],
|
146
|
+
[ 0.01933081871559185069, 0.11919477979462598791, 0.95053215224966058086 ]
|
147
|
+
]
|
148
|
+
|
149
|
+
def rgb_to_xyz(r, g, b)
|
150
|
+
dot_product(RGB2XYZ, srgb_to_linear_srgb(r, g, b))
|
151
|
+
end
|
152
|
+
|
153
|
+
def rgb_to_xterm256(r, g, b)
|
154
|
+
i = closest_xterm256_rgb_index(r)
|
155
|
+
j = closest_xterm256_rgb_index(g)
|
156
|
+
k = closest_xterm256_rgb_index(b)
|
157
|
+
|
158
|
+
r0 = xterm256_rgb_index_to_rgb_value(i)
|
159
|
+
g0 = xterm256_rgb_index_to_rgb_value(j)
|
160
|
+
b0 = xterm256_rgb_index_to_rgb_value(k)
|
161
|
+
d0 = (r - r0)**2 + (g - g0)**2 + (b - b0)**2
|
162
|
+
|
163
|
+
l = closest_xterm256_gray_index(r, g, b)
|
164
|
+
gr = xterm256_gray_index_to_gray_level(l)
|
165
|
+
d1 = (r - gr)**2 + (g - gr)**2 + (b - gr)**2
|
166
|
+
|
167
|
+
if d0 > d1
|
168
|
+
xterm256_gray_index_to_code(l)
|
169
|
+
else
|
170
|
+
xterm256_rgb_indices_to_code(i, j, k)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def xterm256_rgb_index_to_rgb_value(i)
|
175
|
+
(i == 0) ? 0 : (40*i + 55)/255.0
|
176
|
+
end
|
177
|
+
|
178
|
+
def closest_xterm256_rgb_index(x)
|
179
|
+
([x*255 - 55, 0].max / 40.0).round
|
180
|
+
end
|
181
|
+
|
182
|
+
def xterm256_gray_index_to_gray_level(i)
|
183
|
+
(10*i + 8)/255.0
|
184
|
+
end
|
185
|
+
|
186
|
+
def closest_xterm256_gray_index(r, g, b)
|
187
|
+
((255*(r + g + b) - 24)/30.0).round.clamp(0, 23)
|
188
|
+
end
|
189
|
+
|
190
|
+
def xterm256_rgb_indices_to_code(i, j, k)
|
191
|
+
6*(6*i + j) + k + 16
|
192
|
+
end
|
193
|
+
|
194
|
+
def xterm256_gray_index_to_code(i)
|
195
|
+
i + 232
|
196
|
+
end
|
197
|
+
|
198
|
+
# sRGB -> ???
|
199
|
+
|
200
|
+
def srgb_from_linear_srgb(r, g, b)
|
201
|
+
a = 0.055r
|
202
|
+
[r, g, b].map do |v|
|
203
|
+
if v < 0.0031308
|
204
|
+
12.92r * v
|
205
|
+
else
|
206
|
+
(1 + a) * v**(1/2.4r) - a
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def srgb_to_linear_srgb(r, g, b)
|
212
|
+
a = 0.055r
|
213
|
+
[r, g, b].map do |v|
|
214
|
+
if v > 0.04045
|
215
|
+
((v + a) / (1 + a)) ** 2.4r
|
216
|
+
else
|
217
|
+
v / 12.92r
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# xyY -> ???
|
223
|
+
|
224
|
+
def xyy_to_xyz(x, y, large_y)
|
225
|
+
large_x = large_y*x/y
|
226
|
+
large_z = large_y*(1 - x - y)/y
|
227
|
+
[large_x, large_y, large_z]
|
228
|
+
end
|
229
|
+
|
230
|
+
# XYZ -> ???
|
231
|
+
|
232
|
+
# sRGB reference points
|
233
|
+
R_xyY = [0.64r, 0.33r, 1r]
|
234
|
+
G_xyY = [0.30r, 0.60r, 1r]
|
235
|
+
B_xyY = [0.15r, 0.06r, 1r]
|
236
|
+
D65_xyY = [0.3127r, 0.3290r, 1r]
|
237
|
+
|
238
|
+
R_XYZ = xyy_to_xyz(*R_xyY)
|
239
|
+
G_XYZ = xyy_to_xyz(*G_xyY)
|
240
|
+
B_XYZ = xyy_to_xyz(*B_xyY)
|
241
|
+
D65_XYZ = xyy_to_xyz(*D65_xyY)
|
242
|
+
|
243
|
+
M_P = [
|
244
|
+
[R_XYZ[0], G_XYZ[0], B_XYZ[0]],
|
245
|
+
[R_XYZ[1], G_XYZ[1], B_XYZ[1]],
|
246
|
+
[R_XYZ[2], G_XYZ[2], B_XYZ[2]]
|
247
|
+
]
|
248
|
+
|
249
|
+
M_S = dot_product(matrix_inv(M_P), D65_XYZ)
|
250
|
+
|
251
|
+
M_RGB_XYZ = (0 ... 3).map do |i|
|
252
|
+
(0 ... 3).map {|j| (M_S[j] * M_P[i][j]).round(4) }
|
253
|
+
end
|
254
|
+
|
255
|
+
M_XYZ_RGB = matrix_inv(M_RGB_XYZ).map do |row|
|
256
|
+
row.map {|v| v.round(4) }
|
257
|
+
end
|
258
|
+
|
259
|
+
def xyz_to_rgb(x, y, z)
|
260
|
+
r, g, b = dot_product(M_XYZ_RGB, [x, y, z])
|
261
|
+
r, g, b = srgb_from_linear_srgb(r, g, b)
|
262
|
+
[
|
263
|
+
r.clamp(0r, 1r),
|
264
|
+
g.clamp(0r, 1r),
|
265
|
+
b.clamp(0r, 1r)
|
266
|
+
]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
data/lib/colors/helper.rb
CHANGED
@@ -7,7 +7,8 @@ module Colors
|
|
7
7
|
|
8
8
|
private def check_range(value, range, name)
|
9
9
|
return value if range.cover?(value)
|
10
|
-
check_fail ArgumentError,
|
10
|
+
check_fail ArgumentError,
|
11
|
+
"#{name} must be in #{range}, but %p is given" % value
|
11
12
|
end
|
12
13
|
|
13
14
|
private def check_fail(exc_class, message)
|
data/lib/colors/husl.rb
CHANGED
@@ -1,45 +1,7 @@
|
|
1
|
-
require "numo/narray"
|
2
|
-
|
3
1
|
module Colors
|
4
2
|
# Human-friendly alternative to HSL color space.
|
5
3
|
# The definition of HUSL is provided in <http://www.hsluv.org>.
|
6
4
|
class HUSL < HSL
|
7
|
-
DEG2RAD = 0.01745329251994329577r # 2 * pi / 360
|
8
|
-
|
9
|
-
def self.from_rgb(r, g, b)
|
10
|
-
c = XYZ.from_rgb(r, g, b)
|
11
|
-
l, u, v = c.luv_components(WHITE_POINT_D65)
|
12
|
-
l, c, h = convert_luv_to_lch(l, u, v)
|
13
|
-
h, s, l = convert_lch_to_husl(l, c, h)
|
14
|
-
new(h, s.to_r.clamp(0r, 1r), l.to_r.clamp(0r, 1r))
|
15
|
-
end
|
16
|
-
|
17
|
-
private_class_method def self.convert_luv_to_lch(l, u, v)
|
18
|
-
c = Math.sqrt(u*u + v*v).to_r
|
19
|
-
|
20
|
-
if c < 1e-8
|
21
|
-
h = 0r
|
22
|
-
else
|
23
|
-
h = Math.atan2(v, u).to_r * 180/Math::PI.to_r
|
24
|
-
h += 360r if h < 0
|
25
|
-
end
|
26
|
-
|
27
|
-
[l, c, h]
|
28
|
-
end
|
29
|
-
|
30
|
-
private_class_method def self.convert_lch_to_husl(l, c, h)
|
31
|
-
if l > 99.9999999 || l < 1e-8
|
32
|
-
s = 0r
|
33
|
-
else
|
34
|
-
mx = max_chroma(l, h)
|
35
|
-
s = c / mx * 100r
|
36
|
-
end
|
37
|
-
|
38
|
-
h = 0r if c < 1e-8
|
39
|
-
|
40
|
-
[h, s/100r, l/100r]
|
41
|
-
end
|
42
|
-
|
43
5
|
def ==(other)
|
44
6
|
case other
|
45
7
|
when HUSL
|
@@ -61,10 +23,13 @@ module Colors
|
|
61
23
|
RGB.new(*rgb_components)
|
62
24
|
end
|
63
25
|
|
26
|
+
def to_xyz
|
27
|
+
x, y, z = Convert.lch_to_xyz(*lch_components)
|
28
|
+
XYZ.new(x, y, z)
|
29
|
+
end
|
30
|
+
|
64
31
|
def rgb_components
|
65
|
-
|
66
|
-
x, y, z = convert_luv_to_xyz(l, u, v)
|
67
|
-
XYZ.new(x, y, z).rgb_components
|
32
|
+
to_xyz.rgb_components
|
68
33
|
end
|
69
34
|
|
70
35
|
def lch_components
|
@@ -74,7 +39,7 @@ module Colors
|
|
74
39
|
if l > 99.9999999 || l < 1e-8
|
75
40
|
c = 0r
|
76
41
|
else
|
77
|
-
mx =
|
42
|
+
mx = Convert.max_chroma(l, h)
|
78
43
|
c = mx / 100r * s
|
79
44
|
end
|
80
45
|
|
@@ -82,63 +47,5 @@ module Colors
|
|
82
47
|
|
83
48
|
[l, c, h]
|
84
49
|
end
|
85
|
-
|
86
|
-
private def convert_lch_to_luv(l, c, h)
|
87
|
-
h_rad = h * DEG2RAD
|
88
|
-
u = Math.cos(h_rad).to_r * c
|
89
|
-
v = Math.sin(h_rad).to_r * c
|
90
|
-
[l, u, v]
|
91
|
-
end
|
92
|
-
|
93
|
-
private def convert_luv_to_xyz(l, u, v)
|
94
|
-
return [0r, 0r, 0r] if l <= 1e-8
|
95
|
-
|
96
|
-
wp_u, wp_v = WHITE_POINT_D65.uv_values
|
97
|
-
var_u = u / (13 * l) + wp_u
|
98
|
-
var_v = v / (13 * l) + wp_v
|
99
|
-
y = if l < 8
|
100
|
-
l / XYZ::KAPPA
|
101
|
-
else
|
102
|
-
((l + 16r) / 116r)**3
|
103
|
-
end
|
104
|
-
x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v)
|
105
|
-
z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3 * var_v)
|
106
|
-
[x, y, z]
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.max_chroma(l, h)
|
110
|
-
h_rad = h * DEG2RAD
|
111
|
-
sin_h = Math.sin(h_rad).to_r
|
112
|
-
cos_h = Math.cos(h_rad).to_r
|
113
|
-
|
114
|
-
result = Float::INFINITY
|
115
|
-
get_bounds(l).each do |line|
|
116
|
-
len = line[1] / (sin_h - line[0] * cos_h)
|
117
|
-
result = len if 0 <= len && len < result
|
118
|
-
end
|
119
|
-
result
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.get_bounds(l)
|
123
|
-
sub1 = (l + 16)**3 / 1560896r
|
124
|
-
sub2 = sub1 > XYZ::EPSILON ? sub1 : l/XYZ::KAPPA
|
125
|
-
|
126
|
-
bounds = Array.new(6) { [0r, 0r] }
|
127
|
-
0.upto(2) do |ch|
|
128
|
-
m1 = XYZ2RGB[ch, 0].to_r
|
129
|
-
m2 = XYZ2RGB[ch, 1].to_r
|
130
|
-
m3 = XYZ2RGB[ch, 2].to_r
|
131
|
-
|
132
|
-
[0, 1].each do |t|
|
133
|
-
top1 = (284517r * m1 - 94839r * m3) * sub2
|
134
|
-
top2 = (838422r * m3 + 769860r * m2 + 731718r * m1) * l * sub2 - 769860r * t * l
|
135
|
-
bottom = (632260r * m3 - 126452r * m2) * sub2 + 126452r * t
|
136
|
-
|
137
|
-
bounds[ch*2 + t][0] = top1 / bottom
|
138
|
-
bounds[ch*2 + t][1] = top2 / bottom
|
139
|
-
end
|
140
|
-
end
|
141
|
-
bounds
|
142
|
-
end
|
143
50
|
end
|
144
51
|
end
|