class Tco::Colour

Attributes

lab[R]
rgb[R]

Public Class Methods

new(rgb, lab=nil) click to toggle source
# File lib/tco/palette.rb, line 40
def initialize(rgb, lab=nil)
  @rgb = rgb
  @lab = lab ? lab : rgb_to_lab(rgb)
  @hsl = nil
  @yiq = nil
end

Public Instance Methods

-(other) click to toggle source
# File lib/tco/palette.rb, line 47
def -(other)
  delta_e_2000 @lab, other.lab
end
<=>(other) click to toggle source
# File lib/tco/palette.rb, line 51
def <=>(other)
  self.hsl[0] <=> other.hsl[0]
end
hsl() click to toggle source
# File lib/tco/palette.rb, line 69
def hsl
  if @hsl == nil
    @hsl = rgb_to_hsl @rgb
  else
    @hsl
  end
end
to_s() click to toggle source
# File lib/tco/palette.rb, line 55
def to_s
  values = @rgb.map do |v|
    v = v.to_i.to_s 16

    case v.length
    when 0 then "00"
    when 1 then "0" + v
    when 2 then v
    end
  end

  "#" + values.join("")
end
yiq() click to toggle source
# File lib/tco/palette.rb, line 77
def yiq
  if @yiq == nil
    @yiq = rgb_to_yiq @rgb
  else
    @yiq
  end
end

Private Instance Methods

CieLab2Hue(a, b) click to toggle source
# File lib/tco/palette.rb, line 179
def CieLab2Hue(a, b)
  bias = 0
  return 0 if (a >= 0 && b == 0)
  return 180 if (a <  0 && b == 0)
  return 90 if (a == 0 && b > 0)
  return 270 if (a == 0 && b < 0)

  bias = case
  when a > 0 && b > 0 then 0
  when a < 0 then 180
  when a > 0 && b < 0 then 360
  end

  rad_to_deg(Math.atan(b / a)) + bias
end
deg_to_rad(v) click to toggle source
# File lib/tco/palette.rb, line 175
def deg_to_rad(v)
  (v * Math::PI) / 180
end
delta_e_2000(lab1, lab2) click to toggle source
# File lib/tco/palette.rb, line 195
def delta_e_2000(lab1, lab2)
  l1, a1, b1 = lab1
  l2, a2, b2 = lab2
  kl, kc, kh = [1, 1, 1]

  xC1 = Math.sqrt(a1**2 + b1**2)
  xC2 = Math.sqrt(a2**2 + b2**2)
  xCX = (xC1 + xC2) / 2
  xGX = 0.5 * (1 - Math.sqrt(xCX**7 / (xCX**7 + 25**7)))
  xNN = (1 + xGX) * a1
  xC1 = Math.sqrt(xNN**2 + b1**2)
  xH1 = CieLab2Hue(xNN, b1)
  xNN = (1 + xGX) * a2
  xC2 = Math.sqrt(xNN**2 + b2**2)
  xH2 = CieLab2Hue(xNN, b2)
  xDL = l2 - l1
  xDC = xC2 - xC1
  if (xC1 * xC2) == 0
    xDH = 0
  else
    xNN = (xH2 - xH1).round(12)
    if xNN.abs <= 180
      xDH = xH2 - xH1
    else
      if xNN > 180
        xDH = xH2 - xH1 - 360
      else
        xDH = xH2 - xH1 + 360
      end
    end
  end
  xDH = 2 * Math.sqrt(xC1 * xC2) * Math.sin(deg_to_rad(xDH / 2.0))
  xLX = (l1 + l2) / 2.0
  xCY = (xC1 + xC2) / 2.0
  if xC1 * xC2 == 0
    xHX = xH1 + xH2
  else
    xNN = (xH1 - xH2).round(12).abs
    if xNN > 180
      if xH2 + xH1 < 360
        xHX = xH1 + xH2 + 360
      else
        xHX = xH1 + xH2 - 360
      end
    else
      xHX = xH1 + xH2
    end
    xHX /= 2.0
  end
  xTX = 1 - 0.17 * Math.cos(deg_to_rad(xHX - 30)) + 0.24 *
                   Math.cos(deg_to_rad(2 * xHX)) + 0.32 *
                   Math.cos(deg_to_rad(3 * xHX + 6)) - 0.20 *
                   Math.cos(deg_to_rad(4 * xHX - 63 ))
  xPH = 30 * Math.exp(-((xHX - 275) / 25.0) * ((xHX  - 275) / 25.0))
  xRC = 2 * Math.sqrt(xCY**7 / (xCY**7 + 25**7))
  xSL = 1 + ((0.015 * ((xLX - 50) * (xLX - 50))) /
        Math.sqrt(20 + ((xLX - 50) * (xLX - 50))))
  xSC = 1 + 0.045 * xCY
  xSH = 1 + 0.015 * xCY * xTX
  xRT = -Math.sin(deg_to_rad(2 * xPH)) * xRC
  xDL = xDL / (kl * xSL)
  xDC = xDC / (kc * xSC)
  xDH = xDH / (kh * xSH)

  Math.sqrt(xDL**2 + xDC**2 + xDH**2 + xRT * xDC * xDH)
end
rad_to_deg(v) click to toggle source
# File lib/tco/palette.rb, line 171
def rad_to_deg(v)
  (v * 180) / Math::PI
end
rgb_to_hsl(rgb_val) click to toggle source
# File lib/tco/palette.rb, line 126
def rgb_to_hsl(rgb_val)
  r, g, b = rgb_val.map { |v| v / 255.0 }

  min, max = [r, g, b].minmax
  delta = max - min

  lig = (max + min) / 2.0

  if delta == 0
     hue = 0
     sat = 0
  else
     sat = if lig < 0.5
             delta / (0.0 + (max + min))
           else
             delta / (2.0 - max - min)
           end

     delta_r = (((max - r) / 6.0 ) + (delta / 2.0)) / delta
     delta_g = (((max - g) / 6.0 ) + (delta / 2.0)) / delta
     delta_b = (((max - b) / 6.0 ) + (delta / 2.0)) / delta

     hue = case max
           when r then delta_b - delta_g
           when g then (1.0/3) + delta_r - delta_b
           when b then (2.0/3) + delta_g - delta_r
           end

     hue += 1 if hue < 0
     hue -= 1 if hue > 1
  end

  [360 * hue, 100 * sat, 100 * lig]
end
rgb_to_lab(rgb_val) click to toggle source
# File lib/tco/palette.rb, line 122
def rgb_to_lab(rgb_val)
  xyz_to_lab rgb_to_xyz rgb_val
end
rgb_to_xyz(colour) click to toggle source

source: www.easyrgb.com/index.php?X=MATH&H=02#text2

# File lib/tco/palette.rb, line 88
def rgb_to_xyz(colour)
  r, g, b = colour.map do |v|
      v /= 255.0
      if v > 0.04045
          v = ((v + 0.055 ) / 1.055)**2.4
      else
          v = v / 12.92
      end
      v *= 100
  end

  #Observer = 2°, Illuminant = D65
  x = r * 0.4124 + g * 0.3576 + b * 0.1805
  y = r * 0.2126 + g * 0.7152 + b * 0.0722
  z = r * 0.0193 + g * 0.1192 + b * 0.9505

  return [x, y, z]
end
rgb_to_yiq(rgb_val) click to toggle source
# File lib/tco/palette.rb, line 161
def rgb_to_yiq(rgb_val)
  r, g, b = rgb_val

  y = 0.299*r + 0.587*g + 0.114*b
  i = 0.569*r - 0.275*g - 0.321*b
  q = 0.212*r - 0.523*g + 0.311*b

  [y, i, q]
end
xyz_to_lab(colour) click to toggle source
# File lib/tco/palette.rb, line 107
def xyz_to_lab(colour)
  f = lambda { |t|
    return t**(1.0/3) if t > (6.0 / 29)**3
    return (1.0 / 3) * ((29.0 / 6)**2) * t + (4.0 / 29)
  }

  x, y, z = colour
  xn, yn, zn = rgb_to_xyz([255, 255, 255])
  l = 116 * f.call(y/yn) - 16
  a = 500 * (f.call(x/xn) - f.call(y/yn))
  b = 200 * (f.call(y/yn) - f.call(z/zn))

  return [l, a, b]
end