module TermColors
Overview
Color-related functions for term/console applications.
Terminal apps can use 5 different palettes: 1. Monochrome (2-color) 2. Low color (8-color) 3. ANSI / XTerm color (16-color) 4. High color (256-color) 5. TrueColor (16M-color/24-bit color)
Direct including types
Defined in:
term_colors.crConstant Summary
-
CACHE_MATCH =
{} of Int32 => Int32 -
Storage cache for
#matchmethod -
CACHE_MATCH_LIMIT =
65536 -
Upper bound on
CACHE_MATCH. Key is the full 24-bit RGB value, so an animated TrueColor source can feed#matchunbounded distinct keys; on overflow the cache is cleared wholesale. -
ColorNames =
{"default" => -1, "normal" => -1, "bg" => -1, "fg" => -1, "black" => 0, "red" => 1, "green" => 2, "yellow" => 3, "blue" => 4, "magenta" => 5, "cyan" => 6, "white" => 7, "lightblack" => 8, "lightred" => 9, "lightgreen" => 10, "lightyellow" => 11, "lightblue" => 12, "lightmagenta" => 13, "lightcyan" => 14, "lightwhite" => 15, "brightblack" => 8, "brightred" => 9, "brightgreen" => 10, "brightyellow" => 11, "brightblue" => 12, "brightmagenta" => 13, "brightcyan" => 14, "brightwhite" => 15, "grey" => 8, "gray" => 8, "lightgrey" => 7, "lightgray" => 7, "brightgrey" => 7, "brightgray" => 7} -
Mapping of notable color names to 16 color indices.
-
CSS_HUE =
/(#{CSS_NUM})(deg|grad|rad|turn)?/i -
The
hsl()first argument: a number with an optional CSS angle unit. -
CSS_NUM =
/-?(?:\d+(?:\.\d+)?|\.\d+)/ -
A CSS
<number>: optionally negative, integer or decimal. -
CSS_RGB_COMPONENT =
/(#{CSS_NUM})(%)?/ -
A single
#rgb()component: an optionally-signed number with an optional trailing%. The sign is load-bearing: CSS clamps a negative channel to 0, so it must be read as negative rather than as its magnitude (rgb(-10, …)is0, not10). -
HEX_DIGITS =
"0123456789abcdef".to_slice -
Lowercase hex digits, for
#hex. -
HI2HH =
HI2RGB.map do |rgb| "#%02x%02x%02x" % rgb end -
Mapping of high color (256) indices to hex color values. Derived from
HI2RGB(whichbin/generate_colors_2.jsalso emits in this form). -
HI2LI =
[0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 4, 4, 4, 4, 4, 2, 6, 4, 4, 4, 4, 2, 2, 6, 4, 4, 4, 2, 2, 2, 6, 4, 4, 2, 2, 2, 2, 6, 4, 2, 2, 2, 2, 2, 6, 1, 5, 4, 4, 4, 4, 3, 0, 4, 4, 4, 4, 2, 2, 6, 4, 4, 4, 2, 2, 2, 6, 4, 4, 2, 2, 2, 2, 6, 4, 2, 2, 2, 2, 2, 6, 1, 1, 5, 4, 4, 4, 1, 1, 5, 4, 4, 4, 3, 3, 0, 4, 4, 4, 2, 2, 2, 6, 4, 4, 2, 2, 2, 2, 6, 4, 2, 2, 2, 2, 2, 6, 1, 1, 1, 5, 4, 4, 1, 1, 1, 5, 4, 4, 1, 1, 1, 5, 4, 4, 3, 3, 3, 7, 4, 4, 2, 2, 2, 2, 6, 4, 2, 2, 2, 2, 2, 6, 1, 1, 1, 1, 5, 4, 1, 1, 1, 1, 5, 4, 1, 1, 1, 1, 5, 4, 1, 1, 1, 1, 5, 4, 3, 3, 3, 3, 7, 4, 2, 2, 2, 2, 2, 6, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 5, 3, 3, 3, 3, 3, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7] -
Mapping of high color (256) indices to low color (8) indices. Generated by
bin/generate_colors.rb. -
HI2LN =
HI2LI.map do |i| LOW_NAMES[i] end -
Mapping of high color (256) indices to low color (8) names. Derived from
HI2LI(whichbin/generate_colors.rbalso emits in this form). -
HI2RGB =
[{0, 0, 0}, {205, 0, 0}, {0, 205, 0}, {205, 205, 0}, {0, 0, 238}, {205, 0, 205}, {0, 205, 205}, {229, 229, 229}, {127, 127, 127}, {255, 0, 0}, {0, 255, 0}, {255, 255, 0}, {92, 92, 255}, {255, 0, 255}, {0, 255, 255}, {255, 255, 255}, {0, 0, 0}, {0, 0, 95}, {0, 0, 135}, {0, 0, 175}, {0, 0, 215}, {0, 0, 255}, {0, 95, 0}, {0, 95, 95}, {0, 95, 135}, {0, 95, 175}, {0, 95, 215}, {0, 95, 255}, {0, 135, 0}, {0, 135, 95}, {0, 135, 135}, {0, 135, 175}, {0, 135, 215}, {0, 135, 255}, {0, 175, 0}, {0, 175, 95}, {0, 175, 135}, {0, 175, 175}, {0, 175, 215}, {0, 175, 255}, {0, 215, 0}, {0, 215, 95}, {0, 215, 135}, {0, 215, 175}, {0, 215, 215}, {0, 215, 255}, {0, 255, 0}, {0, 255, 95}, {0, 255, 135}, {0, 255, 175}, {0, 255, 215}, {0, 255, 255}, {95, 0, 0}, {95, 0, 95}, {95, 0, 135}, {95, 0, 175}, {95, 0, 215}, {95, 0, 255}, {95, 95, 0}, {95, 95, 95}, {95, 95, 135}, {95, 95, 175}, {95, 95, 215}, {95, 95, 255}, {95, 135, 0}, {95, 135, 95}, {95, 135, 135}, {95, 135, 175}, {95, 135, 215}, {95, 135, 255}, {95, 175, 0}, {95, 175, 95}, {95, 175, 135}, {95, 175, 175}, {95, 175, 215}, {95, 175, 255}, {95, 215, 0}, {95, 215, 95}, {95, 215, 135}, {95, 215, 175}, {95, 215, 215}, {95, 215, 255}, {95, 255, 0}, {95, 255, 95}, {95, 255, 135}, {95, 255, 175}, {95, 255, 215}, {95, 255, 255}, {135, 0, 0}, {135, 0, 95}, {135, 0, 135}, {135, 0, 175}, {135, 0, 215}, {135, 0, 255}, {135, 95, 0}, {135, 95, 95}, {135, 95, 135}, {135, 95, 175}, {135, 95, 215}, {135, 95, 255}, {135, 135, 0}, {135, 135, 95}, {135, 135, 135}, {135, 135, 175}, {135, 135, 215}, {135, 135, 255}, {135, 175, 0}, {135, 175, 95}, {135, 175, 135}, {135, 175, 175}, {135, 175, 215}, {135, 175, 255}, {135, 215, 0}, {135, 215, 95}, {135, 215, 135}, {135, 215, 175}, {135, 215, 215}, {135, 215, 255}, {135, 255, 0}, {135, 255, 95}, {135, 255, 135}, {135, 255, 175}, {135, 255, 215}, {135, 255, 255}, {175, 0, 0}, {175, 0, 95}, {175, 0, 135}, {175, 0, 175}, {175, 0, 215}, {175, 0, 255}, {175, 95, 0}, {175, 95, 95}, {175, 95, 135}, {175, 95, 175}, {175, 95, 215}, {175, 95, 255}, {175, 135, 0}, {175, 135, 95}, {175, 135, 135}, {175, 135, 175}, {175, 135, 215}, {175, 135, 255}, {175, 175, 0}, {175, 175, 95}, {175, 175, 135}, {175, 175, 175}, {175, 175, 215}, {175, 175, 255}, {175, 215, 0}, {175, 215, 95}, {175, 215, 135}, {175, 215, 175}, {175, 215, 215}, {175, 215, 255}, {175, 255, 0}, {175, 255, 95}, {175, 255, 135}, {175, 255, 175}, {175, 255, 215}, {175, 255, 255}, {215, 0, 0}, {215, 0, 95}, {215, 0, 135}, {215, 0, 175}, {215, 0, 215}, {215, 0, 255}, {215, 95, 0}, {215, 95, 95}, {215, 95, 135}, {215, 95, 175}, {215, 95, 215}, {215, 95, 255}, {215, 135, 0}, {215, 135, 95}, {215, 135, 135}, {215, 135, 175}, {215, 135, 215}, {215, 135, 255}, {215, 175, 0}, {215, 175, 95}, {215, 175, 135}, {215, 175, 175}, {215, 175, 215}, {215, 175, 255}, {215, 215, 0}, {215, 215, 95}, {215, 215, 135}, {215, 215, 175}, {215, 215, 215}, {215, 215, 255}, {215, 255, 0}, {215, 255, 95}, {215, 255, 135}, {215, 255, 175}, {215, 255, 215}, {215, 255, 255}, {255, 0, 0}, {255, 0, 95}, {255, 0, 135}, {255, 0, 175}, {255, 0, 215}, {255, 0, 255}, {255, 95, 0}, {255, 95, 95}, {255, 95, 135}, {255, 95, 175}, {255, 95, 215}, {255, 95, 255}, {255, 135, 0}, {255, 135, 95}, {255, 135, 135}, {255, 135, 175}, {255, 135, 215}, {255, 135, 255}, {255, 175, 0}, {255, 175, 95}, {255, 175, 135}, {255, 175, 175}, {255, 175, 215}, {255, 175, 255}, {255, 215, 0}, {255, 215, 95}, {255, 215, 135}, {255, 215, 175}, {255, 215, 215}, {255, 215, 255}, {255, 255, 0}, {255, 255, 95}, {255, 255, 135}, {255, 255, 175}, {255, 255, 215}, {255, 255, 255}, {8, 8, 8}, {18, 18, 18}, {28, 28, 28}, {38, 38, 38}, {48, 48, 48}, {58, 58, 58}, {68, 68, 68}, {78, 78, 78}, {88, 88, 88}, {98, 98, 98}, {108, 108, 108}, {118, 118, 118}, {128, 128, 128}, {138, 138, 138}, {148, 148, 148}, {158, 158, 158}, {168, 168, 168}, {178, 178, 178}, {188, 188, 188}, {198, 198, 198}, {208, 208, 208}, {218, 218, 218}, {228, 228, 228}, {238, 238, 238}] -
Mapping of high color (256) indices to RGB color values. Ported from the xterm color generation script (xterm defaults). Generated by
bin/generate_colors_2.js. -
HSV_LUT =
begin d = Data.new Array(Int32).new(360) do |hue| d.hsv_i(hue) end end -
Precomputed
#hsv_ifor every integer hue0...360at full saturation and value (s = v = 1). Index it only with a hue already reduced by% 360;HSV_LUT[h]is then bit-identical tohsv_i(h). A variables/vneeds#hsv_iitself. (Initialized through a throwawayDatasince the mixin's methods aren't module methods.) -
LOW_NAMES =
["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] of ::String -
Names of the 8 low colors, indexed by low color index.
-
VERSION =
"2.0.2" -
Xterm =
{"#000000", "#cd0000", "#00cd00", "#cdcd00", "#0000ee", "#cd00cd", "#00cdcd", "#e5e5e5", "#7f7f7f", "#ff0000", "#00ff00", "#ffff00", "#5c5cff", "#ff00ff", "#00ffff", "#ffffff"} -
16 XTerm Colors.
(Values taken from X11 sources, mapped to RGB, converted to hex.)
Instance Method Summary
-
#adjust_lightness(rgb : Int32, delta : Float64) : Int32
Moves a color's lightness by delta (positive = lighter, negative = darker), clamped to
[0, 1]. -
#color_distance(r1, g1, b1, r2, g2, b2)
Finds color similarity (weighted Euclidean distance, no color-space conversion needed).
-
#convert(color : Int)
Parses a color spec into the native color value:
-1for the terminal default, or a 24-bit0xRRGGBBinteger. -
#convert(color : String)
Parses a color spec into the native color value:
-1for the terminal default, or a 24-bit0xRRGGBBinteger. -
#convert(color : Tuple | Array)
Strips the alpha channel off the two hex-with-alpha forms (
#rgba,#rrggbbaa), returning the plain#rgb/#rrggbbthe parser understands; any other string is returned as-is. -
#darken(rgb : Int32, amount : Float64) : Int32
Darkens rgb by amount (
0..1) of lightness. -
#darker(color : Int, factor : Int = 200) : Int32
A darker shade of color ↔ Qt's
QColor::darker(factor). -
#hex(rgb : Int32) : String
0xRRGGBB->"#rrggbb". -
#hex_to_int(hex : String) : Int32
Converts a hex color value (
#abcor#rrggbb) to a 24-bit0xRRGGBBinteger. -
#hex_to_rgb(hex : String) : Tuple(Int32, Int32, Int32)
Converts hex color value (#col or #color) to {r,g,b}.
-
#hsl_to_rgb(h : Float64, s : Float64, l : Float64) : Int32
{h, s, l}->0xRRGGBB(inverse of#rgb_to_hsl). -
#hsv(h : Int | Float, s : Float64 = 1.0, v : Float64 = 1.0) : String
Converts an HSV color to a
#rrggbbhex string. -
#hsv_i(h : Int | Float, s : Float64 = 1.0, v : Float64 = 1.0) : Int32
Converts an HSV color to a packed
0xRRGGBBinteger (24-bit RGB). -
#lighten(rgb : Int32, amount : Float64) : Int32
Lightens rgb by amount (
0..1) of lightness. -
#lighter(color : Int, factor : Int = 150) : Int32
A lighter shade of color ↔ Qt's
QColor::lighter(factor). -
#luminance(rgb : Int32) : Float64
Perceived brightness (
0..1) — how bright a color reads, used to choose a contrasting foreground. -
#match(r1 : Int, g1 : Int, b1 : Int)
Takes color value and returns index of the nearest/closest matching color in the current palette.
-
#match(r1 : String)
Takes color value and returns index of the nearest/closest matching color in the current palette.
-
#match(r1 : Array | Tuple)
Takes color value and returns index of the nearest/closest matching color in the current palette.
-
#mix(c1 : Int, c2 : Int, alpha = 0.5) : Int32
Mixes two 24-bit RGB colors in RGB space.
-
#palette_to_rgb(idx : Int) : Int32
Maps a 256-color palette index to its native 24-bit
0xRRGGBBvalue (used when parsing incoming38;5;n/ANSI SGR codes into the RGB-native form). -
#parse_hsl_function(value : String) : Int32 | Nil
Parses a CSS
hsl(h, s%, l%)/hsla(...)function body into0xRRGGBB. -
#parse_rgb_function(value : String) : Int32 | Nil
Parses a CSS
#rgb(r, g, b)/rgba(r, g, b, a)function body (commas or spaces) into0xRRGGBB. -
#readable_on(bg : Int32, dark : Int32, light : Int32) : Int32
Picks whichever of dark/light contrasts better against bg.
-
#reduce(color, total)
Converts color into lower/smaller color space.
-
#rgb(r : Int, g : Int, b : Int) : Int32
Packs three
0..255channel bytes into a0xRRGGBBcolor. -
#rgb_channels(rgb : Int) : Tuple(Int32, Int32, Int32)
Public unpack of a packed
0xRRGGBBinteger into its{r, g, b}byte channels — the inverse of#rgb, for callers that hold a packed color and need the individual0..255channels. -
#rgb_to_hex(r : Int, g : Int, b : Int)
Converts RGB to hex color value (#color).
-
#rgb_to_hex(r : Array | Tuple)
Converts RGB to hex color value (#color).
-
#rgb_to_hex(r : Colorize::ColorRGB)
Converts RGB to hex color value (#color).
-
#rgb_to_hsl(rgb : Int32) : Tuple(Float64, Float64, Float64)
0xRRGGBB->{h (0..360), s (0..1), l (0..1)}. -
#rgb_to_hsv(rgb : Int32) : Tuple(Float64, Float64, Float64)
0xRRGGBB->{h (0..360), s (0..1), v (0..1)}. -
#sgr_color(color : Int, fg : Bool, colors : Int) : String
Builds the SGR parameter fragment encoding one color for a terminal that supports
colorscolors, choosing the richest encoding that fits: TrueColor (38;2;r;g;b), 256-color (38;5;n), or 16/8-color ANSI (30..37/90..97). -
#sgr_color_to(io : IO, color : Int, fg : Bool, colors : Int) : Nil
Allocation-free counterpart of
#sgr_color: writes the SGR parameter fragment for one color straight intoiorather than returning a freshString. -
#to_hex2(n)
Converts number to hex value with 2 places.
-
#to_hex4(n)
Converts number to hex value with 4 places.
Instance Method Detail
Moves a color's lightness by delta (positive = lighter, negative = darker),
clamped to [0, 1]. Saturation/hue are preserved (the work happens in HSL).
Finds color similarity (weighted Euclidean distance, no color-space conversion needed). See https://stackoverflow.com/questions/1633828
Parses a color spec into the native color value: -1 for the terminal
default, or a 24-bit 0xRRGGBB integer.
NOTE native color space is TrueColor; reduction to a smaller palette
happens only at output time (see #sgr_color).
Parses a color spec into the native color value: -1 for the terminal
default, or a 24-bit 0xRRGGBB integer.
NOTE native color space is TrueColor; reduction to a smaller palette
happens only at output time (see #sgr_color).
Strips the alpha channel off the two hex-with-alpha forms (#rgba,
#rrggbbaa), returning the plain #rgb/#rrggbb the parser understands;
any other string is returned as-is.
Tuple and Array share one body: both index with [](Int) and yield
.to_i-able elements, so one method packs either form of {r, g, b}.
A darker shade of color ↔ Qt's QColor::darker(factor). Multiplicative
(unlike the additive #darken): factor is a percentage dividing
lightness, so 200 scales it ×0.5, 100 is a no-op. factor <= 0 returns
color unchanged. See #lighter for the HSL-vs-HSV caveat.
Converts a hex color value (#abc or #rrggbb) to a 24-bit 0xRRGGBB
integer.
Converts hex color value (#col or #color) to {r,g,b}.
{h, s, l} -> 0xRRGGBB (inverse of #rgb_to_hsl).
Converts an HSV color to a #rrggbb hex string.
h is a hue in degrees (wrapped into 0..360); s and v are saturation
and value in 0.0..1.0. Defaults give full saturation/brightness. For the
allocation-free packed-integer form, see #hsv_i.
Converts an HSV color to a packed 0xRRGGBB integer (24-bit RGB).
h is a hue in degrees (wrapped into 0..360); s and v are saturation
and value in 0.0..1.0. Allocation-free counterpart of #hsv.
A lighter shade of color ↔ Qt's QColor::lighter(factor). Multiplicative
(unlike the additive #lighten): factor is a percentage, so 150 scales
lightness ×1.5, 100 is a no-op, and a value below 100 darkens.
factor <= 0 returns color unchanged (Qt leaves it unspecified).
NOTE the scale is applied to HSL lightness (what the routines here expose), whereas Qt scales HSV value; results are visually close but not bit-identical to Qt.
Perceived brightness (0..1) — how bright a color reads, used to choose a
contrasting foreground. Uses the Rec. 709 / sRGB luminance weights applied
directly to the gamma-encoded channels (no linearization), which is cheap
and adequate for picking a readable fg/bg pair, but is not the WCAG
relative luminance.
Takes color value and returns index of the nearest/closest matching color in the current palette.
Takes color value and returns index of the nearest/closest matching color in the current palette.
Takes color value and returns index of the nearest/closest matching color in the current palette.
Mixes two 24-bit RGB colors in RGB space. alpha is the opacity/weight of
c1 (1.0 keeps c1 fully, 0.0 yields c2, 0.5 is the midpoint). Returns a
0xRRGGBB value.
Operates directly in RGB (TrueColor); consumers blend at full precision and only reduce on output.
Maps a 256-color palette index to its native 24-bit 0xRRGGBB value (used
when parsing incoming 38;5;n/ANSI SGR codes into the RGB-native form).
Parses a CSS hsl(h, s%, l%) / hsla(...) function body into 0xRRGGBB.
h honors the optional CSS angle unit (deg/grad/rad/turn,
unitless = degrees); s/l are percentages. Returns nil when fewer
than three numbers parse.
Parses a CSS #rgb(r, g, b) / rgba(r, g, b, a) function body (commas or
spaces) into 0xRRGGBB. Each channel may be a 0..255 number or a
0%..100% percentage (CSS allows either form); a % component is scaled
to 0..255; out-of-range/negative channels clamp. Alpha is ignored (this
is a pure color library with no compositing). Returns nil when fewer
than three components parse.
Picks whichever of dark/light contrasts better against bg.
Converts color into lower/smaller color space.
reduce(color, @tput.colors)
Packs three 0..255 channel bytes into a 0xRRGGBB color. Channels are
assumed already in range (callers clamp/quantize upstream). The inverse of
#rgb_channels.
Public unpack of a packed 0xRRGGBB integer into its {r, g, b} byte
channels — the inverse of #rgb, for callers that hold a packed color and
need the individual 0..255 channels.
Converts RGB to hex color value (#color).
Accepts a Tuple as well as an Array so it composes with #hex_to_rgb
(its inverse), which returns a Tuple — e.g. #rgb_to_hex(hex_to_rgb(x)).
Converts RGB to hex color value (#color).
Accepts a Tuple as well as an Array so it composes with #hex_to_rgb
(its inverse), which returns a Tuple — e.g. #rgb_to_hex(hex_to_rgb(x)).
Converts RGB to hex color value (#color).
Accepts a Tuple as well as an Array so it composes with #hex_to_rgb
(its inverse), which returns a Tuple — e.g. #rgb_to_hex(hex_to_rgb(x)).
0xRRGGBB -> {h (0..360), s (0..1), l (0..1)}. HSL counterpart of the HSV
pair below; used to lighten/darken perceptually evenly (lightness is a
single axis in HSL), compute relative luminance, etc.
0xRRGGBB -> {h (0..360), s (0..1), v (0..1)}. HSV counterpart of
#rgb_to_hsl (inverse of #hsv_i); shares the same hue derivation but
reports value/saturation on the HSV axes rather than lightness.
Builds the SGR parameter fragment encoding one color for a terminal that
supports colors colors, choosing the richest encoding that fits:
TrueColor (38;2;r;g;b), 256-color (38;5;n), or 16/8-color ANSI
(30..37/90..97). color is a native color (-1 for default, or
0xRRGGBB); fg selects foreground (38/3x/9x) vs background (48/4x/10x).
A monochrome target (colors < 2) is treated like the default color: no
palette entry can be meaningful there, so the terminal's own default is
emitted.
Allocation-free counterpart of #sgr_color: writes the SGR parameter
fragment for one color straight into io rather than returning a fresh
String.