color_calculator 0.0.1
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 +7 -0
- data/Gemfile +10 -0
- data/Rakefile +11 -0
- data/lib/color_calculator.rb +7 -0
- data/lib/color_calculator/calculation.rb +7 -0
- data/lib/color_calculator/calculation/delta_e_2000.rb +193 -0
- data/lib/color_calculator/clump.rb +11 -0
- data/lib/color_calculator/clump/abstract.rb +36 -0
- data/lib/color_calculator/clump/lab.rb +15 -0
- data/lib/color_calculator/clump/lch_ab.rb +15 -0
- data/lib/color_calculator/clump/rgb.rb +34 -0
- data/lib/color_calculator/clump/xyz.rb +15 -0
- data/lib/color_calculator/conversion.rb +10 -0
- data/lib/color_calculator/conversion/lab_to_lch_ab.rb +43 -0
- data/lib/color_calculator/conversion/rgb_to_lch_ab.rb +35 -0
- data/lib/color_calculator/conversion/rgb_to_xyz.rb +69 -0
- data/lib/color_calculator/conversion/xyz_to_lab.rb +59 -0
- data/lib/color_calculator/shared/composable.rb +13 -0
- metadata +60 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4095a8dfe79681c7faf97a1610b6fd5f88b8202b4db278543db7dd8c639e1a88
|
4
|
+
data.tar.gz: 15cd1be590199c95cbb52d68241cde2a8ba26953aba0832a366e799ed33d359b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f74c83270cf82df3853bc03428069a0760c575a39a48d7e32e1bd2cd1b5ea73bb955892691dfeec1e56900958c3338e9f2d4bb5d244d211852080ff0373cc10b
|
7
|
+
data.tar.gz: e4602a3606d6a679512b7f621b116e017e99e59ee93b4e3ce316a60814cb3a095ac5fdb86d1a6fb32b4100146e6fd87b0f9e720ac62910835bb2bb282f0623b7
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_calculator/clump/lab'
|
4
|
+
|
5
|
+
module ColorCalculator
|
6
|
+
module Calculation
|
7
|
+
class DeltaE2000
|
8
|
+
class << self
|
9
|
+
def call(*args)
|
10
|
+
new(*args).call
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RADIANS_TO_DEGREES = 180.to_f / Math::PI
|
15
|
+
DEGREES_TO_RADIANS = 1.to_f / RADIANS_TO_DEGREES
|
16
|
+
|
17
|
+
K_OF_L = 1
|
18
|
+
K_OF_C = 1
|
19
|
+
K_OF_H = 1
|
20
|
+
|
21
|
+
def initialize(sample, reference)
|
22
|
+
@sample = sample
|
23
|
+
@reference = reference
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
Math.sqrt(
|
28
|
+
[
|
29
|
+
Rational(delta_l_prime, K_OF_L * s_of_l) ** 2,
|
30
|
+
Rational(delta_c_prime, K_OF_C * s_of_c) ** 2,
|
31
|
+
Rational(delta_h_prime, K_OF_H * s_of_h) ** 2,
|
32
|
+
[
|
33
|
+
r_of_t,
|
34
|
+
Rational(delta_c_prime, K_OF_C * s_of_c),
|
35
|
+
Rational(delta_h_prime, K_OF_H * s_of_h),
|
36
|
+
].reduce(:*)
|
37
|
+
].reduce(:+)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :sample, :reference
|
44
|
+
|
45
|
+
def delta_l_prime
|
46
|
+
sample.lightness - reference.lightness
|
47
|
+
end
|
48
|
+
|
49
|
+
def s_of_l
|
50
|
+
1 + Rational(
|
51
|
+
0.015 * ((l_bar_prime - 50) ** 2),
|
52
|
+
Math.sqrt(20 + ((l_bar_prime - 50) ** 2))
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delta_c_prime
|
57
|
+
c_prime_sample - c_prime_reference
|
58
|
+
end
|
59
|
+
|
60
|
+
def s_of_c
|
61
|
+
1 + 0.045 * c_bar_prime
|
62
|
+
end
|
63
|
+
|
64
|
+
def delta_h_prime
|
65
|
+
[
|
66
|
+
2,
|
67
|
+
Math.sqrt(c_prime_reference * c_prime_sample),
|
68
|
+
Math.sin(Rational(delta_little_h_prime, 2) * DEGREES_TO_RADIANS),
|
69
|
+
].reduce(:*)
|
70
|
+
end
|
71
|
+
|
72
|
+
def s_of_h
|
73
|
+
1 + 0.015 * c_bar_prime * big_t
|
74
|
+
end
|
75
|
+
|
76
|
+
def r_of_t
|
77
|
+
-1 * Math.sin(2 * delta_theta * DEGREES_TO_RADIANS) * r_of_c
|
78
|
+
end
|
79
|
+
|
80
|
+
%i[reference sample].each do |lab|
|
81
|
+
define_method("c_#{lab}") do
|
82
|
+
%i[alpha beta].
|
83
|
+
map { |val| send(lab).public_send(val) ** 2 }.
|
84
|
+
reduce(:+) ** Rational(1, 2)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def c_bar
|
89
|
+
(c_reference + c_sample) / 2.0
|
90
|
+
end
|
91
|
+
|
92
|
+
def big_g
|
93
|
+
0.5 * (1 - Math.sqrt(Rational(c_bar ** 7, c_bar ** 7 + 25 ** 7)))
|
94
|
+
end
|
95
|
+
|
96
|
+
%i[reference sample].each do |lab|
|
97
|
+
# def a_prime_reference
|
98
|
+
# def a_prime_sample
|
99
|
+
define_method("a_prime_#{lab}") do
|
100
|
+
(1 + big_g) * send(lab).alpha
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
%i[reference sample].each do |lab|
|
105
|
+
# def c_prime_reference
|
106
|
+
# def c_prime_sample
|
107
|
+
define_method("c_prime_#{lab}") do
|
108
|
+
Math.sqrt(send("a_prime_#{lab}") ** 2 + send(lab).beta ** 2)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
%i[reference sample].each do |lab|
|
113
|
+
# def little_h_prime_reference
|
114
|
+
# def little_h_prime_sample
|
115
|
+
define_method("little_h_prime_#{lab}") do
|
116
|
+
return 0 if [send(lab).beta, send("a_prime_#{lab}")].all? { |el| el == 0 }
|
117
|
+
|
118
|
+
(Math.atan2(send(lab).beta, send("a_prime_#{lab}")) * RADIANS_TO_DEGREES) % 360
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def delta_little_h_prime
|
123
|
+
c_prime_product = c_prime_reference * c_prime_sample
|
124
|
+
difference = little_h_prime_sample - little_h_prime_reference
|
125
|
+
|
126
|
+
if c_prime_product.zero?
|
127
|
+
0
|
128
|
+
elsif !c_prime_product.zero? && difference.abs <= 180
|
129
|
+
difference
|
130
|
+
elsif !c_prime_product.zero? && difference > 180
|
131
|
+
difference - 360
|
132
|
+
elsif !c_prime_product.zero? && difference < -180
|
133
|
+
difference + 360
|
134
|
+
else
|
135
|
+
raise "SOMETHING IS WRONG"
|
136
|
+
end
|
137
|
+
# return 0 if c_prime_sample * c_prime_reference == 0
|
138
|
+
|
139
|
+
# val = little_h_prime_sample - little_h_prime_reference
|
140
|
+
|
141
|
+
# return val if val.abs >= 180
|
142
|
+
# sign = val <=> 0
|
143
|
+
|
144
|
+
# val - sign * 360
|
145
|
+
end
|
146
|
+
|
147
|
+
def l_bar_prime
|
148
|
+
Rational(reference.lightness + sample.lightness, 2)
|
149
|
+
end
|
150
|
+
|
151
|
+
def c_bar_prime
|
152
|
+
Rational(c_prime_reference + c_prime_sample, 2)
|
153
|
+
end
|
154
|
+
|
155
|
+
def little_h_bar_prime
|
156
|
+
sum = little_h_prime_reference + little_h_prime_sample
|
157
|
+
difference = little_h_prime_reference - little_h_prime_sample
|
158
|
+
c_prime_product = c_prime_reference * c_prime_sample
|
159
|
+
|
160
|
+
|
161
|
+
if difference.abs <= 180 && !c_prime_product.zero?
|
162
|
+
Rational(sum, 2)
|
163
|
+
elsif difference.abs > 180 && sum < 360 && !c_prime_product.zero?
|
164
|
+
Rational(sum + 360, 2)
|
165
|
+
elsif difference.abs > 180 && sum >= 360 && !c_prime_product.zero?
|
166
|
+
Rational(sum - 360, 2)
|
167
|
+
elsif c_prime_product.zero?
|
168
|
+
sum
|
169
|
+
else
|
170
|
+
raise "SOMETHING IS WRONG"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def big_t
|
175
|
+
[
|
176
|
+
1,
|
177
|
+
-0.17 * Math.cos((little_h_bar_prime - 30) * DEGREES_TO_RADIANS),
|
178
|
+
0.24 * Math.cos(2 * little_h_bar_prime * DEGREES_TO_RADIANS),
|
179
|
+
0.32 * Math.cos((3 * little_h_bar_prime + 6) * DEGREES_TO_RADIANS),
|
180
|
+
-0.2 * Math.cos((4 * little_h_bar_prime - 63) * DEGREES_TO_RADIANS),
|
181
|
+
].reduce(:+)
|
182
|
+
end
|
183
|
+
|
184
|
+
def delta_theta
|
185
|
+
30 * Math::E ** (-1 * (Rational(little_h_bar_prime - 275, 25) ** 2))
|
186
|
+
end
|
187
|
+
|
188
|
+
def r_of_c
|
189
|
+
2 * Math.sqrt(Rational(c_bar_prime ** 7, c_bar_prime ** 7 + 25 ** 7))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ColorCalculator
|
4
|
+
module Clump
|
5
|
+
class UnlikeComparisonError < StandardError; end
|
6
|
+
|
7
|
+
class Abstract
|
8
|
+
def initialize(*attributes)
|
9
|
+
self.class.attributes.each.with_index do |name, index|
|
10
|
+
instance_variable_set("@#{name}".to_sym, attributes[index])
|
11
|
+
|
12
|
+
define_singleton_method(name) do
|
13
|
+
instance_variable_get("@#{name}".to_sym)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
self.class.attributes.reduce({}) do |memo, message|
|
20
|
+
memo.merge(message => public_send(message))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(other)
|
25
|
+
raise UnlikeComparisonError if self.class != other.class
|
26
|
+
|
27
|
+
to_h == other.to_h
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
to_h.to_s
|
32
|
+
end
|
33
|
+
alias_method :to_s, :inspect
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'abstract'
|
4
|
+
|
5
|
+
module ColorCalculator
|
6
|
+
module Clump
|
7
|
+
class Rgb < Abstract
|
8
|
+
class << self
|
9
|
+
def attributes
|
10
|
+
%i[red green blue]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(*attributes, normalized:)
|
15
|
+
@red, @green, @blue = attributes
|
16
|
+
@normalized = normalized
|
17
|
+
end
|
18
|
+
|
19
|
+
%i[red green blue].each do |value|
|
20
|
+
define_method(value) do
|
21
|
+
Rational(instance_variable_get("@#{value}"), scale)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :normalized
|
28
|
+
|
29
|
+
def scale
|
30
|
+
normalized ? 1 : 255
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'conversion/lab_to_lch_ab'
|
4
|
+
require_relative 'conversion/rgb_to_xyz'
|
5
|
+
require_relative 'conversion/rgb_to_lch_ab'
|
6
|
+
require_relative 'conversion/xyz_to_lab'
|
7
|
+
|
8
|
+
module ColorCalculator
|
9
|
+
module Conversion; end
|
10
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_calculator/clump/lab'
|
4
|
+
require 'color_calculator/clump/lch_ab'
|
5
|
+
require 'color_calculator/shared/composable'
|
6
|
+
|
7
|
+
module ColorCalculator
|
8
|
+
module Conversion
|
9
|
+
class LabToLchAb
|
10
|
+
extend ColorCalculator::Composable
|
11
|
+
|
12
|
+
RADIANS_TO_DEGREES = 180 / Math::PI
|
13
|
+
|
14
|
+
def initialize(lab)
|
15
|
+
@lab = lab
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
ColorCalculator::Clump::LchAb.new(lightness, chroma, hue)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :lab
|
25
|
+
|
26
|
+
def lightness
|
27
|
+
lab.lightness
|
28
|
+
end
|
29
|
+
|
30
|
+
def chroma
|
31
|
+
(lab.alpha ** 2 + lab.beta ** 2) ** Rational(1, 2)
|
32
|
+
end
|
33
|
+
|
34
|
+
def hue
|
35
|
+
val = Math.atan2(lab.beta, lab.alpha) * RADIANS_TO_DEGREES
|
36
|
+
|
37
|
+
return val if val >= 0
|
38
|
+
|
39
|
+
val + 360
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_calculator/shared/composable'
|
4
|
+
|
5
|
+
module ColorCalculator
|
6
|
+
module Conversion
|
7
|
+
class RgbToLchAb
|
8
|
+
extend ColorCalculator::Composable
|
9
|
+
|
10
|
+
def initialize(rgb)
|
11
|
+
@rgb = rgb
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
composed_path.call(rgb)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :rgb
|
21
|
+
|
22
|
+
def composed_path
|
23
|
+
conversion_path.map(&:to_proc).reduce(:>>)
|
24
|
+
end
|
25
|
+
|
26
|
+
def conversion_path
|
27
|
+
[
|
28
|
+
ColorCalculator::Conversion::RgbToXyz,
|
29
|
+
ColorCalculator::Conversion::XyzToLab,
|
30
|
+
ColorCalculator::Conversion::LabToLchAb
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_calculator/clump/rgb'
|
4
|
+
require 'color_calculator/clump/xyz'
|
5
|
+
require 'color_calculator/shared/composable'
|
6
|
+
|
7
|
+
module ColorCalculator
|
8
|
+
module Conversion
|
9
|
+
class RgbToXyz
|
10
|
+
extend ColorCalculator::Composable
|
11
|
+
|
12
|
+
def initialize(rgb)
|
13
|
+
@rgb = rgb
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
ColorCalculator::Clump::Xyz.new(x, y, z)
|
18
|
+
end
|
19
|
+
|
20
|
+
APPLE = -> (value) do
|
21
|
+
value / 12.92
|
22
|
+
end
|
23
|
+
|
24
|
+
BANANA = -> (value) do
|
25
|
+
((value + 0.055)/1.055) ** Rational(12, 5)
|
26
|
+
end
|
27
|
+
|
28
|
+
FRUIT = -> (value) do
|
29
|
+
(value <= 0.04045 ? APPLE : BANANA).call(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
RGB_TO_XYZ_TRANSFORM_D50 = [
|
33
|
+
[0.4360747, 0.3850649, 0.1430804],
|
34
|
+
[0.2225045, 0.7168786, 0.0606169],
|
35
|
+
[0.0139322, 0.0971045, 0.7141733],
|
36
|
+
]
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :rgb
|
41
|
+
|
42
|
+
def transformed_rgb
|
43
|
+
Hash[
|
44
|
+
[:red, :green, :blue].zip(
|
45
|
+
RGB_TO_XYZ_TRANSFORM_D50.map do |row|
|
46
|
+
%i[red green blue].map.with_index do |rgb, index|
|
47
|
+
row[index] * energetically_linear_rgb[rgb]
|
48
|
+
end.inject(:+)
|
49
|
+
end
|
50
|
+
)
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
def energetically_linear_rgb
|
55
|
+
Hash[
|
56
|
+
%i[red green blue].map do |color|
|
57
|
+
[color, FRUIT.call(rgb.public_send(color))]
|
58
|
+
end
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
(%i[x y z].zip(%i[red green blue])).each do |xyz, rgb|
|
63
|
+
define_method(xyz) do
|
64
|
+
transformed_rgb[rgb]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_calculator/clump/lab'
|
4
|
+
require 'color_calculator/clump/xyz'
|
5
|
+
require 'color_calculator/shared/composable'
|
6
|
+
|
7
|
+
module ColorCalculator
|
8
|
+
module Conversion
|
9
|
+
class XyzToLab
|
10
|
+
extend ColorCalculator::Composable
|
11
|
+
|
12
|
+
D50 = { x: 0.964220, y: 1.000000, z: 0.825210 }
|
13
|
+
EPSILON = 0.008856
|
14
|
+
KAPPA = 903.3
|
15
|
+
|
16
|
+
APPLE = -> (value) do
|
17
|
+
value ** Rational(1, 3)
|
18
|
+
end
|
19
|
+
|
20
|
+
BANANA = -> (value) do
|
21
|
+
((KAPPA * value) + 16) / 116
|
22
|
+
end
|
23
|
+
|
24
|
+
FRUIT = -> (value) do
|
25
|
+
(value > EPSILON ? APPLE : BANANA).call(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(xyz)
|
29
|
+
@xyz = xyz
|
30
|
+
end
|
31
|
+
|
32
|
+
def call
|
33
|
+
ColorCalculator::Clump::Lab.new(lightness, alpha, beta)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :xyz
|
39
|
+
|
40
|
+
def lightness
|
41
|
+
(116 * FRUIT.call(y_scaled)) - 16
|
42
|
+
end
|
43
|
+
|
44
|
+
def alpha
|
45
|
+
500 * (FRUIT.call(x_scaled) - FRUIT.call(y_scaled))
|
46
|
+
end
|
47
|
+
|
48
|
+
def beta
|
49
|
+
200 * (FRUIT.call(y_scaled) - FRUIT.call(z_scaled))
|
50
|
+
end
|
51
|
+
|
52
|
+
%i[x y z].each do |symbol|
|
53
|
+
define_method("#{symbol}_scaled") do
|
54
|
+
xyz.public_send(symbol) / D50.fetch(symbol)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: color_calculator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Seither
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-03 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: You can do color math now!
|
14
|
+
email:
|
15
|
+
- nathanseither@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- Gemfile
|
21
|
+
- Rakefile
|
22
|
+
- lib/color_calculator.rb
|
23
|
+
- lib/color_calculator/calculation.rb
|
24
|
+
- lib/color_calculator/calculation/delta_e_2000.rb
|
25
|
+
- lib/color_calculator/clump.rb
|
26
|
+
- lib/color_calculator/clump/abstract.rb
|
27
|
+
- lib/color_calculator/clump/lab.rb
|
28
|
+
- lib/color_calculator/clump/lch_ab.rb
|
29
|
+
- lib/color_calculator/clump/rgb.rb
|
30
|
+
- lib/color_calculator/clump/xyz.rb
|
31
|
+
- lib/color_calculator/conversion.rb
|
32
|
+
- lib/color_calculator/conversion/lab_to_lch_ab.rb
|
33
|
+
- lib/color_calculator/conversion/rgb_to_lch_ab.rb
|
34
|
+
- lib/color_calculator/conversion/rgb_to_xyz.rb
|
35
|
+
- lib/color_calculator/conversion/xyz_to_lab.rb
|
36
|
+
- lib/color_calculator/shared/composable.rb
|
37
|
+
homepage: https://github.com/Supernats/color_calculator
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 2.6.0
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubygems_version: 3.0.3
|
57
|
+
signing_key:
|
58
|
+
specification_version: 4
|
59
|
+
summary: Color math calculators and converters
|
60
|
+
test_files: []
|