Class: Chromate::Color
Overview
The ‘Color` class is used to represent a terminal color in the range 0..255. Colors are powerful tools, and have a multitude of convenience methods to make working with them easier.
Color Models
All colors have a so-called ‘color model’ (accessible via the ‘color_model` attribute). The color model of a color determines how it will be escaped. The following color models are possible:
- Colors in the range 0..7 have a color model of 8. These colors are
always escaped as single-integer values in the ranges 30..37 and
40..47 for foregrounds and backgrounds, respectively.
- Colors in the range 8..15 have a color model of 16. These colors
can be escaped in two ways, with single-integer values in the
ranges 90..97 and 100..107, for foreground and background,
respectively, or with additional bold sequences. Which route is
taken depends on the compliancy setting; single-integer values are
non-compliant, while bold sequences are. The compliancy setting
may be specified in three ways, each overriding the last: via the
class attribute on `Color`, via the instance attribute by the same
name, and in the method call as a second (optional parameter).
The default at all levels is non-compliancy.
- Colors in the range 16..255 have a color model of 256. These
colors are always escaped as xterm-256 escape sequences of the
form 38;5;x for foreground and 48;5;x for background, where x is
the actual color value.
Converting from Other Formats
The ‘Color` class features a powerful approximation mechanism, allowing the creation of colors from arbitrary RGB values, which may be specified either in RGB using from_rgb or in hex using from_hex. When either of these methods are used, the closest matching terminal color code will be found automatically, using the CIE 1976 delta-E algorithm. This operation is quite a bit slower compared to using exact color values, but it must be done only once, as all values are cached after first use and kept until the end of program execution.
Making New Colors
If you __really__ want to make a new color, you may do so by calling the provided constructor. However, this is wasteful – there is, after all, a finite set of possible colors. Moreover, all of these colors already exist as members of the ‘COLORS` constant. That’s all well and good if you have the raw color code, which can be used as an index for the ‘COLORS` array, but what if you don’t? Well, then [] is your new best friend! This method accepts the full range of color representations, including raw color codes, names, hex strings, and RGB values. The following example showcases all of the various types that [] accepts:
“‘ruby # The following all return the ’black’ color Color Color Color Color Color[[0, 0, 0]] Color[0, 0, 0]
# Malformed inputs Color # => ArgumentError: bad color code: -1 Color # => ArgumentError: bad color code: 256 Color # => nil Color # => ArgumentError: invalid hex string: # Color # => nil “‘
Note that when getting a color from a name, ‘nil` will be returned if no color with that name exists, rather than throwing an error.
Class Attribute Summary collapse
-
.compliant ⇒ Boolean
The global default compliancy setting.
Instance Attribute Summary collapse
-
#color_model ⇒ Integer
readonly
The color model of the color (either 8, 16, or 256).
- #compliant ⇒ Boolean
Class Method Summary collapse
-
.[](value, g = nil, b = nil) ⇒ Color
Get an existing Color object representing the specified color code, hex value, color name, or RGB array.
-
.from_hex(hex) ⇒ Color
Get a Color object representing the specified hex string.
-
.from_rgb(r, g = r, b = r) ⇒ Color
Get a Color object representing the specified color in RGB space.
Instance Method Summary collapse
-
#as_bg ⇒ Color
Convert to a Color that escapes to a background by default.
-
#as_fg ⇒ Color
Convert to a Color that escapes to a foreground by default.
-
#bg? ⇒ Boolean
Does this color represent a background?.
-
#blue ⇒ Integer
(also: #b)
Get the blue component of the color.
-
#escape ⇒ String
Escape as an SGR escape sequence.
-
#fg? ⇒ Boolean
Does this color represent a foreground?.
-
#green ⇒ Integer
(also: #g)
Get the green component of the color.
-
#greyscale? ⇒ Boolean
Is this color greyscale?.
-
#initialize(value, compliant = Color.compliant) ⇒ Color
constructor
Create a new Color object representing the specified color code.
- #inspect ⇒ Object
-
#name ⇒ Symbol
Get the name of the color, if it exists.
-
#red ⇒ Integer
(also: #r)
Get the red component of the color.
-
#supported? ⇒ Boolean
Is this color supported by the host environment?.
-
#to_bg(compliant = @compliant) ⇒ String
Escape as a background SGR escape sequence.
-
#to_fg(compliant = @compliant) ⇒ String
Escape as a foreground SGR escape sequence.
-
#to_hex ⇒ String
Get the hex value represented by the color.
-
#to_rgb ⇒ <Integer>
Get the RGB value represented by the color.
Methods inherited from Effect
Constructor Details
#initialize(value, compliant = Color.compliant) ⇒ Color
Create a new Color object representing the specified color code. The color model will be inferred automatically based on the range of ‘value` (8 if it’s less than 8, 16 if it’s less than 16, and 256 otherwise).
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/chromate/color.rb', line 101 def initialize(value, compliant = Color.compliant) if COLOR_NAMES.key?(value) super(COLOR_NAMES[value]) else super(value) end @compliant = compliant @escape = :fg @color_model = if @value < 8 8 elsif @value < 16 16 else 256 end end |
Class Attribute Details
.compliant ⇒ Boolean
Returns the global default compliancy setting.
85 86 87 |
# File 'lib/chromate/color.rb', line 85 def compliant @compliant end |
Instance Attribute Details
#color_model ⇒ Integer (readonly)
Returns the color model of the color (either 8, 16, or 256).
78 79 80 |
# File 'lib/chromate/color.rb', line 78 def color_model @color_model end |
Class Method Details
.[](value, g = nil, b = nil) ⇒ Color
Get an existing Color object representing the specified color code, hex value, color name, or RGB array.
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 |
# File 'lib/chromate/color.rb', line 125 def self.[](value, g = nil, b = nil) case value when Fixnum if value > 255 or value < 0 raise ArgumentError, "bad color code: #{value}" else COLORS[value] end when String if value[0] == '#' Color.from_hex(value) elsif COLOR_NAMES.key?(value.intern) COLORS[COLOR_NAMES[value.intern]] else nil end when Symbol if COLOR_NAMES.key?(value) COLORS[COLOR_NAMES[value]] else nil end when Array Color.from_rgb(*value) else if g.nil? and b.nil? raise TypeError, "don't know what to do with a #{value.class}" else Color.from_rgb(value, g, b) end end end |
.from_hex(hex) ⇒ Color
Get a Color object representing the specified hex string.
163 164 165 166 167 168 169 |
# File 'lib/chromate/color.rb', line 163 def self.from_hex(hex) if Hex::PATTERN =~ hex Color.from_rgb(*hex.scan(Hex::BYTE).map { |b| b.to_i(16) }) else raise ArgumentError, "invalid hex string: #{hex}" end end |
.from_rgb(r, g = r, b = r) ⇒ Color
The ‘g` and `b` arguments default to the value passed in for `r`, so that if you have a monochromatic color (e.g., r, g, and b are the same), you may pass a single value.
Get a Color object representing the specified color in RGB space.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/chromate/color.rb', line 184 def self.from_rgb(r, g = r, b = r) ary = [r, g, b] if RGB::COLORS.include?(ary) COLORS[RGB::COLORS.index(ary)] elsif CACHE.include?(ary) CACHE[ary] else lab = RGB.to_lab(ary) code = Lab::COLORS.index(Lab::COLORS.sort do |lab1, lab2| Lab.difference(lab, lab1) <=> Lab.difference(lab, lab2) end.first) CACHE[ary] = COLORS[code] COLORS[code] end end |
Instance Method Details
#as_bg ⇒ Color
Convert to a Color that escapes to a background by default.
279 280 281 282 |
# File 'lib/chromate/color.rb', line 279 def as_bg @escape = :bg self end |
#as_fg ⇒ Color
Convert to a Color that escapes to a foreground by default.
241 242 243 244 |
# File 'lib/chromate/color.rb', line 241 def as_fg @escape = :fg self end |
#bg? ⇒ Boolean
Does this color represent a background?
288 289 290 |
# File 'lib/chromate/color.rb', line 288 def bg? @escape == :bg end |
#blue ⇒ Integer Also known as: b
Get the blue component of the color.
361 362 363 |
# File 'lib/chromate/color.rb', line 361 def blue RGB::COLORS[@value][2] end |
#escape ⇒ String
Escape as an SGR escape sequence.
296 297 298 299 300 301 302 303 |
# File 'lib/chromate/color.rb', line 296 def escape case @escape when :fg to_fg when :bg to_bg end end |
#fg? ⇒ Boolean
Does this color represent a foreground?
250 251 252 |
# File 'lib/chromate/color.rb', line 250 def fg? @escape == :fg end |
#green ⇒ Integer Also known as: g
Get the green component of the color.
352 353 354 |
# File 'lib/chromate/color.rb', line 352 def green RGB::COLORS[@value][1] end |
#greyscale? ⇒ Boolean
Is this color greyscale?
212 213 214 |
# File 'lib/chromate/color.rb', line 212 def greyscale? GREYSCALE_COLORS.include?(self) end |
#inspect ⇒ Object
315 316 317 318 319 320 321 |
# File 'lib/chromate/color.rb', line 315 def inspect if name.nil? "#<Color: (#{to_rgb.join(',')})>" else "#<Color: #{name}>" end end |
#name ⇒ Symbol
Get the name of the color, if it exists.
309 310 311 312 313 |
# File 'lib/chromate/color.rb', line 309 def name if COLOR_NAMES.value?(@value) COLOR_NAMES.find { |k, v| v == @value }.first end end |
#red ⇒ Integer Also known as: r
Get the red component of the color.
343 344 345 |
# File 'lib/chromate/color.rb', line 343 def red RGB::COLORS[@value][0] end |
#supported? ⇒ Boolean
Is this color supported by the host environment?
204 205 206 |
# File 'lib/chromate/color.rb', line 204 def supported? SUPPORTED_COLORS.include?(self) end |
#to_bg(compliant = @compliant) ⇒ String
Escape as a background SGR escape sequence.
260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/chromate/color.rb', line 260 def to_bg(compliant = @compliant) case @color_model when 8 "\e[#{40 + @value}m" when 16 if compliant "\e[#{40 + @value - 8};1m" else "\e[#{100 + @value - 8}m" end when 256 "\e[48;5;#{@value}m" end end |
#to_fg(compliant = @compliant) ⇒ String
Escape as a foreground SGR escape sequence.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/chromate/color.rb', line 222 def to_fg(compliant = @compliant) case @color_model when 8 "\e[#{30 + @value}m" when 16 if compliant "\e[#{30 + @value - 8};1m" else "\e[#{90 + @value - 8}m" end when 256 "\e[38;5;#{@value}m" end end |
#to_hex ⇒ String
Get the hex value represented by the color.
335 336 337 |
# File 'lib/chromate/color.rb', line 335 def to_hex '#' + Hex::COLORS[@value] end |
#to_rgb ⇒ <Integer>
Get the RGB value represented by the color.
327 328 329 |
# File 'lib/chromate/color.rb', line 327 def to_rgb RGB::COLORS[@value] end |