Class: Colorist::Color

Inherits:
Object
  • Object
show all
Defined in:
lib/colorist/color.rb

Overview

Color is the general class for storing and manipulating a color with the Colorist gem. It provides methods to add, subtract, and calculate aspects of the color based on W3C and other standards.

Constant Summary collapse

CSS_COLOR_NAMES =
{  "maroon"  => 0x800000,
"red"     => 0xff0000,
"orange"  => 0xffa500,
"yellow"  => 0xffff00,
"olive"   => 0x808000,
"purple"  => 0x800080,
"fuchsia" => 0xff00ff,
"white"   => 0xffffff,
"lime"    => 0x00ff00,
"green"   => 0x008000,
"navy"    => 0x000080,
"blue"    => 0x0000ff,
"aqua"    => 0x00ffff,
"teal"    => 0x008080,
"black"   => 0x000000,
"silver"  => 0xc0c0c0,
"gray"    => 0x808080  }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(color = 0x000000, alpha = 1.0) ⇒ Color

Creates a new color with the hex color provided as a number (i.e. 0x112233)



27
28
29
30
31
32
33
# File 'lib/colorist/color.rb', line 27

def initialize(color = 0x000000, alpha = 1.0)
  string = "%.6x" % color
  @r = string[0..1].hex
  @g = string[2..3].hex
  @b = string[4..5].hex
  @a = alpha
end

Instance Attribute Details

#aObject

Returns the value of attribute a.



6
7
8
# File 'lib/colorist/color.rb', line 6

def a
  @a
end

#bObject

Returns the value of attribute b.



6
7
8
# File 'lib/colorist/color.rb', line 6

def b
  @b
end

#gObject

Returns the value of attribute g.



6
7
8
# File 'lib/colorist/color.rb', line 6

def g
  @g
end

#rObject

Returns the value of attribute r.



6
7
8
# File 'lib/colorist/color.rb', line 6

def r
  @r
end

Class Method Details

.from(some_entity) ⇒ Object

Create a new color from the provided object. Duplicates Color objects and attempts to call to_color on other objects. Will raise an ArgumentError if it is unable to coerce the color.



109
110
111
112
113
114
115
116
117
# File 'lib/colorist/color.rb', line 109

def self.from(some_entity)
  case some_entity
    when Colorist::Color
      some_entity.dup
    else
      raise ArgumentError, "#{some_entity.class.to_s} cannot be coerced into a color.", caller unless some_entity.respond_to?(:to_color)
      some_entity.to_color
  end
end

.from_hsv(hue, saturation, value) ⇒ Object

Initialize a colour based on HSV/HSB values. Hue should be between 0 and 360 (inclusive), while saturation and value should be from 0.0 to 1.0.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/colorist/color.rb', line 57

def self.from_hsv(hue, saturation, value)
  saturation = 1 if saturation > 1
  value = 1 if saturation > 1
  
  # Conversion formula taken from wikipedia
  
  f = (hue / 60.0) - (hue / 60).floor
  
  p = value * (1 - saturation)
  q = value * (1 - (saturation * f))
  t = value * (1 - (saturation * (1 - f)))
  
  r, g, b = case (hue / 60).floor % 6
            when 0 then [ value, t, p ]
            when 1 then [ q, value, p ]
            when 2 then [ p, value, t ]
            when 3 then [ p, q, value ]
            when 4 then [ t, p, value ]
            when 5 then [ value, p, q ]
            end
  
  from_rgb(r, g, b, :percent => true)
end

.from_hsva(hue, saturation, value, alpha) ⇒ Object



81
82
83
84
85
# File 'lib/colorist/color.rb', line 81

def self.from_hsva(hue, saturation, value, alpha)
  color = from_hsv(hue, saturation, value)
  color.a = alpha
  color
end

.from_rgb(r, g, b, options = {}) ⇒ Object

Initialize a color based on RGB values. By default, the values should be between 0 and 255. If you use the option :percent => true, the values should then be between 0.0 and 1.0.



38
39
40
41
42
43
44
45
46
47
# File 'lib/colorist/color.rb', line 38

def self.from_rgb(r, g, b, options = {})
  color = new
  # convert from 0.0 to 1.0 to 0 to 255 if the :percent option is used
  if options[:percent]
    color.r, color.g, color.b = (r * 255).round, (g * 255).round, (b * 255).round
  else
    color.r, color.g, color.b = r, g, b
  end
  color
end

.from_rgba(r, g, b, a, options = {}) ⇒ Object



49
50
51
52
53
# File 'lib/colorist/color.rb', line 49

def self.from_rgba(r, g, b, a, options = {})
  color = from_rgb(r, g, b, options)
  color.a = a
  color
end

.from_string(some_string) ⇒ Object

Converts a CSS hex string into a color. Works both with the full form (i.e. #ffffff) and the abbreviated form (#fff). Can also take any of the 16 named CSS colors.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/colorist/color.rb', line 90

def self.from_string(some_string)
  if matched = some_string.match(/\A#([0-9a-f]{3})\z/i)
    color = from_rgb(*matched[1].split(//).collect{|v| "#{v}#{v}".hex })
  elsif matched = some_string.match(/\A#([0-9a-f]{6})\z/i)
    color = new
    color.r = matched[1][0..1].hex
    color.g = matched[1][2..3].hex
    color.b = matched[1][4..5].hex
  elsif CSS_COLOR_NAMES.key?(some_string)
    color = new(CSS_COLOR_NAMES[some_string])
  else
    raise ArgumentError, "Must provide a valid CSS hex color or color name.", caller
  end
  color
end

Instance Method Details

#*(other) ⇒ Object

Multiply the individual RGB values of two colors together or against a Float. Colors divided in a way that is equivalent to each of the values being normalized to 0.0..1.0 prior to the operation

and normalized back to 0.0..255.0 after the operation.

You may also use an equivalent numeric or string color representation. The alpha value is kept from the original color (left-hand side).



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/colorist/color.rb', line 161

def *(other)
  color = self.dup
  
  if other.is_a? Float
    color.r *= other
    color.g *= other
    color.b *= other
  else
    other_color = self.class.from(other)
    color.r = color.r * other_color.r / 255.0
    color.g = color.g * other_color.g / 255.0
    color.b = color.b * other_color.b / 255.0
  end
  
  color
end

#+(other_color) ⇒ Object

Add the individual RGB values of two colors together. You may also use an equivalent numeric or string color representation. The alpha value is kept from the original color (left-hand side).

Examples:

gray = Colorist::Color.new(0x333333)
gray + "#300"   # => <Color #663333>
gray + 0x000000 # => <Color #333333>
white = "white".to_color
gray + white    # => <Color #ffffff>


135
136
137
138
139
140
141
142
# File 'lib/colorist/color.rb', line 135

def +(other_color)
  other_color = self.class.from(other_color)
  color = self.dup
  color.r += other_color.r
  color.g += other_color.g
  color.b += other_color.b
  color
end

#-(other_color) ⇒ Object

Subtract the individual RGB values of the two colors together. You may also use an equivalent numeric or string color representation. The alpha value is kept from the original color (left-hand side).



147
148
149
150
151
152
153
154
# File 'lib/colorist/color.rb', line 147

def -(other_color)
  other_color = self.class.from(other_color)
  color = self.dup
  color.r -= other_color.r
  color.g -= other_color.g
  color.b -= other_color.b
  color
end

#/(other) ⇒ Object

Divide the individual RGB values of the two colors together or against a Float. Colors divided in a way that is equivalent to each of the values being normalized to 0.0..1.0 prior to the operation

and normalized back to 0.0..255.0 after the operation.

You may also use an equivalent numeric or string color representation. The alpha value is kept from the original color (left-hand side).



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/colorist/color.rb', line 183

def /(other)
  color = self.dup
  
  if other.is_a? Float
    color.r /= other
    color.g /= other
    color.b /= other
  else
    other_color = self.class.from(other)
    color.r = color.r / other_color.r * 255.0
    color.g = color.g / other_color.g * 255.0
    color.b = color.b / other_color.b * 255.0
  end
  
  color
end

#<(other_color) ⇒ Object

Compares colors based on brightness.



207
208
209
210
# File 'lib/colorist/color.rb', line 207

def < (other_color)
  other_color = self.class.from(other_color)
  brightness < other_color.brightness
end

#<=>(other_color) ⇒ Object

Compares colors based on brightness.



201
202
203
204
# File 'lib/colorist/color.rb', line 201

def <=>(other_color)
  other_color = self.class.from(other_color)
  brightness <=> other_color.brightness
end

#==(other_color) ⇒ Object

Equal if the red, green, blue, and alpha values are identical.



219
220
221
222
# File 'lib/colorist/color.rb', line 219

def ==(other_color)
  other_color = self.class.from(other_color)
  other_color.r == self.r && other_color.g == self.g && other_color.b == self.b && other_color.a == self.a
end

#===(other_color) ⇒ Object

Equal if the brightnesses of the two colors are identical.



225
226
227
228
# File 'lib/colorist/color.rb', line 225

def ===(other_color)
  other_color = self.class.from(other_color)
  other_color.brightness == brightness
end

#>(other_color) ⇒ Object

Compares colors based on brightness.



213
214
215
216
# File 'lib/colorist/color.rb', line 213

def > (other_color)
  other_color = self.class.from(other_color)
  brightness > other_color.brightness
end

#adjust(opts = {}) ⇒ Object

Adjusts any of H, S, V values with relative values: opts[:h], opts[:s], opts[:v] and returns adjusted value.



363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/colorist/color.rb', line 363

def adjust(opts = {})
  unless [:h, :s, :v].any? { |part| opts.include? part }
    raise ArgumentError, "please specify at least one of :h, :s, or :v options"
  end
  
  h, s, v = *self.to_hsv
  
  h = (h + opts[:h]) % 360 if opts[:h]
  s = _clamp(s + opts[:s], 0..1)   if opts[:s]
  v = _clamp(v + opts[:v], 0..1)   if opts[:v]
  
  self.class.from_hsv(h, s, v)
end

#brightness(formula = :w3c) ⇒ Object

Returns the perceived brightness of the provided color on a scale of 0.0 to 1.0 based on the formula provided. The formulas available are:

  • :w3c - ((r * 299 + g * 587 + b * 114) / 1000 / 255

  • :standard - sqrt(0.241 * r^2 + 0.691 * g^2 + 0.068 * b^2) / 255



294
295
296
297
298
299
300
301
# File 'lib/colorist/color.rb', line 294

def brightness(formula = :w3c)
  case formula
    when :standard
      Math.sqrt(0.241 * r**2 + 0.691 * g**2 + 0.068 * b**2) / 255
    when :w3c
      ((r * 299 + g * 587 + b * 114) / 255000.0)
  end
end

#contrast_with(other_color, formula = :w3c) ⇒ Object

Contrast this color with another color using the provided formula. The available formulas are:

  • :w3c - (max(r1 r2) - min(r1 r2)) + (max(g1 g2) - min(g1 g2)) + (max(b1 b2) - min(b1 b2))



307
308
309
310
311
312
313
314
315
# File 'lib/colorist/color.rb', line 307

def contrast_with(other_color, formula=:w3c)
  other_color = self.class.from(other_color)
  case formula
    when :w3c
      (([self.r, other_color.r].max - [self.r, other_color.r].min) +
      ([self.g, other_color.g].max - [self.g, other_color.g].min) +
      ([self.b, other_color.b].max - [self.b, other_color.b].min)) / 765.0
  end
end

#dupObject

Create a duplicate of this color.



120
121
122
# File 'lib/colorist/color.rb', line 120

def dup
  self.class.from_rgba(@r, @g, @b, @a)
end

#gradient_to(color, steps = 10) ⇒ Object

Uses a naive formula to generate a gradient between this color and the given color. Returns the array of colors that make the gradient, including this color and the target color. By default will return 10 colors, but this can be changed by supplying an optional steps parameter.



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/colorist/color.rb', line 328

def gradient_to(color, steps = 10)
  color_to = self.class.from(color)
  red = color_to.r - r
  green = color_to.g - g
  blue = color_to.b - b
  
  result = (1..(steps - 3)).to_a.collect do |step|
    percentage = step.to_f / (steps - 1)
    self.class.from_rgb(r + (red * percentage), g + (green * percentage), b + (blue * percentage))
  end
  
  # Add first and last colors to result, avoiding uneccessary calculation and rounding errors
  
  result.unshift(self.dup)
  result.push(color.dup)
  result
end

#inspectObject



284
285
286
# File 'lib/colorist/color.rb', line 284

def inspect
  "#<Color #{to_s(:css_rgba)}>"
end

#invertObject Also known as: opposite

Returns the opposite of the current color.



318
319
320
# File 'lib/colorist/color.rb', line 318

def invert
  self.class.from_rgba(255 - r, 255 - g, 255 - b, a)
end

#text_color(threshold = 0.6, formula = :standard) ⇒ Object

Returns an appropriate text color (either black or white) based on the brightness of this color. The threshold specifies the brightness cutoff point.



357
358
359
# File 'lib/colorist/color.rb', line 357

def text_color(threshold = 0.6, formula = :standard)
  brightness(formula) > threshold ? self.class.new(0x000000) : self.class.new(0xffffff)
end

#to_grayscale(formula = :w3c) ⇒ Object

Converts the current color to grayscale using the brightness formula provided. See #brightness for a description of the available formulas.



349
350
351
352
# File 'lib/colorist/color.rb', line 349

def to_grayscale(formula = :w3c)
  b = brightness(formula)
  self.class.from_rgb(255 * b, 255 * b, 255 * b)
end

#to_hsvObject

Returns an array of the hue, saturation and value of the color. Hue will range from 0-359, hue and saturation will be between 0 and 1.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/colorist/color.rb', line 265

def to_hsv
  red, green, blue = *[r, g, b].collect {|x| x / 255.0}
  max = [red, green, blue].max
  min = [red, green, blue].min
  
  if min == max
    hue = 0
  elsif max == red
    hue = 60 * ((green - blue) / (max - min))
  elsif max == green
    hue = 60 * ((blue - red) / (max - min)) + 120
  elsif max == blue
    hue = 60 * ((red - green) / (max - min)) + 240
  end
  
  saturation = (max == 0) ? 0 : (max - min) / max
  [hue % 360, saturation, max]
end

#to_s(format = :css) ⇒ Object

Outputs a string representation of the color in the desired format. The available formats are:

  • :css - As a CSS hex string (i.e. #ffffff) (default)

  • :css_rgb - As a CSS RGB value string (i.e. rgb(255, 255, 255))

  • :css_rgba - As a CSS RGBA value string (i.e. rgb(255, 255, 255, 1.0))

  • :rgb - As an RGB triplet (i.e. 1.0, 1.0, 1.0)

  • :rgba - As an RGBA quadruplet (i.e. 1.0, 1.0, 1.0, 1.0)



247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/colorist/color.rb', line 247

def to_s(format=:css)
  case format
    when :css
      "#%.2x%.2x%.2x" % [r, g, b]
    when :css_rgb
      "rgb(%d, %d, %d)" % [r, g, b]
    when :css_rgba
      "rgba(%d, %d, %d, %.3f)" % [r, g, b, a]
    when :rgb
      "%.3f, %.3f, %.3f" % [r / 255, g / 255, b / 255]
    when :rgba
      "%.3f, %.3f, %.3f, %.3f" % [r / 255, g / 255, b / 255, a / 255]
  end
end

#with(opts = {}) ⇒ Object

Adjusts any of R, G, B, or A values with aboslute values: opts, opts, opts, opts and returns adjusted value.



379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/colorist/color.rb', line 379

def with(opts = {})
  unless [:r, :g, :b, :a].any? { |part| opts.include? part }
    raise ArgumentError, "please specify at least one of :r, :g, :b, or :a options"
  end
  
  color = self.dup
  
  color.r = opts[:r] if opts[:r]
  color.g = opts[:g] if opts[:g]
  color.b = opts[:b] if opts[:b]
  color.a = opts[:a] if opts[:a]
  
  color
end