husler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in husler.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright 2012 Bradley Schaefer
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,11 @@
1
+ # Husler
2
+
3
+ A ruby implementation of [HUSL, a human-friendly color space](http://boronine.com/husl/).
4
+
5
+ ## Usage
6
+
7
+ TODO
8
+
9
+ ## Credit
10
+
11
+ Algorithms translated from Alexei Boronine's canonical implementation at https://github.com/boronine/husl
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'husler/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "husler"
8
+ gem.version = Husler::VERSION
9
+ gem.authors = ["Bradley Schaefer"]
10
+ gem.email = ["bradley.schaefer@gmail.com"]
11
+ gem.description = %q{A ruby implementation of HUSL, a human-friendly color space}
12
+ gem.summary = %q{A ruby implementation of HUSL, a human-friendly color space}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,183 @@
1
+ require 'mathn'
2
+
3
+ require "husler/version"
4
+ require 'husler/constants'
5
+
6
+ # :nodoc:
7
+ module Husler
8
+ extend self
9
+
10
+ # Pass in HUSL values and get back RGB values, H ranges from 0 to 360, S and L from 0 to 100.
11
+ # RGB values will range from 0 to 1.
12
+ def husl_to_rgb(h, s, l)
13
+ xyz_rgb(luv_xyz(lch_luv(husl_lch([h, s, l]))))
14
+ end
15
+
16
+ # Pass in RGB values ranging from 0 to 1 and get back HUSL values.
17
+ # H ranges from 0 to 360, S and L from 0 to 100.
18
+ def rgb_to_husl(r, g, b)
19
+ lch_husl(luv_lch(xyz_luv(rgb_xyz([r, g, b]))))
20
+ end
21
+
22
+ private
23
+
24
+ def max_chroma(l, h)
25
+ hrad = (h / 360.0) * 2.0 * PI
26
+ sin_h = Math.sin(hrad)
27
+ cos_h = Math.cos(hrad)
28
+ sub1 = ((l + 16) ** 3) / 1560896.0
29
+ sub2 = sub1 > 0.008856 ? sub1 : (l / 903.3);
30
+
31
+ result = Float::INFINITY
32
+
33
+ M.each do |m1, m2, m3|
34
+ top = ((0.99915 * m1 + 1.05122 * m2 + 1.14460 * m3) * sub2);
35
+ rbottom = (0.86330 * m3 - 0.17266 * m2);
36
+ lbottom = (0.12949 * m3 - 0.38848 * m1);
37
+ bottom = (rbottom * sin_h + lbottom * cos_h) * sub2;
38
+
39
+ LIMITS.each do |t|
40
+ c = (l * (top - 1.05122 * t) / (bottom + 0.17266 * sin_h * t));
41
+ result = c if c > 0 && c < result
42
+ end
43
+ end
44
+
45
+ result
46
+ end
47
+
48
+ def dot_product l1, l2
49
+ sum = 0
50
+ for i in 0...l1.size
51
+ sum += l1[i] * l2[i]
52
+ end
53
+ sum
54
+ end
55
+
56
+ def f(t)
57
+ t > LAB_E ? (t ** ONE_THIRD) : (7.787 * t + 16 / 116.0)
58
+ end
59
+
60
+ def f_inv(t)
61
+ val = t ** 3
62
+ val > LAB_E ? val : ((116 * t - 16) / LAB_K)
63
+ end
64
+
65
+ def from_linear(c)
66
+ c <= 0.0031308 ? (12.92 * c) : (1.055 * (c ** (1 / 2.4)) - 0.055)
67
+ end
68
+
69
+ def to_linear(c)
70
+ a = 0.055
71
+
72
+ c > 0.04045 ? ( ((c + a) / (1 + a)) ** 2.4) : (c / 12.92)
73
+ end
74
+
75
+ def rgb_prepare(tuple)
76
+ tuple.map! do |v|
77
+ v = v.round(3)
78
+ v = [0, v].max
79
+ v = [1, v].min
80
+
81
+ (v * 255).round
82
+ end
83
+ end
84
+
85
+ def xyz_rgb(tuple)
86
+ tuple.map! do |v|
87
+ from_linear(dot_product(v, tuple))
88
+ end
89
+ end
90
+
91
+ def rgb_xyz(tuple)
92
+ rgbl = tuple.map { |v| to_linear(v) }
93
+
94
+ (0...3).each do |i|
95
+ tuple[i] = dot_product(M_INV[i], rgbl)
96
+ end
97
+ tuple
98
+ end
99
+
100
+ def xyz_luv(tuple)
101
+ x, y, z = *tuple
102
+
103
+ var_u = (4 * x) / (x + (15.0 * y) + (3 * z));
104
+ var_v = (9 * y) / (x + (15.0 * y) + (3 * z));
105
+
106
+ l = 116 * f(y / REF_Y) - 16;
107
+ u = 13 * l * (var_u - REF_U);
108
+ v = 13 * l * (var_v - REF_V);
109
+
110
+ tuple[0] = l
111
+ tuple[1] = u
112
+ tuple[2] = v
113
+
114
+ tuple
115
+ end
116
+
117
+ def luv_xyz(tuple)
118
+ l, u, v = *tuple
119
+
120
+ return tuple.map! { 0.0 } if l == 0
121
+
122
+ var_y = f_inv((l + 16) / 116.0)
123
+ var_u = u / (13.0 * l) + REF_U
124
+ var_v = v / (13.0 * l) + REF_V
125
+
126
+ y = var_y * REF_Y
127
+ x = 0 - (9 * y * var_u) / ((var_u - 4.0) * var_v - var_u * var_v)
128
+ z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3.0 * var_v)
129
+
130
+ tuple[0] = x
131
+ tuple[1] = y
132
+ tuple[2] = z
133
+
134
+ tuple
135
+ end
136
+
137
+ def luv_lch(tuple)
138
+ _, u, v = *tuple
139
+
140
+ c = ((u ** 2) + (v ** 2)) ** (1 / 2.0)
141
+ h_rad = Math.atan2(v, u)
142
+ h = h_rad * 360.0 / 2.0 / PI
143
+ h = h + 360 if h < 0
144
+
145
+ tuple[1] = c
146
+ tuple[2] = h
147
+
148
+ tuple
149
+ end
150
+
151
+ def lch_luv(tuple)
152
+ _, c, h = *tuple
153
+
154
+ h_rad = h / 360.0 * 2.0 * PI
155
+ u = Math.cos(h_rad) * c
156
+ v = Math.sin(h_rad) * c
157
+
158
+ tuple[1] = u
159
+ tuple[2] = v
160
+
161
+ tuple
162
+ end
163
+
164
+ def husl_lch(tuple)
165
+ h, s, l = *tuple
166
+
167
+ max = max_chroma(l, h)
168
+ c = max / 100.0 * s
169
+
170
+ tuple[0], tuple[1], tuple[2] = l, c, h
171
+ tuple
172
+ end
173
+
174
+ def lch_husl(tuple)
175
+ l, c, h = *tuple
176
+
177
+ max = max_chroma(l, h)
178
+ s = c / max * 100
179
+
180
+ tuple[0], tuple[1], tuple[2] = h, s, l
181
+ tuple
182
+ end
183
+ end
@@ -0,0 +1,30 @@
1
+ module Husler
2
+ PI = Math::PI
3
+ #PI = 3.1415926535897932384626433832795
4
+
5
+ ONE_THIRD = (1.0 / 3.0)
6
+
7
+ M = [
8
+ [3.2406, -1.5372, -0.4986],
9
+ [-0.9689, 1.8758, 0.0415],
10
+ [0.0557, -0.2040, 1.0570]
11
+ ]
12
+
13
+ M_INV = [
14
+ [0.4124, 0.3576, 0.1805],
15
+ [0.2126, 0.7152, 0.0722],
16
+ [0.0193, 0.1192, 0.9505]
17
+ ]
18
+
19
+ LIMITS = [0.0, 1.0]
20
+
21
+ REF_X = 0.95047
22
+ REF_Y = 1.00000
23
+ REF_Z = 1.08883
24
+
25
+ REF_U = 0.19784
26
+ REF_V = 0.46834
27
+
28
+ LAB_E = 0.008856
29
+ LAB_K = 903.3
30
+ end
@@ -0,0 +1,3 @@
1
+ module Husler
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: husler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bradley Schaefer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A ruby implementation of HUSL, a human-friendly color space
15
+ email:
16
+ - bradley.schaefer@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - husler.gemspec
27
+ - lib/husler.rb
28
+ - lib/husler/constants.rb
29
+ - lib/husler/version.rb
30
+ homepage: ''
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.24
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: A ruby implementation of HUSL, a human-friendly color space
54
+ test_files: []