class ColorGenerator GOLDEN_RATIO_CONJUGATE = 0.618033988749895 attr_reader :mode, :hue, :saturation, :lightness, :value # Initializes a color generator. # # @param [Hash] opts optional arguments # @option opts [Float,Integer] :saturation saturation in the interval [0, 1] # @option opts [Float,Integer] :lightness lightness in the interval [0, 1], # sets the color representation to HSL # @option opts [Float,Integer] :value value in the interval [0, 1], sets the # color representation to HSV def initialize(opts = {}) @hue = rand @saturation = opts[:saturation].to_f if opts.has_key? :lightness @mode = :HSL @lightness = opts[:lightness].to_f else @mode = :HSV @value = opts[:value].to_f end end # Generates a random color. # # @return [String] an RGB hex triplet def create @hue = (hue + GOLDEN_RATIO_CONJUGATE) % 1 color = if hsl? self.class.rgb_from_hsl hue, saturation, lightness else self.class.rgb_from_hsv hue, saturation, value end '%02x%02x%02x' % color end # @return [Boolean] whether the color representation is HSL def hsl? mode == :HSL end # @return [Boolean] whether the color representation is HSV def hsv? mode == :HSV end # Converts a color from HSL to RGB. # # @param [Float] h hue in the interval [0, 1] # @param [Float] s saturation in the interval [0, 1] # @param [Float] l lightness in the interval [0, 1] # @return [Array] an RGB decimal triplet def self.rgb_from_hsl(h, s, l) c = (1 - (2 * l - 1).abs) * s m = l - 0.5 * c rgb_from_hsl_or_hsv h, c, m end # Converts a color from HSV to RGB. # # @param [Float] h hue in the interval [0, 1] # @param [Float] s saturation in the interval [0, 1] # @param [Float] v value in the interval [0, 1] # @return [Array] an RGB decimal triplet def self.rgb_from_hsv(h, s, v) c = v * s m = v - c rgb_from_hsl_or_hsv h, c, m end private # @param [Float] h hue in the interval [0, 1] # @param [Float] c chroma # @param [Float] m # @return [Array] an RGB decimal triplet # # @see http://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB def self.rgb_from_hsl_or_hsv(h, c, m) h_prime = h * 6 x = c * (1 - (h_prime % 2 - 1).abs) case h_prime.to_i when 0 # 0 <= H' < 1 [c, x, 0] when 1 # 1 <= H' < 2 [x, c, 0] when 2 # 2 <= H' < 3 [0, c, x] when 3 # 3 <= H' < 4 [0, x, c] when 4 # 4 <= H' < 5 [x, 0, c] else # 5 <= H' < 6 [c, 0, x] end.map{|value| ((value + m) * 255).round} end end