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.



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.



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.



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.



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.



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.



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.



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



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



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.



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



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.



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.



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.



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.



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}

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.



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



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



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.



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