Class: Color::RGB

Inherits:
Object
  • Object
show all
Includes:
Color
Defined in:
lib/color/rgb.rb,
lib/color.rb,
lib/color/rgb/colors.rb,
lib/color/rgb/metallic.rb

Overview

An RGB colour object.

Defined Under Namespace

Modules: Metallic

Constant Summary collapse

PDF_FORMAT_STR =

The format of a DeviceRGB colour for PDF. In color-tools 2.0 this will be removed from this package and added back as a modification by the PDF::Writer package.

"%.3f %.3f %.3f %s"

Constants included from Color

COLOR_EPSILON, COLOR_TOLERANCE, COLOR_VERSION, GreyScale

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Color

#==, coerce, const_missing, equivalent?, #name, #names, #names=, near?, near_one?, near_one_or_more?, near_zero?, near_zero_or_less?, new, normalize, normalize_byte, normalize_to_range, normalize_word

Constructor Details

#initialize(r = 0, g = 0, b = 0, radix = 255.0, &block) ⇒ RGB

Creates an RGB colour object from the standard range 0..255.

Color::RGB.new(32, 64, 128)
Color::RGB.new(0x20, 0x40, 0x80)


115
116
117
118
# File 'lib/color/rgb.rb', line 115

def initialize(r = 0, g = 0, b = 0, radix = 255.0, &block) # :yields self:
  @r, @g, @b = [ r, g, b ].map { |v| Color.normalize(v / radix) }
  block.call(self) if block
end

Class Method Details

.by_css(name_or_hex, &block) ⇒ Object

Return a colour as identified by the colour name, or by hex.



77
78
79
# File 'lib/color/rgb.rb', line 77

def by_css(name_or_hex, &block)
  by_name(name_or_hex) { by_hex(name_or_hex, &block) }
end

.by_hex(hex, &block) ⇒ Object

Find or create a colour by an HTML hex code. This differs from the #from_html method in that if the colour code matches a named colour, the existing colour will be returned.

Color::RGB.by_hex('ff0000').name # => 'red'
Color::RGB.by_hex('ff0001').name # => nil

If a block is provided, the value that is returned by the block will be returned instead of the exception caused by an error in providing a correct hex format.



61
62
63
64
65
66
67
68
69
# File 'lib/color/rgb.rb', line 61

def by_hex(hex, &block)
  __by_hex.fetch(html_hexify(hex)) { from_html(hex) }
rescue
  if block
    block.call
  else
    raise
  end
end

.by_name(name, &block) ⇒ Object

Return a colour as identified by the colour name.



72
73
74
# File 'lib/color/rgb.rb', line 72

def by_name(name, &block)
  __by_name.fetch(name.to_s.downcase, &block)
end

.extract_colors(text, mode = :both) ⇒ Object

Extract named or hex colours from the provided text.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/color/rgb.rb', line 82

def extract_colors(text, mode = :both)
  text  = text.downcase
  regex = case mode
          when :name
            Regexp.union(__by_name.keys)
          when :hex
            Regexp.union(__by_hex.keys)
          when :both
            Regexp.union(__by_hex.keys + __by_name.keys)
          end

  text.scan(regex).map { |match|
    case mode
    when :name
      by_name(match)
    when :hex
      by_hex(match)
    when :both
      by_css(match)
    end
  }
end

.from_fraction(r = 0.0, g = 0.0, b = 0.0, &block) ⇒ Object

Creates an RGB colour object from fractional values 0..1.

Color::RGB.from_fraction(.3, .2, .1)


21
22
23
# File 'lib/color/rgb.rb', line 21

def from_fraction(r = 0.0, g = 0.0, b = 0.0, &block)
  new(r, g, b, 1.0, &block)
end

.from_grayscale_fraction(l = 0.0, &block) ⇒ Object Also known as: from_greyscale_fraction

Creates an RGB colour object from a grayscale fractional value 0..1.



26
27
28
# File 'lib/color/rgb.rb', line 26

def from_grayscale_fraction(l = 0.0, &block)
  new(l, l, l, 1.0, &block)
end

.from_html(html_colour, &block) ⇒ Object

Creates an RGB colour object from an HTML colour descriptor (e.g., "fed" or "#cabbed;".

Color::RGB.from_html("fed")
Color::RGB.from_html("#fed")
Color::RGB.from_html("#cabbed")
Color::RGB.from_html("cabbed")


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

def from_html(html_colour, &block)
  # When we can move to 1.9+ only, this will be \h
  h = html_colour.scan(/[0-9a-f]/i)
  case h.size
  when 3
    new(*h.map { |v| (v * 2).to_i(16) }, &block)
  when 6
    new(*h.each_slice(2).map { |v| v.join.to_i(16) }, &block)
  else
    raise ArgumentError, "Not a supported HTML colour type."
  end
end

.from_percentage(r = 0, g = 0, b = 0, &block) ⇒ Object

Creates an RGB colour object from percentages 0..100.

Color::RGB.from_percentage(10, 20 30)


14
15
16
# File 'lib/color/rgb.rb', line 14

def from_percentage(r = 0, g = 0, b = 0, &block)
  new(r, g, b, 100.0, &block)
end

Instance Method Details

#+(other) ⇒ Object

Adds another colour to the current colour. The other colour will be converted to RGB before addition. This conversion depends upon a #to_rgb method on the other colour.

The addition is done using the RGB Accessor methods to ensure a valid colour in the result.



440
441
442
# File 'lib/color/rgb.rb', line 440

def +(other)
  self.class.from_fraction(r + other.r, g + other.g, b + other.b)
end

#-(other) ⇒ Object

Subtracts another colour to the current colour. The other colour will be converted to RGB before subtraction. This conversion depends upon a #to_rgb method on the other colour.

The subtraction is done using the RGB Accessor methods to ensure a valid colour in the result.



450
451
452
# File 'lib/color/rgb.rb', line 450

def -(other)
  self + (-other)
end

#-@Object

Numerically negate the color. This results in a color that is only usable for subtraction.



471
472
473
474
475
476
477
# File 'lib/color/rgb.rb', line 471

def -@
  rgb = self.dup
  rgb.instance_variable_set(:@r, -rgb.r)
  rgb.instance_variable_set(:@g, -rgb.g)
  rgb.instance_variable_set(:@b, -rgb.b)
  rgb
end

#adjust_brightness(percent) ⇒ Object

Returns a new colour with the brightness adjusted by the specified percentage. Negative percentages will darken the colour; positive percentages will brighten the colour.

Color::RGB::DarkBlue.adjust_brightness(10)
Color::RGB::DarkBlue.adjust_brightness(-10)


320
321
322
323
324
325
# File 'lib/color/rgb.rb', line 320

def adjust_brightness(percent)
  percent = normalize_percent(percent)
  hsl      = to_hsl
  hsl.l   *= percent
  hsl.to_rgb
end

#adjust_hue(percent) ⇒ Object

Returns a new colour with the hue adjusted by the specified percentage. Negative percentages will reduce the hue; positive percentages will increase the hue.

Color::RGB::DarkBlue.adjust_hue(10)
Color::RGB::DarkBlue.adjust_hue(-10)


346
347
348
349
350
351
# File 'lib/color/rgb.rb', line 346

def adjust_hue(percent)
  percent = normalize_percent(percent)
  hsl      = to_hsl
  hsl.h   *= percent
  hsl.to_rgb
end

#adjust_saturation(percent) ⇒ Object

Returns a new colour with the saturation adjusted by the specified percentage. Negative percentages will reduce the saturation; positive percentages will increase the saturation.

Color::RGB::DarkBlue.adjust_saturation(10)
Color::RGB::DarkBlue.adjust_saturation(-10)


333
334
335
336
337
338
# File 'lib/color/rgb.rb', line 333

def adjust_saturation(percent)
  percent = normalize_percent(percent)
  hsl      = to_hsl
  hsl.s   *= percent
  hsl.to_rgb
end

#bObject

Returns the blue component of the colour as a fraction in the range 0.0 .. 1.0.



417
418
419
# File 'lib/color/rgb.rb', line 417

def b
  @b
end

#b=(bb) ⇒ Object

Sets the blue component of the colour as a fraction in the range 0.0 .. 1.0.



430
431
432
# File 'lib/color/rgb.rb', line 430

def b=(bb)
  @b = Color.normalize(bb)
end

#blueObject

Returns the blue component of the colour in the normal 0 .. 255 range.



408
409
410
# File 'lib/color/rgb.rb', line 408

def blue
  @b * 255.0
end

#blue=(bb) ⇒ Object

Sets the blue component of the colour in the normal 0 .. 255 range.



421
422
423
# File 'lib/color/rgb.rb', line 421

def blue=(bb)
  @b = Color.normalize(bb / 255.0)
end

#blue_pObject

Returns the blue component of the colour as a percentage.



412
413
414
# File 'lib/color/rgb.rb', line 412

def blue_p
  @b * 100.0
end

#blue_p=(bb) ⇒ Object

Sets the blue component of the colour as a percentage.



425
426
427
# File 'lib/color/rgb.rb', line 425

def blue_p=(bb)
  @b = Color.normalize(bb / 100.0)
end

#brightnessObject

Returns the brightness value for a colour, a number between 0..1. Based on the Y value of YIQ encoding, representing luminosity, or perceived brightness.

This may be modified in a future version of color-tools to use the luminosity value of HSL.



305
306
307
# File 'lib/color/rgb.rb', line 305

def brightness
  to_yiq.y
end

#coerce(other) ⇒ Object

Coerces the other Color object into RGB.



107
108
109
# File 'lib/color/rgb.rb', line 107

def coerce(other)
  other.to_rgb
end

#css_hslObject

Present the colour as an HSL HTML/CSS colour string (e.g., “hsl(180, 25%, 35%)”). Note that this will perform a #to_hsl operation using the default conversion formula.



168
169
170
# File 'lib/color/rgb.rb', line 168

def css_hsl
  to_hsl.css_hsl
end

#css_hslaObject

Present the colour as an HSLA (with alpha) HTML/CSS colour string (e.g., “hsla(180, 25%, 35%, 1)”). Note that this will perform a #to_hsl operation using the default conversion formula.



175
176
177
# File 'lib/color/rgb.rb', line 175

def css_hsla
  to_hsl.css_hsla
end

#css_rgbObject

Present the colour as an RGB HTML/CSS colour string (e.g., “rgb(0%, 50%, 100%)”). Note that this will perform a #to_rgb operation using the default conversion formula.



154
155
156
# File 'lib/color/rgb.rb', line 154

def css_rgb
  "rgb(%3.2f%%, %3.2f%%, %3.2f%%)" % [ red_p, green_p, blue_p ]
end

#css_rgbaObject

Present the colour as an RGBA (with alpha) HTML/CSS colour string (e.g., “rgb(0%, 50%, 100%, 1)”). Note that this will perform a #to_rgb operation using the default conversion formula.



161
162
163
# File 'lib/color/rgb.rb', line 161

def css_rgba
  "rgba(%3.2f%%, %3.2f%%, %3.2f%%, %3.2f)" % [ red_p, green_p, blue_p, 1 ]
end

#darken_by(percent) ⇒ Object

Mix the RGB hue with Black so that the RGB hue is the specified percentage of the resulting colour. Strictly speaking, this isn’t a darken_by operation.



282
283
284
# File 'lib/color/rgb.rb', line 282

def darken_by(percent)
  mix_with(Black, percent)
end

#gObject

Returns the green component of the colour as a fraction in the range 0.0 .. 1.0.



390
391
392
# File 'lib/color/rgb.rb', line 390

def g
  @g
end

#g=(gg) ⇒ Object

Sets the green component of the colour as a fraction in the range 0.0 .. 1.0.



403
404
405
# File 'lib/color/rgb.rb', line 403

def g=(gg)
  @g = Color.normalize(gg)
end

#greenObject

Returns the green component of the colour in the normal 0 .. 255 range.



381
382
383
# File 'lib/color/rgb.rb', line 381

def green
  @g * 255.0
end

#green=(gg) ⇒ Object

Sets the green component of the colour in the normal 0 .. 255 range.



394
395
396
# File 'lib/color/rgb.rb', line 394

def green=(gg)
  @g = Color.normalize(gg / 255.0)
end

#green_pObject

Returns the green component of the colour as a percentage.



385
386
387
# File 'lib/color/rgb.rb', line 385

def green_p
  @g * 100.0
end

#green_p=(gg) ⇒ Object

Sets the green component of the colour as a percentage.



398
399
400
# File 'lib/color/rgb.rb', line 398

def green_p=(gg)
  @g = Color.normalize(gg / 100.0)
end

#hexObject

Present the colour as an RGB hex triplet.



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/color/rgb.rb', line 133

def hex
  r = (@r * 255).round
  r = 255 if r > 255

  g = (@g * 255).round
  g = 255 if g > 255

  b = (@b * 255).round
  b = 255 if b > 255

  "%02x%02x%02x" % [ r, g, b ]
end

#htmlObject

Present the colour as an HTML/CSS colour string.



147
148
149
# File 'lib/color/rgb.rb', line 147

def html
  "##{hex}"
end

#inspectObject



461
462
463
# File 'lib/color/rgb.rb', line 461

def inspect
  "RGB [#{html}]"
end

#lighten_by(percent) ⇒ Object

Mix the RGB hue with White so that the RGB hue is the specified percentage of the resulting colour. Strictly speaking, this isn’t a darken_by operation.



275
276
277
# File 'lib/color/rgb.rb', line 275

def lighten_by(percent)
  mix_with(White, percent)
end

#max_rgb_as_grayscaleObject Also known as: max_rgb_as_greyscale

Retrieve the maxmum RGB value from the current colour as a GrayScale colour



456
457
458
# File 'lib/color/rgb.rb', line 456

def max_rgb_as_grayscale
    Color::GrayScale.from_fraction([@r, @g, @b].max)
end

#mix_with(mask, opacity) ⇒ Object

Mix the mask colour (which must be an RGB object) with the current colour at the stated opacity percentage (0..100).



288
289
290
291
292
293
294
295
296
297
# File 'lib/color/rgb.rb', line 288

def mix_with(mask, opacity)
  opacity /= 100.0
  rgb = self.dup

  rgb.r = (@r * opacity) + (mask.r * (1 - opacity))
  rgb.g = (@g * opacity) + (mask.g * (1 - opacity))
  rgb.b = (@b * opacity) + (mask.b * (1 - opacity))

  rgb
end

#pdf_fillObject

Present the colour as a DeviceRGB fill colour string for PDF. This will be removed from the default package in color-tools 2.0.



122
123
124
# File 'lib/color/rgb.rb', line 122

def pdf_fill
  PDF_FORMAT_STR % [ @r, @g, @b, "rg" ]
end

#pdf_strokeObject

Present the colour as a DeviceRGB stroke colour string for PDF. This will be removed from the default package in color-tools 2.0.



128
129
130
# File 'lib/color/rgb.rb', line 128

def pdf_stroke
  PDF_FORMAT_STR % [ @r, @g, @b, "RG" ]
end

#rObject

Returns the red component of the colour as a fraction in the range 0.0 .. 1.0.



363
364
365
# File 'lib/color/rgb.rb', line 363

def r
  @r
end

#r=(rr) ⇒ Object

Sets the red component of the colour as a fraction in the range 0.0 .. 1.0.



376
377
378
# File 'lib/color/rgb.rb', line 376

def r=(rr)
  @r = Color.normalize(rr)
end

#redObject

Returns the red component of the colour in the normal 0 .. 255 range.



354
355
356
# File 'lib/color/rgb.rb', line 354

def red
  @r * 255.0
end

#red=(rr) ⇒ Object

Sets the red component of the colour in the normal 0 .. 255 range.



367
368
369
# File 'lib/color/rgb.rb', line 367

def red=(rr)
  @r = Color.normalize(rr / 255.0)
end

#red_pObject

Returns the red component of the colour as a percentage.



358
359
360
# File 'lib/color/rgb.rb', line 358

def red_p
  @r * 100.0
end

#red_p=(rr) ⇒ Object

Sets the red component of the colour as a percentage.



371
372
373
# File 'lib/color/rgb.rb', line 371

def red_p=(rr)
  @r = Color.normalize(rr / 100.0)
end

#to_aObject



465
466
467
# File 'lib/color/rgb.rb', line 465

def to_a
  [ r, g, b ]
end

#to_cmykObject

Converts the RGB colour to CMYK. Most colour experts strongly suggest that this is not a good idea (some even suggesting that it’s a very bad idea). CMYK represents additive percentages of inks on white paper, whereas RGB represents mixed colour intensities on a black screen.

However, the colour conversion can be done. The basic method is multi-step:

  1. Convert the R, G, and B components to C, M, and Y components.

    c = 1.0 - r
    m = 1.0 - g
    y = 1.0 - b
    
  2. Compute the minimum amount of black (K) required to smooth the colour in inks.

    k = min(c, m, y)
    
  3. Perform undercolour removal on the C, M, and Y components of the colours because less of each colour is needed for each bit of black. Also, regenerate the black (K) based on the undercolour removal so that the colour is more accurately represented in ink.

    c = min(1.0, max(0.0, c - UCR(k)))
    m = min(1.0, max(0.0, m - UCR(k)))
    y = min(1.0, max(0.0, y - UCR(k)))
    k = min(1.0, max(0.0, BG(k)))
    

The undercolour removal function and the black generation functions return a value based on the brightness of the RGB colour.



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/color/rgb.rb', line 205

def to_cmyk
  c = 1.0 - @r.to_f
  m = 1.0 - @g.to_f
  y = 1.0 - @b.to_f

  k = [c, m, y].min
  k = k - (k * brightness)

  c = [1.0, [0.0, c - k].max].min
  m = [1.0, [0.0, m - k].max].min
  y = [1.0, [0.0, y - k].max].min
  k = [1.0, [0.0, k].max].min

  Color::CMYK.from_fraction(c, m, y, k)
end

#to_grayscaleObject Also known as: to_greyscale

Convert to grayscale.



309
310
311
# File 'lib/color/rgb.rb', line 309

def to_grayscale
  Color::GrayScale.from_fraction(to_hsl.l)
end

#to_hslObject

Returns the HSL colour encoding of the RGB value. The conversions here are based on forumlas from www.easyrgb.com/math.php and elsewhere.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/color/rgb.rb', line 236

def to_hsl
  min   = [ @r, @g, @b ].min
  max   = [ @r, @g, @b ].max
  delta = (max - min).to_f

  lum   = (max + min) / 2.0

  if Color.near_zero?(delta) # close to 0.0, so it's a grey
    hue = 0
    sat = 0
  else
    if Color.near_zero_or_less?(lum - 0.5)
      sat = delta / (max + min).to_f
    else
      sat = delta / (2 - max - min).to_f
    end

    # This is based on the conversion algorithm from
    # http://en.wikipedia.org/wiki/HSV_color_space#Conversion_from_RGB_to_HSL_or_HSV
    # Contributed by Adam Johnson
    sixth = 1 / 6.0
    if @r == max # Color.near_zero_or_less?(@r - max)
      hue = (sixth * ((@g - @b) / delta))
      hue += 1.0 if @g < @b
    elsif @g == max # Color.near_zero_or_less(@g - max)
      hue = (sixth * ((@b - @r) / delta)) + (1.0 / 3.0)
    elsif @b == max # Color.near_zero_or_less?(@b - max)
      hue = (sixth * ((@r - @g) / delta)) + (2.0 / 3.0)
    end

    hue += 1 if hue < 0
    hue -= 1 if hue > 1
  end
  Color::HSL.from_fraction(hue, sat, lum)
end

#to_rgb(ignored = nil) ⇒ Object



221
222
223
# File 'lib/color/rgb.rb', line 221

def to_rgb(ignored = nil)
  self
end

#to_yiqObject

Returns the YIQ (NTSC) colour encoding of the RGB value.



226
227
228
229
230
231
# File 'lib/color/rgb.rb', line 226

def to_yiq
  y = (@r * 0.299) + (@g *  0.587) + (@b *  0.114)
  i = (@r * 0.596) + (@g * -0.275) + (@b * -0.321)
  q = (@r * 0.212) + (@g * -0.523) + (@b *  0.311)
  Color::YIQ.from_fraction(y, i, q)
end