Module: Hsluv
Constant Summary collapse
- M =
[ [3.240969941904521, -1.537383177570093, -0.498610760293], [-0.96924363628087, 1.87596750150772, 0.041555057407175], [0.055630079696993, -0.20397695888897, 1.056971514242878], ]
- M_INV =
[ [0.41239079926595, 0.35758433938387, 0.18048078840183], [0.21263900587151, 0.71516867876775, 0.072192315360733], [0.019330818715591, 0.11919477979462, 0.95053215224966], ]
- REF_X =
0.95045592705167
- REF_Y =
1.0
- REF_Z =
1.089057750759878
- REF_U =
0.19783000664283
- REF_V =
0.46831999493879
- KAPPA =
903.2962962
- EPSILON =
0.0088564516
Instance Method Summary collapse
- #degrees_to_radians(degrees) ⇒ Object
- #distance_from_pole(point) ⇒ Object
- #dot_product(a, b) ⇒ Object
- #f(t) ⇒ Object
- #f_inv(t) ⇒ Object
- #from_linear(c) ⇒ Object
- #get_bounds(l) ⇒ Object
- #hex_to_hpluv(hex) ⇒ Object
- #hex_to_hsluv(hex) ⇒ Object
- #hex_to_rgb(hex) ⇒ Object
- #hpluv_to_hex(h, s, l) ⇒ Object
- #hpluv_to_lch(arr) ⇒ Object
- #hpluv_to_rgb(h, s, l) ⇒ Object
- #hsluv_to_hex(h, s, l) ⇒ Object
- #hsluv_to_lch(arr) ⇒ Object
- #hsluv_to_rgb(h, s, l) ⇒ Object
- #intersect_line_line(line1, line2) ⇒ Object
- #lch_to_hpluv(arr) ⇒ Object
- #lch_to_hsluv(arr) ⇒ Object
- #lch_to_luv(arr) ⇒ Object
- #lch_to_rgb(l, c, h) ⇒ Object
- #length_of_ray_until_intersect(theta, line) ⇒ Object
- #luv_to_lch(arr) ⇒ Object
- #luv_to_xyz(arr) ⇒ Object
- #max_chroma_for(l, h) ⇒ Object
- #max_safe_chroma_for(l) ⇒ Object
- #radians_to_degrees(rad) ⇒ Object
- #rgb_prepare(arr) ⇒ Object
- #rgb_to_hex(r, g, b) ⇒ Object
- #rgb_to_hpluv(r, g, b) ⇒ Object
- #rgb_to_hsluv(r, g, b) ⇒ Object
- #rgb_to_lch(r, g, b) ⇒ Object
- #rgb_to_xyz(arr) ⇒ Object
- #to_linear(c) ⇒ Object
- #xyz_to_luv(arr) ⇒ Object
- #xyz_to_rgb(arr) ⇒ Object
Instance Method Details
#degrees_to_radians(degrees) ⇒ Object
200 201 202 |
# File 'lib/hsluv.rb', line 200 def degrees_to_radians (degrees) degrees * Math::PI / 180.0 end |
#distance_from_pole(point) ⇒ Object
255 256 257 |
# File 'lib/hsluv.rb', line 255 def distance_from_pole (point) Math.sqrt(point[0] ** 2 + point[1] ** 2) end |
#dot_product(a, b) ⇒ Object
275 276 277 |
# File 'lib/hsluv.rb', line 275 def dot_product (a, b) a.zip(b).map { |i, j| i * j }.inject(:+) end |
#f(t) ⇒ Object
259 260 261 |
# File 'lib/hsluv.rb', line 259 def f (t) t > EPSILON ? 116 * ((t / REF_Y) ** (1.0 / 3.0)) - 16.0 : t / REF_Y * KAPPA end |
#f_inv(t) ⇒ Object
263 264 265 |
# File 'lib/hsluv.rb', line 263 def f_inv (t) t > 8 ? REF_Y * ((t + 16.0) / 116.0) ** 3.0 : REF_Y * t / KAPPA end |
#from_linear(c) ⇒ Object
271 272 273 |
# File 'lib/hsluv.rb', line 271 def from_linear (c) c <= 0.0031308 ? 12.92 * c : (1.055 * (c ** (1.0 / 2.4)) - 0.055) end |
#get_bounds(l) ⇒ Object
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/hsluv.rb', line 227 def get_bounds (l) sub1 = ((l + 16.0) ** 3.0) / 1560896.0 sub2 = sub1 > EPSILON ? sub1 : l / KAPPA ret = [] M.each do |m1, m2, m3| [0, 1].each do |t| top1 = (284517.0 * m1 - 94839.0 * m3) * sub2 top2 = (838422.0 * m3 + 769860.0 * m2 + 731718.0 * m1) * l * sub2 - 769860.0 * t * l bottom = (632260.0 * m3 - 126452.0 * m2) * sub2 + 126452.0 * t ret << [top1 / bottom, top2 / bottom] end end ret end |
#hex_to_hpluv(hex) ⇒ Object
38 39 40 |
# File 'lib/hsluv.rb', line 38 def hex_to_hpluv (hex) rgb_to_hpluv(*hex_to_rgb(hex)) end |
#hex_to_hsluv(hex) ⇒ Object
34 35 36 |
# File 'lib/hsluv.rb', line 34 def hex_to_hsluv (hex) rgb_to_hsluv(*hex_to_rgb(hex)) end |
#hex_to_rgb(hex) ⇒ Object
70 71 72 73 |
# File 'lib/hsluv.rb', line 70 def hex_to_rgb (hex) hex = hex.tr('#', '') [].tap { |arr| hex.split('').each_slice(2) { |block| arr << block.join.to_i(16) / 255.0 } } end |
#hpluv_to_hex(h, s, l) ⇒ Object
30 31 32 |
# File 'lib/hsluv.rb', line 30 def hpluv_to_hex (h, s, l) rgb_to_hex(*hpluv_to_rgb(h, s, l)) end |
#hpluv_to_lch(arr) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/hsluv.rb', line 182 def hpluv_to_lch (arr) h, s, l = arr return [100, 0.0, h] if l > 99.9999999 return [0.0, 0.0, h] if l < 0.00000001 mx = max_safe_chroma_for(l) c = mx / 100.0 * s [l, c, h] end |
#hpluv_to_rgb(h, s, l) ⇒ Object
50 51 52 |
# File 'lib/hsluv.rb', line 50 def hpluv_to_rgb (h, s, l) lch_to_rgb(*hpluv_to_lch([h, s, l])) end |
#hsluv_to_hex(h, s, l) ⇒ Object
26 27 28 |
# File 'lib/hsluv.rb', line 26 def hsluv_to_hex (h, s, l) rgb_to_hex(*hsluv_to_rgb(h, s, l)) end |
#hsluv_to_lch(arr) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/hsluv.rb', line 170 def hsluv_to_lch (arr) h, s, l = arr return [100, 0.0, h] if l > 99.9999999 return [0.0, 0.0, h] if l < 0.00000001 mx = max_chroma_for(l, h) c = mx / 100.0 * s [l, c, h] end |
#hsluv_to_rgb(h, s, l) ⇒ Object
42 43 44 |
# File 'lib/hsluv.rb', line 42 def hsluv_to_rgb (h, s, l) xyz_to_rgb(luv_to_xyz(lch_to_luv(hsluv_to_lch([h, s, l])))) end |
#intersect_line_line(line1, line2) ⇒ Object
251 252 253 |
# File 'lib/hsluv.rb', line 251 def intersect_line_line (line1, line2) (line1[1] - line2[1]) / (line2[0] - line1[0]) end |
#lch_to_hpluv(arr) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/hsluv.rb', line 124 def lch_to_hpluv (arr) l, c, h = arr return [h, 0.0, 100.0] if l > 99.9999999 return [h, 0.0, 0.0] if l < 0.00000001 mx = max_safe_chroma_for(l) s = c / mx * 100.0 [h, s, l] end |
#lch_to_hsluv(arr) ⇒ Object
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/hsluv.rb', line 113 def lch_to_hsluv (arr) l, c, h = arr return [h, 0.0, 100.0] if l > 99.9999999 return [h, 0.0, 0.0] if l < 0.00000001 mx = max_chroma_for(l, h) s = c / mx * 100.0 [h, s, l] end |
#lch_to_luv(arr) ⇒ Object
160 161 162 163 164 165 166 167 168 |
# File 'lib/hsluv.rb', line 160 def lch_to_luv (arr) l, c, h = arr hrad = degrees_to_radians(h) u = Math.cos(hrad) * c v = Math.sin(hrad) * c [l, u, v] end |
#lch_to_rgb(l, c, h) ⇒ Object
58 59 60 |
# File 'lib/hsluv.rb', line 58 def lch_to_rgb (l, c, h) xyz_to_rgb(luv_to_xyz(lch_to_luv([l, c, h]))) end |
#length_of_ray_until_intersect(theta, line) ⇒ Object
244 245 246 247 248 249 |
# File 'lib/hsluv.rb', line 244 def length_of_ray_until_intersect (theta, line) m1, b1 = line length = b1 / (Math.sin(theta) - m1 * Math.cos(theta)) return nil if length < 0 length end |
#luv_to_lch(arr) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/hsluv.rb', line 96 def luv_to_lch (arr) l, u, v = arr c = Math.sqrt(u * u + v * v) h = if c < 0.00000001 0.0 else hrad = Math.atan2(v, u) h = hrad * 180.0 / Math::PI h += 360.0 if h < 0.0 h end [l, c, h] end |
#luv_to_xyz(arr) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/hsluv.rb', line 143 def luv_to_xyz (arr) l, u, v = arr return [0.0, 0.0, 0.0] if l == 0 var_y = f_inv(l) var_u = u / (13.0 * l) + REF_U var_v = v / (13.0 * l) + REF_V y = var_y * REF_Y x = 0.0 - (9.0 * y * var_u) / ((var_u - 4.0) * var_v - var_u * var_v) z = (9.0 * y - (15.0 * var_v * y) - (var_v * x)) / (3.0 * var_v) [x, y, z] end |
#max_chroma_for(l, h) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/hsluv.rb', line 204 def max_chroma_for (l, h) hrad = h / 360.0 * Math::PI * 2.0 lengths = [] get_bounds(l).each do |line| l = length_of_ray_until_intersect(hrad, line) lengths << l if l end lengths.min end |
#max_safe_chroma_for(l) ⇒ Object
216 217 218 219 220 221 222 223 224 225 |
# File 'lib/hsluv.rb', line 216 def max_safe_chroma_for (l) lengths = [] get_bounds(l).each do |m1, b1| x = intersect_line_line([m1, b1], [-1.0 / m1, 0.0]) lengths << distance_from_pole([x, b1 + x * m1]) end lengths.min end |
#radians_to_degrees(rad) ⇒ Object
196 197 198 |
# File 'lib/hsluv.rb', line 196 def radians_to_degrees (rad) rad * 180.0 / Math::PI end |
#rgb_prepare(arr) ⇒ Object
279 280 281 |
# File 'lib/hsluv.rb', line 279 def rgb_prepare (arr) arr.map! { |ch| ch = ch.round(3); ch = [0, ch].max; ch = [1, ch].min; (ch * 255).round } end |
#rgb_to_hex(r, g, b) ⇒ Object
66 67 68 |
# File 'lib/hsluv.rb', line 66 def rgb_to_hex (r, g, b) '#%02x%02x%02x' % rgb_prepare([r, g, b]) end |
#rgb_to_hpluv(r, g, b) ⇒ Object
54 55 56 |
# File 'lib/hsluv.rb', line 54 def rgb_to_hpluv (r, g, b) lch_to_hpluv(rgb_to_lch(r, g, b)) end |
#rgb_to_hsluv(r, g, b) ⇒ Object
46 47 48 |
# File 'lib/hsluv.rb', line 46 def rgb_to_hsluv (r, g, b) lch_to_hsluv(rgb_to_lch(r, g, b)) end |
#rgb_to_lch(r, g, b) ⇒ Object
62 63 64 |
# File 'lib/hsluv.rb', line 62 def rgb_to_lch (r, g, b) luv_to_lch(xyz_to_luv(rgb_to_xyz([r, g, b]))) end |
#rgb_to_xyz(arr) ⇒ Object
77 78 79 80 |
# File 'lib/hsluv.rb', line 77 def rgb_to_xyz (arr) rgbl = arr.map { |val| to_linear(val) } M_INV.map { |i| dot_product(i, rgbl) } end |
#to_linear(c) ⇒ Object
267 268 269 |
# File 'lib/hsluv.rb', line 267 def to_linear (c) c > 0.04045 ? ((c + 0.055) / 1.055) ** 2.4 : c / 12.92 end |
#xyz_to_luv(arr) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/hsluv.rb', line 82 def xyz_to_luv (arr) x, y, z = arr l = f(y) return [0.0, 0.0, 0.0] if [x, y, z, 0.0].uniq.length == 1 || l == 0.0 var_u = (4.0 * x) / (x + (15.0 * y) + (3.0 * z)) var_v = (9.0 * y) / (x + (15.0 * y) + (3.0 * z)) u = 13.0 * l * (var_u - REF_U) v = 13.0 * l * (var_v - REF_V) [l, u, v] end |
#xyz_to_rgb(arr) ⇒ Object
138 139 140 141 |
# File 'lib/hsluv.rb', line 138 def xyz_to_rgb (arr) xyz = M.map { |i| dot_product(i, arr) } xyz.map { |i| from_linear(i) } end |