1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
# frozen_string_literal: true
##
# \Grayscale is a color object representing shades of gray as a ratio of black to white,
# where 0% (0.0) gray is black and 100% (1.0) gray is white.
#
# \Grayscale colors are immutable Data class instances. Array deconstruction is `[gray]`
# and hash deconstruction is `{g:, gray:}`. See #g, #gray.
class Color::Grayscale
include Color
##
# :attr_reader: brightness
# Returns the grayscale value as a proportion of white (0.0 .. 1.0).
##
# :attr_reader: g
# Returns the grayscale value as a proportion of white (0.0 .. 1.0).
##
# :attr_reader: gray
# Returns the grayscale value as a percentage of white (0.0 .. 100.0).
##
# Creates a grayscale color object from a percentage value (0.0 .. 100.0).
#
# ```ruby
# Color::Grayscale.from_percentage(50) # => Grayscale [0.50%]
# Color::Grayscale.from_values(50) # => Grayscale [0.50%]
# ```
#
# :call-seq:
# from_percentage(g)
# from_percentage(g:)
# from_values(g)
# from_values(g:)
def self.from_percentage(*args, **kwargs)
g =
case [args, kwargs]
in [[g], {}]
g
in [[], {g:}]
g
else
new(*args, **kwargs)
end
new(g: g / 100.0)
end
class << self
alias_method :from_values, :from_percentage
alias_method :from_fraction, :new
alias_method :from_internal, :from_fraction # :nodoc:
end
##
# Creates a grayscale color object from a fractional value (0.0 .. 1.0).
#
# ```ruby
# Color::Grayscale.from_fraction(0.5)
# Color::Grayscale.new(0.5)
# Color::Grayscale[g: 0.5]
# ```
def initialize(g:)
super(g: normalize(g))
end
##
# Coerces the other Color object to grayscale.
def coerce(other) = other.to_grayscale
##
# Convert \Grayscale to Color::CMYK.
def to_cmyk(...) = Color::CMYK.from_fraction(0, 0, 0, 1.0 - g.to_f)
##
# Convert \Grayscale to Color::RGB.
def to_rgb(...) = Color::RGB.from_fraction(g, g, g)
##
def to_grayscale(...) = self
##
# Convert \Grayscale to Color::YIQ.
#
# This approximates the actual value, as I and Q are calculated by treating the
# grayscale value as a RGB value. The Y (intensity or brightness) value is the same as
# the grayscale value.
def to_yiq(...)
y = g
i = (g * 0.596) + (g * -0.275) + (g * -0.321)
q = (g * 0.212) + (g * -0.523) + (g * 0.311)
Color::YIQ.from_fraction(y, i, q)
end
##
# Converts \Grayscale to Color::HSL.
def to_hsl(...) = Color::HSL.from_fraction(0, 0, g)
##
# Converts \Grayscale to Color::CIELAB via Color::RGB.
def to_lab(...) = to_rgb(...).to_lab(...)
##
# Present the color as an HTML/CSS color string (e.g., `#dddddd`).
def html
"##{("%02x" % translate_range(g, to: 0.0..255.0)) * 3}"
end
##
# Present the color as a CSS `rgb` color with optional `alpha`.
#
# ```ruby
# Color::Grayscale[0.5].css # => rgb(50.00% 50.00% 50.00%)
# Color::Grayscale[0.5].css(alpha: 0.75) # => rgb(50.00% 50.00% 50.00% / 0.75)
# ```
def css(alpha: nil)
params = ([css_value(gray, :percent)] * 3).join(" ")
params = "#{params} / #{css_value(alpha)}" if alpha
"rgb(#{params})"
end
##
# Lightens the grayscale color by the stated percent.
def lighten_by(percent) = Color::Grayscale.from_fraction([g + (g * (percent / 100.0)), 1.0].min)
##
# Darken the grayscale color by the stated percent.
def darken_by(percent) = Color::Grayscale.from_fraction([g - (g * (percent / 100.0)), 0.0].max)
##
alias_method :brightness, :g
##
def gray = g * 100.0
##
def inspect = "Grayscale [%.2f%%]" % [gray] # :nodoc:
##
def pretty_print(q) # :nodoc:
q.text "Grayscale"
q.breakable
q.group 2, "[", "]" do
q.text "%.2f%%" % gray
end
end
##
def to_a = [gray] # :nodoc:
##
alias_method :deconstruct, :to_a
##
def deconstruct_keys(_keys) = {g:, gray:}
##
def to_internal = [g] # :nodoc:
##
def components = 1 # :nodoc:
end
|