husler 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.
@@ -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: []