hsluv 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hsluv.rb +274 -0
  3. metadata +13 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73a3f107ee6cb5c00f486efdf69f13175f00fb2d
4
- data.tar.gz: e9f833f7e232992a5538e5ae79d22ae9f63b51b3
3
+ metadata.gz: ef572dfa305acb1580e620aca808dc0a1a333a28
4
+ data.tar.gz: a8c9d21375d2d7f814403517a1a3375ff36c5315
5
5
  SHA512:
6
- metadata.gz: 49e37de82548f2ea7931779a6dc000798735dbaa20bf62872e23e97931a823ad7248674240755c0fc29073cf94cb6989cb373f66c789e8d2cf3c389facfab0f2
7
- data.tar.gz: b0dcf8343d2eb492bac3acc36551b6189b8fda24205498f974a4a285bdb6ac7039521176bb24540961e0f42be54abb2841e4863a4a5e22fff5e1450a3369fc76
6
+ metadata.gz: 7716cd233a9bdd8b98d5a6ddc0e4cd5060ec314d0f125eb2357caba3efe8d7deb9275325ff484ea1b1389357fd860b73fb611505fc8e7d5cfbbbaa0e87b25d6e
7
+ data.tar.gz: 7115ab48803d3770ed365dc7c6562463df91bdbcad7821a087ed2af20293d3f6b19f8ba89e50208f1cab64b3bd70ee262e1dc0db088e3a0e7b9ded66692d5a4b
@@ -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.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-01-30 00:00:00.000000000 Z
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.6.8
100
+ rubygems_version: 2.5.1
100
101
  signing_key:
101
102
  specification_version: 4
102
103
  summary: Human friendly alternative to HSL.