hsluv 1.0.0 → 1.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 +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.
|