hsluv 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hsluv.rb +274 -0
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef572dfa305acb1580e620aca808dc0a1a333a28
|
4
|
+
data.tar.gz: a8c9d21375d2d7f814403517a1a3375ff36c5315
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7716cd233a9bdd8b98d5a6ddc0e4cd5060ec314d0f125eb2357caba3efe8d7deb9275325ff484ea1b1389357fd860b73fb611505fc8e7d5cfbbbaa0e87b25d6e
|
7
|
+
data.tar.gz: 7115ab48803d3770ed365dc7c6562463df91bdbcad7821a087ed2af20293d3f6b19f8ba89e50208f1cab64b3bd70ee262e1dc0db088e3a0e7b9ded66692d5a4b
|
data/lib/hsluv.rb
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
module Hsluv
|
2
|
+
extend self
|
3
|
+
|
4
|
+
M = [
|
5
|
+
[3.240969941904521, -1.537383177570093, -0.498610760293],
|
6
|
+
[-0.96924363628087, 1.87596750150772, 0.041555057407175],
|
7
|
+
[0.055630079696993, -0.20397695888897, 1.056971514242878],
|
8
|
+
]
|
9
|
+
|
10
|
+
M_INV = [
|
11
|
+
[0.41239079926595, 0.35758433938387, 0.18048078840183],
|
12
|
+
[0.21263900587151, 0.71516867876775, 0.072192315360733],
|
13
|
+
[0.019330818715591, 0.11919477979462, 0.95053215224966],
|
14
|
+
]
|
15
|
+
|
16
|
+
REF_X = 0.95045592705167
|
17
|
+
REF_Y = 1.0
|
18
|
+
REF_Z = 1.089057750759878
|
19
|
+
REF_U = 0.19783000664283
|
20
|
+
REF_V = 0.46831999493879
|
21
|
+
KAPPA = 903.2962962
|
22
|
+
EPSILON = 0.0088564516
|
23
|
+
|
24
|
+
###
|
25
|
+
|
26
|
+
def hsluv_to_hex (h, s, l)
|
27
|
+
rgb_to_hex(*hsluv_to_rgb(h, s, l))
|
28
|
+
end
|
29
|
+
|
30
|
+
def hpluv_to_hex (h, s, l)
|
31
|
+
rgb_to_hex(*hpluv_to_rgb(h, s, l))
|
32
|
+
end
|
33
|
+
|
34
|
+
def hex_to_hsluv (hex)
|
35
|
+
rgb_to_hsluv(*hex_to_rgb(hex))
|
36
|
+
end
|
37
|
+
|
38
|
+
def hex_to_hpluv (hex)
|
39
|
+
rgb_to_hpluv(*hex_to_rgb(hex))
|
40
|
+
end
|
41
|
+
|
42
|
+
def hsluv_to_rgb (h, s, l)
|
43
|
+
xyz_to_rgb(luv_to_xyz(lch_to_luv(hsluv_to_lch([h, s, l]))))
|
44
|
+
end
|
45
|
+
|
46
|
+
def rgb_to_hsluv (r, g, b)
|
47
|
+
lch_to_hsluv(rgb_to_lch(r, g, b))
|
48
|
+
end
|
49
|
+
|
50
|
+
def hpluv_to_rgb (h, s, l)
|
51
|
+
lch_to_rgb(*hpluv_to_lch([h, s, l]))
|
52
|
+
end
|
53
|
+
|
54
|
+
def rgb_to_hpluv (r, g, b)
|
55
|
+
lch_to_hpluv(rgb_to_lch(r, g, b))
|
56
|
+
end
|
57
|
+
|
58
|
+
def lch_to_rgb (l, c, h)
|
59
|
+
xyz_to_rgb(luv_to_xyz(lch_to_luv([l, c, h])))
|
60
|
+
end
|
61
|
+
|
62
|
+
def rgb_to_lch (r, g, b)
|
63
|
+
luv_to_lch(xyz_to_luv(rgb_to_xyz([r, g, b])))
|
64
|
+
end
|
65
|
+
|
66
|
+
def rgb_to_hex (r, g, b)
|
67
|
+
'#%02x%02x%02x' % rgb_prepare([r, g, b])
|
68
|
+
end
|
69
|
+
|
70
|
+
def hex_to_rgb (hex)
|
71
|
+
hex = hex.tr('#', '')
|
72
|
+
[].tap { |arr| hex.split('').each_slice(2) { |block| arr << block.join.to_i(16) / 255.0 } }
|
73
|
+
end
|
74
|
+
|
75
|
+
###
|
76
|
+
|
77
|
+
def rgb_to_xyz (arr)
|
78
|
+
rgbl = arr.map { |val| to_linear(val) }
|
79
|
+
M_INV.map { |i| dot_product(i, rgbl) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def xyz_to_luv (arr)
|
83
|
+
x, y, z = arr
|
84
|
+
l = f(y)
|
85
|
+
|
86
|
+
return [0.0, 0.0, 0.0] if [x, y, z, 0.0].uniq.length == 1 || l == 0.0
|
87
|
+
|
88
|
+
var_u = (4.0 * x) / (x + (15.0 * y) + (3.0 * z))
|
89
|
+
var_v = (9.0 * y) / (x + (15.0 * y) + (3.0 * z))
|
90
|
+
u = 13.0 * l * (var_u - REF_U)
|
91
|
+
v = 13.0 * l * (var_v - REF_V)
|
92
|
+
|
93
|
+
[l, u, v]
|
94
|
+
end
|
95
|
+
|
96
|
+
def luv_to_lch (arr)
|
97
|
+
l, u, v = arr
|
98
|
+
c = ((u ** 2) + (v ** 2)) ** (1 / 2.0)
|
99
|
+
hrad = Math.atan2(v, u)
|
100
|
+
h = radians_to_degrees(hrad)
|
101
|
+
h += 360.0 if h < 0.0
|
102
|
+
[l, c, h]
|
103
|
+
end
|
104
|
+
|
105
|
+
def lch_to_hsluv (arr)
|
106
|
+
l, c, h = arr
|
107
|
+
return [h, 0.0, 100.0] if l > 99.9999999
|
108
|
+
return [h, 0.0, 0.0] if l < 0.00000001
|
109
|
+
|
110
|
+
mx = max_chroma_for(l, h)
|
111
|
+
s = c / mx * 100.0
|
112
|
+
|
113
|
+
[h, s, l]
|
114
|
+
end
|
115
|
+
|
116
|
+
def lch_to_hpluv (arr)
|
117
|
+
l, c, h = arr
|
118
|
+
|
119
|
+
return [h, 0.0, 100.0] if l > 99.9999999
|
120
|
+
return [h, 0.0, 0.0] if l < 0.00000001
|
121
|
+
|
122
|
+
mx = max_safe_chroma_for(l)
|
123
|
+
s = c / mx * 100.0
|
124
|
+
|
125
|
+
[h, s, l]
|
126
|
+
end
|
127
|
+
|
128
|
+
###
|
129
|
+
|
130
|
+
def xyz_to_rgb (arr)
|
131
|
+
xyz = M.map { |i| dot_product(i, arr) }
|
132
|
+
xyz.map { |i| from_linear(i) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def luv_to_xyz (arr)
|
136
|
+
l, u, v = arr
|
137
|
+
|
138
|
+
return [0.0, 0.0, 0.0] if l == 0
|
139
|
+
|
140
|
+
var_y = f_inv(l)
|
141
|
+
var_u = u / (13.0 * l) + REF_U
|
142
|
+
var_v = v / (13.0 * l) + REF_V
|
143
|
+
|
144
|
+
|
145
|
+
y = var_y * REF_Y
|
146
|
+
x = 0.0 - (9.0 * y * var_u) / ((var_u - 4.0) * var_v - var_u * var_v)
|
147
|
+
z = (9.0 * y - (15.0 * var_v * y) - (var_v * x)) / (3.0 * var_v)
|
148
|
+
|
149
|
+
[x, y, z]
|
150
|
+
end
|
151
|
+
|
152
|
+
def lch_to_luv (arr)
|
153
|
+
l, c, h = arr
|
154
|
+
|
155
|
+
hrad = degrees_to_radians(h)
|
156
|
+
u = Math.cos(hrad) * c
|
157
|
+
v = Math.sin(hrad) * c
|
158
|
+
|
159
|
+
[l, u, v]
|
160
|
+
end
|
161
|
+
|
162
|
+
def hsluv_to_lch (arr)
|
163
|
+
h, s, l = arr
|
164
|
+
|
165
|
+
return [100, 0.0, h] if l > 99.9999999
|
166
|
+
return [0.0, 0.0, h] if l < 0.00000001
|
167
|
+
|
168
|
+
mx = max_chroma_for(l, h)
|
169
|
+
c = mx / 100.0 * s
|
170
|
+
|
171
|
+
[l, c, h]
|
172
|
+
end
|
173
|
+
|
174
|
+
def hpluv_to_lch (arr)
|
175
|
+
h, s, l = arr
|
176
|
+
|
177
|
+
return [100, 0.0, h] if l > 99.9999999
|
178
|
+
return [0.0, 0.0, h] if l < 0.00000001
|
179
|
+
|
180
|
+
mx = max_safe_chroma_for(l)
|
181
|
+
c = mx / 100.0 * s
|
182
|
+
|
183
|
+
[l, c, h]
|
184
|
+
end
|
185
|
+
|
186
|
+
###
|
187
|
+
|
188
|
+
def radians_to_degrees (rad)
|
189
|
+
rad * 180.0 / Math::PI
|
190
|
+
end
|
191
|
+
|
192
|
+
def degrees_to_radians (degrees)
|
193
|
+
degrees * Math::PI / 180.0
|
194
|
+
end
|
195
|
+
|
196
|
+
def max_chroma_for (l, h)
|
197
|
+
hrad = h / 360.0 * Math::PI * 2.0
|
198
|
+
lengths = []
|
199
|
+
|
200
|
+
get_bounds(l).each do |line|
|
201
|
+
l = length_of_ray_until_intersect(hrad, line)
|
202
|
+
lengths << l if l
|
203
|
+
end
|
204
|
+
|
205
|
+
lengths.min
|
206
|
+
end
|
207
|
+
|
208
|
+
def max_safe_chroma_for (l)
|
209
|
+
lengths = []
|
210
|
+
|
211
|
+
get_bounds(l).each do |m1, b1|
|
212
|
+
x = intersect_line_line([m1, b1], [-1.0 / m1, 0.0])
|
213
|
+
lengths << distance_from_pole([x, b1 + x * m1])
|
214
|
+
end
|
215
|
+
|
216
|
+
lengths.min
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_bounds (l)
|
220
|
+
sub1 = ((l + 16.0) ** 3.0) / 1560896.0
|
221
|
+
sub2 = sub1 > EPSILON ? sub1 : l / KAPPA
|
222
|
+
ret = []
|
223
|
+
|
224
|
+
M.each do |m1, m2, m3|
|
225
|
+
[0, 1].each do |t|
|
226
|
+
top1 = (284517.0 * m1 - 94839.0 * m3) * sub2
|
227
|
+
top2 = (838422.0 * m3 + 769860.0 * m2 + 731718.0 * m1) * l * sub2 - 769860.0 * t * l
|
228
|
+
bottom = (632260.0 * m3 - 126452.0 * m2) * sub2 + 126452.0 * t
|
229
|
+
ret << [top1 / bottom, top2 / bottom]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
ret
|
234
|
+
end
|
235
|
+
|
236
|
+
def length_of_ray_until_intersect (theta, line)
|
237
|
+
m1, b1 = line
|
238
|
+
length = b1 / (Math.sin(theta) - m1 * Math.cos(theta))
|
239
|
+
return nil if length < 0
|
240
|
+
length
|
241
|
+
end
|
242
|
+
|
243
|
+
def intersect_line_line (line1, line2)
|
244
|
+
(line1[1] - line2[1]) / (line2[0] - line1[0])
|
245
|
+
end
|
246
|
+
|
247
|
+
def distance_from_pole (point)
|
248
|
+
Math.sqrt(point[0] ** 2 + point[1] ** 2)
|
249
|
+
end
|
250
|
+
|
251
|
+
def f (t)
|
252
|
+
t > EPSILON ? 116 * ((t / REF_Y) ** (1.0 / 3.0)) - 16.0 : t / REF_Y * KAPPA
|
253
|
+
end
|
254
|
+
|
255
|
+
def f_inv (t)
|
256
|
+
t > 8 ? REF_Y * ((t + 16.0) / 116.0) ** 3.0 : REF_Y * t / KAPPA
|
257
|
+
end
|
258
|
+
|
259
|
+
def to_linear (c)
|
260
|
+
c > 0.04045 ? ((c + 0.055) / 1.055) ** 2.4 : c / 12.92
|
261
|
+
end
|
262
|
+
|
263
|
+
def from_linear (c)
|
264
|
+
c <= 0.0031308 ? 12.92 * c : (1.055 * (c ** (1.0 / 2.4)) - 0.055)
|
265
|
+
end
|
266
|
+
|
267
|
+
def dot_product (a, b)
|
268
|
+
a.zip(b).map { |i, j| i * j }.inject(:+)
|
269
|
+
end
|
270
|
+
|
271
|
+
def rgb_prepare (arr)
|
272
|
+
arr.map! { |ch| ch = ch.round(3); ch = [0, ch].max; ch = [1, ch].min; (ch * 255).round }
|
273
|
+
end
|
274
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hsluv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radu-Bogdan Croitoru
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-03-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -43,30 +43,30 @@ dependencies:
|
|
43
43
|
name: pry
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
48
|
+
version: '0.0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - "
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
55
|
+
version: '0.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - "
|
60
|
+
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
62
|
+
version: '0.0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - "
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
69
|
+
version: '0.0'
|
70
70
|
description: HSLuv is implemented as a set of functions to convert colors between
|
71
71
|
RGB, HSLuv and HPLuv.
|
72
72
|
email:
|
@@ -75,7 +75,8 @@ email:
|
|
75
75
|
executables: []
|
76
76
|
extensions: []
|
77
77
|
extra_rdoc_files: []
|
78
|
-
files:
|
78
|
+
files:
|
79
|
+
- lib/hsluv.rb
|
79
80
|
homepage: https://github.com/hsluv/hsluv-ruby
|
80
81
|
licenses:
|
81
82
|
- MIT
|
@@ -96,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
97
|
version: '0'
|
97
98
|
requirements: []
|
98
99
|
rubyforge_project:
|
99
|
-
rubygems_version: 2.
|
100
|
+
rubygems_version: 2.5.1
|
100
101
|
signing_key:
|
101
102
|
specification_version: 4
|
102
103
|
summary: Human friendly alternative to HSL.
|