Class: Rich::ColorTriplet
- Inherits:
-
Object
- Object
- Rich::ColorTriplet
- Defined in:
- lib/rich/color_triplet.rb
Overview
Represents an RGB color triplet with values from 0-255. This is an immutable value object used for true color representation.
Instance Attribute Summary collapse
-
#blue ⇒ Integer
readonly
Blue component (0-255).
-
#green ⇒ Integer
readonly
Green component (0-255).
-
#red ⇒ Integer
readonly
Red component (0-255).
Class Method Summary collapse
-
.from_hex(hex_str) ⇒ ColorTriplet
Create from hex string.
-
.from_hsl(h, s, l) ⇒ ColorTriplet
Create from HSL values.
-
.from_normalized(r, g, b) ⇒ ColorTriplet
Create from normalized values (0.0-1.0).
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Check equality with another triplet.
-
#blend(other, factor = 0.5) ⇒ ColorTriplet
Blend this color with another.
-
#dark? ⇒ Boolean
Check if this is a “dark” color based on luminance.
-
#deconstruct ⇒ Array<Integer>
Deconstruct for pattern matching.
-
#deconstruct_keys(keys) ⇒ Hash
Deconstruct for pattern matching with keys.
-
#distance(other) ⇒ Float
Calculate color distance (Euclidean in RGB space).
-
#hash ⇒ Integer
Hash code for use in hash tables.
-
#hex ⇒ String
Hexadecimal representation without a leading ‘#’ (e.g., “ff0000”).
-
#hex_with_hash ⇒ String
Hexadecimal representation with a leading ‘#’ (e.g., “#ff0000”).
-
#initialize(red, green, blue) ⇒ ColorTriplet
constructor
Create a new color triplet.
-
#inspect ⇒ String
Inspect representation.
-
#light? ⇒ Boolean
Check if this is a “light” color based on luminance.
-
#luminance ⇒ Float
Calculate the perceived luminance of the color Uses the formula for relative luminance from WCAG 2.0.
-
#normalized ⇒ Array<Float>
Normalized components (0.0-1.0).
-
#rgb ⇒ String
RGB string representation (e.g., “rgb(255, 0, 0)”).
-
#to_a ⇒ Array<Integer>
Components as array [red, green, blue].
-
#to_h ⇒ Hash
Components as hash.
-
#to_s ⇒ String
String representation.
-
#weighted_distance(other) ⇒ Float
Calculate weighted color distance (better perceptual accuracy) Uses weighted Euclidean distance based on human color perception.
Constructor Details
#initialize(red, green, blue) ⇒ ColorTriplet
Create a new color triplet
20 21 22 23 24 25 |
# File 'lib/rich/color_triplet.rb', line 20 def initialize(red, green, blue) @red = clamp_component(red) @green = clamp_component(green) @blue = clamp_component(blue) freeze end |
Instance Attribute Details
#blue ⇒ Integer (readonly)
Returns Blue component (0-255).
14 15 16 |
# File 'lib/rich/color_triplet.rb', line 14 def blue @blue end |
#green ⇒ Integer (readonly)
Returns Green component (0-255).
11 12 13 |
# File 'lib/rich/color_triplet.rb', line 11 def green @green end |
#red ⇒ Integer (readonly)
Returns Red component (0-255).
8 9 10 |
# File 'lib/rich/color_triplet.rb', line 8 def red @red end |
Class Method Details
.from_hex(hex_str) ⇒ ColorTriplet
Create from hex string
166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rich/color_triplet.rb', line 166 def from_hex(hex_str) hex_str = hex_str.delete_prefix("#") raise ArgumentError, "Invalid hex color: #{hex_str}" unless hex_str.match?(/\A[0-9a-fA-F]{6}\z/) r = hex_str[0, 2].to_i(16) g = hex_str[2, 2].to_i(16) b = hex_str[4, 2].to_i(16) new(r, g, b) end |
.from_hsl(h, s, l) ⇒ ColorTriplet
Create from HSL values
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/rich/color_triplet.rb', line 195 def from_hsl(h, s, l) h = h % 360 s = s / 100.0 l = l / 100.0 c = (1 - (2 * l - 1).abs) * s x = c * (1 - ((h / 60.0) % 2 - 1).abs) m = l - c / 2.0 r, g, b = case (h / 60).floor when 0 then [c, x, 0] when 1 then [x, c, 0] when 2 then [0, c, x] when 3 then [0, x, c] when 4 then [x, 0, c] else [c, 0, x] end new( ((r + m) * 255).round, ((g + m) * 255).round, ((b + m) * 255).round ) end |
.from_normalized(r, g, b) ⇒ ColorTriplet
Create from normalized values (0.0-1.0)
182 183 184 185 186 187 188 |
# File 'lib/rich/color_triplet.rb', line 182 def from_normalized(r, g, b) new( (r * 255).round, (g * 255).round, (b * 255).round ) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Check equality with another triplet
62 63 64 65 66 |
# File 'lib/rich/color_triplet.rb', line 62 def ==(other) return false unless other.is_a?(ColorTriplet) @red == other.red && @green == other.green && @blue == other.blue end |
#blend(other, factor = 0.5) ⇒ ColorTriplet
Blend this color with another
124 125 126 127 128 129 130 131 132 |
# File 'lib/rich/color_triplet.rb', line 124 def blend(other, factor = 0.5) factor = [[factor, 0.0].max, 1.0].min new_r = (@red + (other.red - @red) * factor).round new_g = (@green + (other.green - @green) * factor).round new_b = (@blue + (other.blue - @blue) * factor).round ColorTriplet.new(new_r, new_g, new_b) end |
#dark? ⇒ Boolean
Check if this is a “dark” color based on luminance
110 111 112 |
# File 'lib/rich/color_triplet.rb', line 110 def dark? luminance < 0.5 end |
#deconstruct ⇒ Array<Integer>
Deconstruct for pattern matching
87 88 89 |
# File 'lib/rich/color_triplet.rb', line 87 def deconstruct to_a end |
#deconstruct_keys(keys) ⇒ Hash
Deconstruct for pattern matching with keys
94 95 96 |
# File 'lib/rich/color_triplet.rb', line 94 def deconstruct_keys(keys) to_h.slice(*(keys || [:red, :green, :blue])) end |
#distance(other) ⇒ Float
Calculate color distance (Euclidean in RGB space)
137 138 139 140 141 142 |
# File 'lib/rich/color_triplet.rb', line 137 def distance(other) dr = @red - other.red dg = @green - other.green db = @blue - other.blue Math.sqrt(dr * dr + dg * dg + db * db) end |
#hash ⇒ Integer
Returns Hash code for use in hash tables.
71 72 73 |
# File 'lib/rich/color_triplet.rb', line 71 def hash [@red, @green, @blue].hash end |
#hex ⇒ String
Returns Hexadecimal representation without a leading ‘#’ (e.g., “ff0000”). Use #hex_with_hash for the “#ff0000” form.
29 30 31 |
# File 'lib/rich/color_triplet.rb', line 29 def hex format("%02x%02x%02x", @red, @green, @blue) end |
#hex_with_hash ⇒ String
Returns Hexadecimal representation with a leading ‘#’ (e.g., “#ff0000”).
35 36 37 |
# File 'lib/rich/color_triplet.rb', line 35 def hex_with_hash "##{hex}" end |
#inspect ⇒ String
Returns Inspect representation.
81 82 83 |
# File 'lib/rich/color_triplet.rb', line 81 def inspect "#<Rich::ColorTriplet #{hex} (#{@red}, #{@green}, #{@blue})>" end |
#light? ⇒ Boolean
Check if this is a “light” color based on luminance
116 117 118 |
# File 'lib/rich/color_triplet.rb', line 116 def light? !dark? end |
#luminance ⇒ Float
Calculate the perceived luminance of the color Uses the formula for relative luminance from WCAG 2.0
101 102 103 104 105 106 |
# File 'lib/rich/color_triplet.rb', line 101 def luminance r, g, b = normalized.map do |c| c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055)**2.4 end 0.2126 * r + 0.7152 * g + 0.0722 * b end |
#normalized ⇒ Array<Float>
Returns Normalized components (0.0-1.0).
45 46 47 |
# File 'lib/rich/color_triplet.rb', line 45 def normalized [@red / 255.0, @green / 255.0, @blue / 255.0] end |
#rgb ⇒ String
Returns RGB string representation (e.g., “rgb(255, 0, 0)”).
40 41 42 |
# File 'lib/rich/color_triplet.rb', line 40 def rgb "rgb(#{@red}, #{@green}, #{@blue})" end |
#to_a ⇒ Array<Integer>
Returns Components as array [red, green, blue].
50 51 52 |
# File 'lib/rich/color_triplet.rb', line 50 def to_a [@red, @green, @blue] end |
#to_h ⇒ Hash
Returns Components as hash.
55 56 57 |
# File 'lib/rich/color_triplet.rb', line 55 def to_h { red: @red, green: @green, blue: @blue } end |
#to_s ⇒ String
Returns String representation.
76 77 78 |
# File 'lib/rich/color_triplet.rb', line 76 def to_s hex end |
#weighted_distance(other) ⇒ Float
Calculate weighted color distance (better perceptual accuracy) Uses weighted Euclidean distance based on human color perception
148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/rich/color_triplet.rb', line 148 def weighted_distance(other) dr = @red - other.red dg = @green - other.green db = @blue - other.blue # Weighted by perceptual importance (red-green component is most important) r_mean = (@red + other.red) / 2.0 weight_r = 2.0 + r_mean / 256.0 weight_g = 4.0 weight_b = 2.0 + (255.0 - r_mean) / 256.0 Math.sqrt(weight_r * dr * dr + weight_g * dg * dg + weight_b * db * db) end |