Module: Inker::Color::Tools

Included in:
Inker::Color
Defined in:
lib/inker/color/tools.rb

Overview

Tools module implements a set of methods useful for color parsing and for getting useful info about color.

Constant Summary collapse

HEX_REGEX =

Regular expression for HEX colors matching

/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.freeze
RGB_REGEX =

Regular expression for RGB colors matching

/^rgb\((\d+,){2}\d+\)$/.freeze
RGBA_REGEX =

Regular expression for RGBA colors matching

/^rgba\((\d+,){3}\d+(.\d+)?\)$/.freeze
HSL_REGEX =

Regular expression for HSL colors matching

/^hsl\((\d+)(,\d+%|,\d+(.\d+)){2}\)$/.freeze
HSLA_REGEX =

Regular expression for HSLA colors matching

/^hsla\((\d+)(,\d+%|,\d+(.\d+)){2},\d+(.\d+)?\)$/.freeze

Instance Method Summary collapse

Instance Method Details

#brightness(red, green, blue) ⇒ Integer

Calculate the brightness of a color.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Integer)

    a value between 0-255 which indicates the brightness of the color



30
31
32
# File 'lib/inker/color/tools.rb', line 30

def brightness(red, green, blue)
  Math.sqrt(0.299 * red**2 + 0.587 * green**2 + 0.114 * blue**2).round
end

#contrast_ratio(color1, color2) ⇒ Float

Calculates the contrast ratio between two colors.

Parameters:

Returns:

  • (Float)

    the contrast ratio between the two colors [1.0-21.0].



303
304
305
# File 'lib/inker/color/tools.rb', line 303

def contrast_ratio(color1, color2)
  color1.to_color.contrast_ratio(color2)
end

#from_custom_string(custom_string, positions: [0, 29, 14, 30, 28, 31]) ⇒ Inker::Color

Use MD5 digest of the string to get hex values from specified positions (by default [0, 29, 14, 30, 28, 31]) in order to obtain a color in HEX format which represents the specified string.

Returns:

  • (Inker::Color)

    a Inker::Color object which represents the color associated to input string



244
245
246
247
# File 'lib/inker/color/tools.rb', line 244

def from_custom_string(custom_string, positions: [0, 29, 14, 30, 28, 31])
  digest = Digest::MD5.hexdigest(custom_string.to_s)
  Inker.color("##{positions.map { |p| digest[p] }.join}")
end

#from_hsl(hue, saturation, lightness) ⇒ Inker::Color

A helper for Inker::Color generation from HSL components.

Parameters:

  • hue (Integer)

    the value of HUE component [0-360]

  • saturation (Float)

    the value of saturation component [0.0-1.0]

  • lightness (Float)

    the value of lightness component [0.0-1.0]

Returns:

  • (Inker::Color)

    a Inker::Color generated from passed HSL values



220
221
222
# File 'lib/inker/color/tools.rb', line 220

def from_hsl(hue, saturation, lightness)
  Inker.color("hsl(#{hue}, #{saturation}, #{lightness})")
end

#from_hsla(hue, saturation, lightness, alpha) ⇒ Inker::Color

A helper for Inker::Color generation from HSLA components.

Parameters:

  • hue (Integer)

    the value of HUE component [0-360]

  • saturation (Float)

    the value of saturation component [0.0-1.0]

  • lightness (Float)

    the value of lightness component [0.0-1.0]

  • alpha (Float)

    the value of alpha component [0.0-1.1]

Returns:

  • (Inker::Color)

    a Inker::Color generated from passed HSLA values



232
233
234
# File 'lib/inker/color/tools.rb', line 232

def from_hsla(hue, saturation, lightness, alpha)
  Inker.color("hsla(#{hue}, #{saturation}, #{lightness}, #{alpha})")
end

#from_rgb(red, green, blue) ⇒ Inker::Color

A helper for Inker::Color generation from RGB components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Inker::Color)

    a Inker::Color generated from passed RGB values



197
198
199
# File 'lib/inker/color/tools.rb', line 197

def from_rgb(red, green, blue)
  Inker.color("rgb(#{red}, #{green}, #{blue})")
end

#from_rgba(red, green, blue, alpha) ⇒ Inker::Color

A helper for Inker::Color generation from RGBA components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

  • alpha (Float)

    the value of alpha component [0.0-1.1]

Returns:

  • (Inker::Color)

    a Inker::Color generated from passed RGBA values



209
210
211
# File 'lib/inker/color/tools.rb', line 209

def from_rgba(red, green, blue, alpha)
  Inker.color("rgba(#{red}, #{green}, #{blue}, #{alpha})")
end

#hex?(color_str) ⇒ Boolean Also known as: is_hex?

Returns a Boolean which indicates if color is in HEX format

Parameters:

  • color_str (String)

    a color string

Returns:

  • (Boolean)

    true when color is in HEX format



127
128
129
# File 'lib/inker/color/tools.rb', line 127

def hex?(color_str)
  !!(color_str.to_s.downcase.strip =~ HEX_REGEX)
end

#hsl?(color_str) ⇒ Boolean Also known as: is_hsl?

Returns a Boolean which indicates if color is in HSL format

Parameters:

  • color_str (String)

    a color string

Returns:

  • (Boolean)

    true when color is in HSL format



160
161
162
# File 'lib/inker/color/tools.rb', line 160

def hsl?(color_str)
  !!(color_str.to_s.downcase.gsub(/\s+/, '') =~ HSL_REGEX)
end

#hsl_to_rgb(hue, saturation, lightness) ⇒ Hash

Get RGB values from a color in HSL format.

Parameters:

  • hue (Integer)

    the value of HUE component [0-360]

  • saturation (Float)

    the saturation of the color [0.0-1.0]

  • lightness (Float)

    the lightness of the color [0.0-1.0]

Returns:

  • (Hash)

    a Hash which contains the values of RGB components



111
112
113
114
115
116
117
118
119
120
# File 'lib/inker/color/tools.rb', line 111

def hsl_to_rgb(hue, saturation, lightness)
  c, x, m = hue_convert_params(hue, saturation, lightness)
  weights = hsl_hue_weights(hue, c, x)

  {
    red: ((weights[0] + m) * 255).round,
    green: ((weights[1] + m) * 255).round,
    blue: ((weights[2] + m) * 255).round
  }
end

#hsla?(color_str) ⇒ Boolean Also known as: is_hsla?

Returns a Boolean which indicates if color is in HSLA format

Parameters:

  • color_str (String)

    a color string

Returns:

  • (Boolean)

    true when color is in HSLA format



171
172
173
# File 'lib/inker/color/tools.rb', line 171

def hsla?(color_str)
  !!(color_str.to_s.downcase.gsub(/\s+/, '') =~ HSLA_REGEX)
end

#hue(red, green, blue) ⇒ Integer

Calculate the HUE value of a color from RGB components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Integer)

    a value in range 0-360 which indicates the HUE value of the color



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/inker/color/tools.rb', line 71

def hue(red, green, blue)
  min, max = [red, green, blue].minmax

  numerator = (max - min).to_f
  return 0 if numerator.zero?

  hue = case max
        when red then (green - blue) / numerator
        when green then 2 + (blue - red) / numerator
        when blue then 4 + (red - green) / numerator
        end

  hue *= 60

  (hue.negative? ? hue + 360 : hue).round
end

#lightness(red, green, blue) ⇒ Float

Calculate the lightness of a color from RGB components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Float)

    a value in range 0.0-1.0 which indicates the ligthness of the color



41
42
43
44
45
# File 'lib/inker/color/tools.rb', line 41

def lightness(red, green, blue)
  min, max = [red, green, blue].minmax

  (min + max) / (2.0 * 255)
end

#luminance(red, green, blue) ⇒ Float

Calculate the luminance of a color from RGB components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Float)

    a value in range 0.0-1.0 which indicates the luminance of the color



95
96
97
98
99
100
101
102
# File 'lib/inker/color/tools.rb', line 95

def luminance(red, green, blue)
  components = [red, green, blue].map do |c|
    value = c / 255.0
    value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055)**2.4
  end

  0.2126 * components[0] + 0.7152 * components[1] + 0.0722 * components[2]
end

#overlay(color1, color2) ⇒ Inker::Color

Calculates the result of overlaying two colors.

Parameters:

Returns:

  • (Inker::Color)

    the result of overlaying the two colors.



313
314
315
# File 'lib/inker/color/tools.rb', line 313

def overlay(color1, color2)
  color1.to_color.overlay(color2)
end

#parse_color(color_str) ⇒ Hash

Parse a color string an return it's RGBA components as a hash.

Examples:

Inker::Color.parse_color("#FF005544") # returns {:red=>255, :green=>0, :blue=>85, :alpha=>0.4}

Parameters:

  • color_str (String)

    color string to parse

Returns:

  • (Hash)

    a hash which contains RGBA components of parsed color

Raises:

  • (ArgumentError)


256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/inker/color/tools.rb', line 256

def parse_color(color_str)
  # Normalize input string by stripping white spaces and converting
  # string to downcase
  input = color_str.to_s.strip.downcase

  # By default result is nil
  result = nil

  # Try to guess the format of color string and parse it by
  # using the apropriate algorithm
  if hex?(input)
    # Parse the string as HEX color
    result = parse_hex(input)
  elsif rgb?(input)
    # Parse the string as RGB color
    result = parse_rgb(input)
  elsif rgba?(input)
    # Parse the string as RGBA color
    result = parse_rgb(input, is_rgba: true)
  elsif hsl?(input)
    # Parse the string as HSL color
    result = parse_hsl(input)
  elsif hsla?(input)
    # Parse the string as HSLA color
    result = parse_hsl(input, is_hsla: true)
  else
    # Check if color is in "named color" format
    named_color = Inker.named_colors[input]
    if named_color
      # If a named color has been matched, use it's HEX value and
      # parse it as HEX color
      result = parse_hex(named_color)
    end
  end

  # If we didn't have any match, throw an ArgumentError error
  raise ArgumentError, "Unknown color format: #{color_str.to_s.strip.inspect}" if result.nil?

  result
end

#random(with_alpha: false) ⇒ Inker::Color

Generate a random Inker::Color.

Parameters:

  • with_alpha (Boolean) (defaults to: false)

    when true include alpha channel

Returns:



182
183
184
185
186
187
188
# File 'lib/inker/color/tools.rb', line 182

def random(with_alpha: false)
  prefix = with_alpha ? 'rgba' : 'rgb'
  values = (1..3).map{ (rand * 255).round }
  values << rand.round(2) if with_alpha

  Inker.color("#{prefix}(#{values.join(',')})")
end

#rgb?(color_str) ⇒ Boolean Also known as: is_rgb?

Returns a Boolean which indicates if color is in RGB format

Parameters:

  • color_str (String)

    a color string

Returns:

  • (Boolean)

    true when color is in RGB format



138
139
140
# File 'lib/inker/color/tools.rb', line 138

def rgb?(color_str)
  !!(color_str.to_s.downcase.gsub(/\s+/, '') =~ RGB_REGEX)
end

#rgba?(color_str) ⇒ Boolean Also known as: is_rgba?

Returns a Boolean which indicates if color is in RGBA format

Parameters:

  • color_str (String)

    a color string

Returns:

  • (Boolean)

    true when color is in RGBA format



149
150
151
# File 'lib/inker/color/tools.rb', line 149

def rgba?(color_str)
  !!(color_str.to_s.downcase.gsub(/\s+/, '') =~ RGBA_REGEX)
end

#saturation(red, green, blue) ⇒ Float

Calculate the saturation of a color from RGB components.

Parameters:

  • red (Integer)

    the value of red component [0-255]

  • green (Integer)

    the value of green component [0-255]

  • blue (Integer)

    the value of blue component [0-255]

Returns:

  • (Float)

    a value in range 0.0-1.0 which indicates the saturation of the color



54
55
56
57
58
59
60
61
62
# File 'lib/inker/color/tools.rb', line 54

def saturation(red, green, blue)
  # return 0 for black and white colors
  return 0 if red == green && red == blue && (red.zero? || red == 255)

  lightness = lightness(red, green, blue)
  min, max = [red / 255.0, green / 255.0, blue / 255.0].minmax

  lightness < 0.5 ? (max - min) / (max + min) : (max - min) / (2.0 - max - min)
end