module Hsluv
Converts between RGB, HSLUV
Constants
- EPSILON
- KAPPA
- M
- M_INV
- REF_U
- REF_V
- REF_X
- REF_Y
- REF_Z
Public Instance Methods
# File _plugins/gtn/hsluv.rb, line 219 def degrees_to_radians(degrees) degrees * Math::PI / 180.0 end
# File _plugins/gtn/hsluv.rb, line 275 def distance_from_pole(point) Math.sqrt((point[0]**2) + (point[1]**2)) end
# File _plugins/gtn/hsluv.rb, line 295 def dot_product(a, b) a.zip(b).map { |i, j| i * j }.inject(:+) end
# File _plugins/gtn/hsluv.rb, line 279 def f(t) t > EPSILON ? (116 * ((t / REF_Y)**(1.0 / 3.0))) - 16.0 : t / REF_Y * KAPPA end
# File _plugins/gtn/hsluv.rb, line 283 def f_inv(t) t > 8 ? REF_Y * (((t + 16.0) / 116.0)**3.0) : REF_Y * t / KAPPA end
# File _plugins/gtn/hsluv.rb, line 291 def from_linear(c) c <= 0.0031308 ? 12.92 * c : ((1.055 * (c**(1.0 / 2.4))) - 0.055) end
# File _plugins/gtn/hsluv.rb, line 246 def get_bounds(l) sub1 = ((l + 16.0)**3.0) / 1_560_896.0 sub2 = sub1 > EPSILON ? sub1 : l / KAPPA ret = [] M.each do |m1, m2, m3| [0, 1].each do |t| top1 = ((284_517.0 * m1) - (94_839.0 * m3)) * sub2 top2 = (((838_422.0 * m3) + (769_860.0 * m2) + (731_718.0 * m1)) * l * sub2) - (769_860.0 * t * l) bottom = (((632_260.0 * m3) - (126_452.0 * m2)) * sub2) + (126_452.0 * t) ret << [top1 / bottom, top2 / bottom] end end ret end
# File _plugins/gtn/hsluv.rb, line 66 def hex_to_hpluv(hex) rgb_to_hpluv(*hex_to_rgb(hex)) end
# File _plugins/gtn/hsluv.rb, line 62 def hex_to_hsluv(hex) rgb_to_hsluv(*hex_to_rgb(hex)) end
# File _plugins/gtn/hsluv.rb, line 98 def hex_to_rgb(hex) hex = hex.tr('#', '') [].tap { |arr| hex.chars.each_slice(2) { |block| arr << (block.join.to_i(16) / 255.0) } } end
# File _plugins/gtn/hsluv.rb, line 58 def hpluv_to_hex(h, s, l) rgb_to_hex(*hpluv_to_rgb(h, s, l)) end
# File _plugins/gtn/hsluv.rb, line 201 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
# File _plugins/gtn/hsluv.rb, line 78 def hpluv_to_rgb(h, s, l) lch_to_rgb(*hpluv_to_lch([h, s, l])) end
# File _plugins/gtn/hsluv.rb, line 54 def hsluv_to_hex(h, s, l) rgb_to_hex(*hsluv_to_rgb(h, s, l)) end
# File _plugins/gtn/hsluv.rb, line 189 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
# File _plugins/gtn/hsluv.rb, line 70 def hsluv_to_rgb(h, s, l) xyz_to_rgb(luv_to_xyz(lch_to_luv(hsluv_to_lch([h, s, l])))) end
# File _plugins/gtn/hsluv.rb, line 271 def intersect_line_line(line1, line2) (line1[1] - line2[1]) / (line2[0] - line1[0]) end
# File _plugins/gtn/hsluv.rb, line 144 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
# File _plugins/gtn/hsluv.rb, line 133 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
# File _plugins/gtn/hsluv.rb, line 179 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
# File _plugins/gtn/hsluv.rb, line 86 def lch_to_rgb(l, c, h) xyz_to_rgb(luv_to_xyz(lch_to_luv([l, c, h]))) end
# File _plugins/gtn/hsluv.rb, line 263 def length_of_ray_until_intersect(theta, line) m1, b1 = line length = b1 / (Math.sin(theta) - (m1 * Math.cos(theta))) return nil if length.negative? length end
# File _plugins/gtn/hsluv.rb, line 124 def luv_to_lch(arr) l, u, v = arr c = ((u**2) + (v**2))**(1 / 2.0) hrad = Math.atan2(v, u) h = radians_to_degrees(hrad) h += 360.0 if h < 0.0 [l, c, h] end
# File _plugins/gtn/hsluv.rb, line 163 def luv_to_xyz(arr) l, u, v = arr return [0.0, 0.0, 0.0] if l.zero? 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
# File _plugins/gtn/hsluv.rb, line 223 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
# File _plugins/gtn/hsluv.rb, line 235 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
# File _plugins/gtn/hsluv.rb, line 215 def radians_to_degrees(rad) rad * 180.0 / Math::PI end
# File _plugins/gtn/hsluv.rb, line 299 def rgb_prepare(arr) arr.map! do |ch| ch = ch.round(3) ch = [0, ch].max ch = [1, ch].min (ch * 255).round end end
# File _plugins/gtn/hsluv.rb, line 94 def rgb_to_hex(r, g, b) '#%02x%02x%02x' % rgb_prepare([r, g, b]) end
# File _plugins/gtn/hsluv.rb, line 82 def rgb_to_hpluv(r, g, b) lch_to_hpluv(rgb_to_lch(r, g, b)) end
# File _plugins/gtn/hsluv.rb, line 74 def rgb_to_hsluv(r, g, b) lch_to_hsluv(rgb_to_lch(r, g, b)) end
# File _plugins/gtn/hsluv.rb, line 90 def rgb_to_lch(r, g, b) luv_to_lch(xyz_to_luv(rgb_to_xyz([r, g, b]))) end
# File _plugins/gtn/hsluv.rb, line 105 def rgb_to_xyz(arr) rgbl = arr.map { |val| to_linear(val) } M_INV.map { |i| dot_product(i, rgbl) } end
# File _plugins/gtn/hsluv.rb, line 287 def to_linear(c) c > 0.04045 ? ((c + 0.055) / 1.055)**2.4 : c / 12.92 end
# File _plugins/gtn/hsluv.rb, line 110 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.zero? 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
# File _plugins/gtn/hsluv.rb, line 158 def xyz_to_rgb(arr) xyz = M.map { |i| dot_product(i, arr) } xyz.map { |i| from_linear(i) } end