abachrome 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.envrc +3 -0
- data/README.md +10 -0
- data/Rakefile +12 -0
- data/devenv.lock +88 -17
- data/devenv.nix +2 -1
- data/devenv.yaml +5 -12
- data/lib/abachrome/abc_decimal.rb +202 -8
- data/lib/abachrome/color.rb +77 -2
- data/lib/abachrome/color_mixins/blend.rb +53 -2
- data/lib/abachrome/color_mixins/lighten.rb +49 -2
- data/lib/abachrome/color_mixins/to_colorspace.rb +67 -2
- data/lib/abachrome/color_mixins/to_lrgb.rb +70 -2
- data/lib/abachrome/color_mixins/to_oklab.rb +67 -2
- data/lib/abachrome/color_mixins/to_oklch.rb +60 -2
- data/lib/abachrome/color_mixins/to_srgb.rb +77 -2
- data/lib/abachrome/color_models/hsv.rb +25 -2
- data/lib/abachrome/color_models/oklab.rb +19 -2
- data/lib/abachrome/color_models/oklch.rb +42 -2
- data/lib/abachrome/color_models/rgb.rb +28 -2
- data/lib/abachrome/color_space.rb +76 -2
- data/lib/abachrome/converter.rb +57 -3
- data/lib/abachrome/converters/base.rb +69 -2
- data/lib/abachrome/converters/lrgb_to_oklab.rb +28 -2
- data/lib/abachrome/converters/lrgb_to_srgb.rb +27 -2
- data/lib/abachrome/converters/oklab_to_lrgb.rb +34 -2
- data/lib/abachrome/converters/oklab_to_oklch.rb +31 -2
- data/lib/abachrome/converters/oklab_to_srgb.rb +27 -2
- data/lib/abachrome/converters/oklch_to_lrgb.rb +25 -2
- data/lib/abachrome/converters/oklch_to_oklab.rb +27 -2
- data/lib/abachrome/converters/oklch_to_srgb.rb +26 -2
- data/lib/abachrome/converters/srgb_to_lrgb.rb +26 -2
- data/lib/abachrome/converters/srgb_to_oklab.rb +28 -2
- data/lib/abachrome/converters/srgb_to_oklch.rb +27 -2
- data/lib/abachrome/gamut/base.rb +2 -2
- data/lib/abachrome/gamut/p3.rb +2 -2
- data/lib/abachrome/gamut/rec2020.rb +2 -2
- data/lib/abachrome/gamut/srgb.rb +20 -2
- data/lib/abachrome/illuminants/base.rb +2 -2
- data/lib/abachrome/illuminants/d50.rb +2 -2
- data/lib/abachrome/illuminants/d55.rb +2 -2
- data/lib/abachrome/illuminants/d65.rb +2 -2
- data/lib/abachrome/illuminants/d75.rb +2 -2
- data/lib/abachrome/named/css.rb +149 -158
- data/lib/abachrome/outputs/css.rb +2 -2
- data/lib/abachrome/palette.rb +112 -2
- data/lib/abachrome/palette_mixins/interpolate.rb +20 -2
- data/lib/abachrome/palette_mixins/resample.rb +2 -2
- data/lib/abachrome/palette_mixins/stretch_luminance.rb +2 -2
- data/lib/abachrome/parsers/hex.rb +2 -2
- data/lib/abachrome/to_abcd.rb +10 -2
- data/lib/abachrome/version.rb +2 -2
- data/lib/abachrome.rb +78 -2
- data/logo.png +0 -0
- data/logo.webp +0 -0
- metadata +15 -67
data/lib/abachrome/color.rb
CHANGED
@@ -1,4 +1,22 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::Color - Core color representation class
|
2
|
+
#
|
3
|
+
# This is the central color class that represents colors across multiple color spaces
|
4
|
+
# including sRGB, OKLAB, OKLCH, and linear RGB. The Color class encapsulates color
|
5
|
+
# coordinates, alpha values, and color space information while providing methods
|
6
|
+
# for color creation, conversion, and manipulation.
|
7
|
+
#
|
8
|
+
# Key features:
|
9
|
+
# - Create colors from RGB, OKLAB, OKLCH values with factory methods
|
10
|
+
# - Automatic coordinate validation against color space definitions
|
11
|
+
# - Immutable color objects with equality and hash support
|
12
|
+
# - Extensible through mixins for color space conversions and operations
|
13
|
+
# - High-precision decimal arithmetic using AbcDecimal for accurate calculations
|
14
|
+
# - Support for alpha (opacity) values with proper handling in conversions
|
15
|
+
#
|
16
|
+
# The class uses a mixin system to dynamically include functionality for converting
|
17
|
+
# between color spaces, blending operations, and lightness adjustments. All coordinate
|
18
|
+
# values are stored as AbcDecimal objects to maintain precision during color science
|
19
|
+
# calculations and transformations.
|
2
20
|
|
3
21
|
require "dry-inflector"
|
4
22
|
require_relative "abc_decimal"
|
@@ -8,6 +26,13 @@ module Abachrome
|
|
8
26
|
class Color
|
9
27
|
attr_reader :color_space, :coordinates, :alpha
|
10
28
|
|
29
|
+
# Initializes a new Color object with the specified color space, coordinates, and alpha value.
|
30
|
+
#
|
31
|
+
# @param color_space [ColorSpace] The color space for this color instance
|
32
|
+
# @param coordinates [Array<Numeric, String>] The color coordinates in the specified color space
|
33
|
+
# @param alpha [Numeric, String] The alpha (opacity) value, between 0.0 and 1.0 (default: 1.0)
|
34
|
+
# @raise [ArgumentError] If the coordinates are invalid for the specified color space
|
35
|
+
# @return [Color] A new Color instance
|
11
36
|
def initialize(color_space, coordinates, alpha = AbcDecimal("1.0"))
|
12
37
|
@color_space = color_space
|
13
38
|
@coordinates = coordinates.map { |c| AbcDecimal(c.to_s) }
|
@@ -25,21 +50,49 @@ module Abachrome
|
|
25
50
|
include mixin_module
|
26
51
|
end
|
27
52
|
|
53
|
+
# Creates a new Color instance from RGB values
|
54
|
+
#
|
55
|
+
# @param r [Numeric] The red component value (typically 0-1)
|
56
|
+
# @param g [Numeric] The green component value (typically 0-1)
|
57
|
+
# @param b [Numeric] The blue component value (typically 0-1)
|
58
|
+
# @param a [Numeric] The alpha (opacity) component value (0-1), defaults to 1.0 (fully opaque)
|
59
|
+
# @return [Abachrome::Color] A new Color instance in the sRGB color space
|
28
60
|
def self.from_rgb(r, g, b, a = 1.0)
|
29
61
|
space = ColorSpace.find(:srgb)
|
30
62
|
new(space, [r, g, b], a)
|
31
63
|
end
|
32
64
|
|
65
|
+
# Creates a new Color object with OKLAB values.
|
66
|
+
#
|
67
|
+
# @param l [Float] The lightness component (L) of the OKLAB color space
|
68
|
+
# @param a [Float] The green-red component (a) of the OKLAB color space
|
69
|
+
# @param b [Float] The blue-yellow component (b) of the OKLAB color space
|
70
|
+
# @param alpha [Float] The alpha (opacity) value, from 0.0 to 1.0
|
71
|
+
# @return [Abachrome::Color] A new Color object in the OKLAB color space
|
33
72
|
def self.from_oklab(l, a, b, alpha = 1.0)
|
34
73
|
space = ColorSpace.find(:oklab)
|
35
74
|
new(space, [l, a, b], alpha)
|
36
75
|
end
|
37
76
|
|
77
|
+
# Creates a new color instance in the OKLCH color space.
|
78
|
+
#
|
79
|
+
# @param l [Numeric] The lightness component (L), typically in range 0..1
|
80
|
+
# @param c [Numeric] The chroma component (C), typically starting from 0 with no upper bound
|
81
|
+
# @param h [Numeric] The hue component (H) in degrees, typically in range 0..360
|
82
|
+
# @param alpha [Float] The alpha (opacity) component, in range 0..1, defaults to 1.0 (fully opaque)
|
83
|
+
# @return [Abachrome::Color] A new Color instance in the OKLCH color space
|
38
84
|
def self.from_oklch(l, c, h, alpha = 1.0)
|
39
85
|
space = ColorSpace.find(:oklch)
|
40
86
|
new(space, [l, c, h], alpha)
|
41
87
|
end
|
42
88
|
|
89
|
+
# Compares this color instance with another for equality.
|
90
|
+
#
|
91
|
+
# Two colors are considered equal if they have the same color space,
|
92
|
+
# coordinates, and alpha value.
|
93
|
+
#
|
94
|
+
# @param other [Object] The object to compare with
|
95
|
+
# @return [Boolean] true if the colors are equal, false otherwise
|
43
96
|
def ==(other)
|
44
97
|
return false unless other.is_a?(Color)
|
45
98
|
|
@@ -48,14 +101,31 @@ module Abachrome
|
|
48
101
|
alpha == other.alpha
|
49
102
|
end
|
50
103
|
|
104
|
+
# Checks if this color is equal to another color object.
|
105
|
+
#
|
106
|
+
# @param other [Object] The object to compare with
|
107
|
+
# @return [Boolean] true if the two colors are equal, false otherwise
|
108
|
+
# @see ==
|
51
109
|
def eql?(other)
|
52
110
|
self == other
|
53
111
|
end
|
54
112
|
|
113
|
+
# Generates a hash code for this color instance
|
114
|
+
# based on its color space, coordinates, and alpha value.
|
115
|
+
# The method first converts these components to strings,
|
116
|
+
# then computes a hash of the resulting array.
|
117
|
+
#
|
118
|
+
# @return [Integer] a hash code that can be used for equality comparison
|
119
|
+
# and as a hash key in Hash objects
|
55
120
|
def hash
|
56
121
|
[color_space, coordinates, alpha].map(&:to_s).hash
|
57
122
|
end
|
58
123
|
|
124
|
+
# Returns a string representation of the color in the format "ColorSpaceName(coord1, coord2, coord3, alpha)"
|
125
|
+
#
|
126
|
+
# @return [String] A human-readable string representation of the color showing its
|
127
|
+
# color space name, coordinate values rounded to 3 decimal places, and alpha value
|
128
|
+
# (if not 1.0)
|
59
129
|
def to_s
|
60
130
|
coord_str = coordinates.map { |c| c.to_f.round(3) }.join(", ")
|
61
131
|
alpha_str = alpha == AbcDecimal.new("1.0") ? "" : ", #{alpha.to_f.round(3)}"
|
@@ -64,6 +134,11 @@ module Abachrome
|
|
64
134
|
|
65
135
|
private
|
66
136
|
|
137
|
+
# Validates that the number of coordinates matches the expected number for the color space.
|
138
|
+
# Compares the size of the coordinates array with the number of coordinates
|
139
|
+
# defined in the associated color space.
|
140
|
+
# @raise [ArgumentError] when the number of coordinates doesn't match the color space definition
|
141
|
+
# @return [nil] if validation passes
|
67
142
|
def validate_coordinates!
|
68
143
|
return if coordinates.size == color_space.coordinates.size
|
69
144
|
|
@@ -71,4 +146,4 @@ module Abachrome
|
|
71
146
|
"Expected #{color_space.coordinates.size} coordinates for #{color_space.name}, got #{coordinates.size}"
|
72
147
|
end
|
73
148
|
end
|
74
|
-
end
|
149
|
+
end
|
@@ -1,8 +1,38 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::ColorMixins::Blend - Color blending and mixing functionality
|
2
|
+
#
|
3
|
+
# This mixin provides methods for blending and mixing colors together in various color spaces.
|
4
|
+
# The blend operation interpolates between two colors by a specified amount, creating smooth
|
5
|
+
# color transitions. All blending operations preserve alpha values and can be performed in
|
6
|
+
# the current color space or a specified target color space for optimal results.
|
7
|
+
#
|
8
|
+
# Key features:
|
9
|
+
# - Linear interpolation between colors with configurable blend amounts
|
10
|
+
# - Support for blending in different color spaces (sRGB, OKLAB, OKLCH)
|
11
|
+
# - Both non-destructive (blend/mix) and destructive (blend!/mix!) variants
|
12
|
+
# - Automatic color space conversion when blending colors from different spaces
|
13
|
+
# - High-precision decimal arithmetic for accurate color calculations
|
14
|
+
#
|
15
|
+
# The mixin includes both immutable methods that return new color instances and mutable
|
16
|
+
# methods that modify the current color object in place, providing flexibility for
|
17
|
+
# different use cases and performance requirements.
|
2
18
|
|
3
19
|
module Abachrome
|
4
20
|
module ColorMixins
|
5
21
|
module Blend
|
22
|
+
# @method blend
|
23
|
+
# Interpolates between two colors, creating a new color that is a blend of the two.
|
24
|
+
# The blend happens in the specified color space or the current color space if none is provided.
|
25
|
+
# #
|
26
|
+
# @param [Abachrome::Color] other The color to blend with
|
27
|
+
# @param [Float, Integer, #to_d] amount The blend amount between 0 and 1, where 0 returns the original color and 1 returns the other color. Defaults to 0.5 (midpoint)
|
28
|
+
# @param [Symbol, nil] target_color_space The color space to perform the blend in (optional)
|
29
|
+
# @return [Abachrome::Color] A new color representing the blend of the two colors
|
30
|
+
# @example Blend two colors equally
|
31
|
+
# red.blend(blue, 0.5)
|
32
|
+
# @example Blend with 25% of another color
|
33
|
+
# red.blend(blue, 0.25)
|
34
|
+
# @example Blend in a specific color space
|
35
|
+
# red.blend(blue, 0.5, target_color_space: :oklab)
|
6
36
|
def blend(other, amount = 0.5, target_color_space: nil)
|
7
37
|
amount = AbcDecimal(amount)
|
8
38
|
|
@@ -25,6 +55,14 @@ module Abachrome
|
|
25
55
|
)
|
26
56
|
end
|
27
57
|
|
58
|
+
# Blends this color with another color by the specified amount.
|
59
|
+
# This is a destructive version of the blend method, modifying the current
|
60
|
+
# color in place.
|
61
|
+
#
|
62
|
+
# @param other [Abachrome::Color] The color to blend with
|
63
|
+
# @param amount [Float] The blend amount, between 0.0 and 1.0, where 0.0 is
|
64
|
+
# this color and 1.0 is the other color (default: 0.5)
|
65
|
+
# @return [Abachrome::Color] Returns self after modification
|
28
66
|
def blend!(other, amount = 0.5)
|
29
67
|
blended = blend(other, amount)
|
30
68
|
@color_space = blended.color_space
|
@@ -33,13 +71,26 @@ module Abachrome
|
|
33
71
|
self
|
34
72
|
end
|
35
73
|
|
74
|
+
# Alias for the blend method that mixes two colors together.
|
75
|
+
#
|
76
|
+
# @param other [Abachrome::Color] The color to mix with
|
77
|
+
# @param amount [Float] The amount to mix, between 0.0 and 1.0, where 0.0 returns the original color and 1.0 returns the other color (default: 0.5)
|
78
|
+
# @return [Abachrome::Color] A new color resulting from the mix of the two colors
|
36
79
|
def mix(other, amount = 0.5)
|
37
80
|
blend(other, amount)
|
38
81
|
end
|
39
82
|
|
83
|
+
# Mix the current color with another color.
|
84
|
+
#
|
85
|
+
# This method is an alias for blend!. It combines the current color with
|
86
|
+
# the provided color at the specified amount.
|
87
|
+
#
|
88
|
+
# @param other [Abachrome::Color] The color to mix with the current color
|
89
|
+
# @param amount [Numeric] The amount of the other color to mix in, from 0 to 1 (default: 0.5)
|
90
|
+
# @return [self] Returns the modified color object
|
40
91
|
def mix!(other, amount = 0.5)
|
41
92
|
blend!(other, amount)
|
42
93
|
end
|
43
94
|
end
|
44
95
|
end
|
45
|
-
end
|
96
|
+
end
|
@@ -1,8 +1,32 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::ColorMixins::Lighten - Color lightness adjustment functionality
|
2
|
+
#
|
3
|
+
# This mixin provides methods for adjusting the lightness of colors by manipulating
|
4
|
+
# the L (lightness) component in the OKLAB color space. The OKLAB color space is used
|
5
|
+
# because it provides perceptually uniform lightness adjustments that appear more
|
6
|
+
# natural to the human eye compared to adjustments in other color spaces.
|
7
|
+
#
|
8
|
+
# Key features:
|
9
|
+
# - Lighten and darken colors with configurable amounts
|
10
|
+
# - Both non-destructive (lighten/darken) and destructive (lighten!/darken!) variants
|
11
|
+
# - Automatic clamping to valid lightness ranges [0, 1]
|
12
|
+
# - High-precision decimal arithmetic for accurate color calculations
|
13
|
+
# - Conversion to OKLAB color space for perceptually uniform adjustments
|
14
|
+
#
|
15
|
+
# The mixin includes both immutable methods that return new color instances and mutable
|
16
|
+
# methods that modify the current color object in place, providing flexibility for
|
17
|
+
# different use cases and performance requirements.
|
2
18
|
|
3
19
|
module Abachrome
|
4
20
|
module ColorMixins
|
5
21
|
module Lighten
|
22
|
+
# Increases the lightness of a color by the specified amount in the OKLab color space.
|
23
|
+
# This method works by extracting the L (lightness) component from the OKLab
|
24
|
+
# representation of the color and increasing it by the given amount, ensuring
|
25
|
+
# the result stays within the valid range of [0, 1].
|
26
|
+
#
|
27
|
+
# @param amount [Numeric] The amount to increase the lightness by, as a decimal
|
28
|
+
# value between 0 and 1. Defaults to 0.1 (10% increase).
|
29
|
+
# @return [Abachrome::Color] A new Color instance with increased lightness.
|
6
30
|
def lighten(amount = 0.1)
|
7
31
|
amount = AbcDecimal(amount)
|
8
32
|
oklab = to_oklab
|
@@ -19,6 +43,13 @@ module Abachrome
|
|
19
43
|
)
|
20
44
|
end
|
21
45
|
|
46
|
+
# Increases the lightness of the color by the specified amount and modifies the current color object.
|
47
|
+
# This method changes the color in-place, mutating the current object. The color
|
48
|
+
# is converted to a lightness-based color space if needed to perform the operation.
|
49
|
+
#
|
50
|
+
# @param amount [Float] The amount to increase the lightness by, as a decimal value
|
51
|
+
# between 0 and 1. Default is 0.1 (10% increase).
|
52
|
+
# @return [Abachrome::Color] Returns self for method chaining.
|
22
53
|
def lighten!(amount = 0.1)
|
23
54
|
lightened = lighten(amount)
|
24
55
|
@color_space = lightened.color_space
|
@@ -27,13 +58,29 @@ module Abachrome
|
|
27
58
|
self
|
28
59
|
end
|
29
60
|
|
61
|
+
# Darkens a color by decreasing its lightness value.
|
62
|
+
#
|
63
|
+
# This method is effectively a convenience wrapper around the {#lighten} method,
|
64
|
+
# passing a negative amount value to decrease the lightness instead of increasing it.
|
65
|
+
#
|
66
|
+
# @param amount [Float] The amount to darken the color by, between 0 and 1.
|
67
|
+
# Defaults to 0.1 (10% darker).
|
68
|
+
# @return [Color] A new color instance with decreased lightness.
|
69
|
+
# @see #lighten
|
30
70
|
def darken(amount = 0.1)
|
31
71
|
lighten(-amount)
|
32
72
|
end
|
33
73
|
|
74
|
+
# Decreases the lightness value of the color by the specified amount.
|
75
|
+
# Modifies the color in place.
|
76
|
+
#
|
77
|
+
# @param amount [Float] The amount to darken the color by, as a value between 0 and 1.
|
78
|
+
# Defaults to 0.1 (10% darker).
|
79
|
+
# @return [Abachrome::Color] Returns self with the modified lightness value.
|
80
|
+
# @see #lighten!
|
34
81
|
def darken!(amount = 0.1)
|
35
82
|
lighten!(-amount)
|
36
83
|
end
|
37
84
|
end
|
38
85
|
end
|
39
|
-
end
|
86
|
+
end
|
@@ -1,14 +1,46 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::ColorMixins::ToColorspace - Color space conversion functionality
|
2
|
+
#
|
3
|
+
# This mixin provides methods for converting colors between different color spaces within
|
4
|
+
# the Abachrome library. It includes both immutable and mutable conversion methods that
|
5
|
+
# allow colors to be transformed from their current color space to any registered target
|
6
|
+
# color space, such as sRGB, OKLAB, OKLCH, or linear RGB.
|
7
|
+
#
|
8
|
+
# Key features:
|
9
|
+
# - Convert colors to any registered color space with automatic converter lookup
|
10
|
+
# - Both non-destructive (to_color_space/convert_to/in_color_space) and destructive variants
|
11
|
+
# - Optimized to return the same object when no conversion is needed
|
12
|
+
# - Flexible API with multiple method names for different use cases and preferences
|
13
|
+
# - Integration with the Converter system for extensible color space transformations
|
14
|
+
#
|
15
|
+
# The mixin provides a consistent interface for color space conversions while maintaining
|
16
|
+
# the precision and accuracy required for color science calculations through the use of
|
17
|
+
# the underlying converter infrastructure.
|
2
18
|
|
3
19
|
module Abachrome
|
4
20
|
module ColorMixins
|
5
21
|
module ToColorspace
|
22
|
+
# Converts the current color to the specified target color space.
|
23
|
+
#
|
24
|
+
# This method transforms the current color into an equivalent color in a different
|
25
|
+
# color space. If the target space is the same as the current color space, no
|
26
|
+
# conversion is performed and the current color is returned.
|
27
|
+
#
|
28
|
+
# @param target_space [Abachrome::ColorSpace] The target color space to convert to
|
29
|
+
# @return [Abachrome::Color] A new color object in the target color space, or self
|
30
|
+
# if the target space is the same as the current color space
|
6
31
|
def to_color_space(target_space)
|
7
32
|
return self if color_space == target_space
|
8
33
|
|
9
34
|
Converter.convert(self, target_space.name)
|
10
35
|
end
|
11
36
|
|
37
|
+
# Converts the color object to the specified target color space in-place.
|
38
|
+
# This method modifies the current object by changing its color space and
|
39
|
+
# coordinates to match the target color space.
|
40
|
+
#
|
41
|
+
# @param target_space [Abachrome::ColorSpace] The color space to convert to
|
42
|
+
# @return [Abachrome::Color] Returns self with modified color space and coordinates
|
43
|
+
# @see #to_color_space The non-destructive version that returns a new color object
|
12
44
|
def to_color_space!(target_space)
|
13
45
|
unless color_space == target_space
|
14
46
|
converted = to_color_space(target_space)
|
@@ -18,21 +50,54 @@ module Abachrome
|
|
18
50
|
self
|
19
51
|
end
|
20
52
|
|
53
|
+
# Convert this color to a different color space.
|
54
|
+
#
|
55
|
+
# @param space_name [String, Symbol] The name of the target color space to convert to.
|
56
|
+
# @return [Abachrome::Color] A new Color object in the specified color space.
|
57
|
+
# @example
|
58
|
+
# # Convert a color from sRGB to OKLCH
|
59
|
+
# rgb_color.convert_to(:oklch)
|
60
|
+
# @see Abachrome::ColorSpace.find
|
61
|
+
# @see #to_color_space
|
21
62
|
def convert_to(space_name)
|
22
63
|
to_color_space(ColorSpace.find(space_name))
|
23
64
|
end
|
24
65
|
|
66
|
+
# Converts this color to the specified color space in place.
|
67
|
+
#
|
68
|
+
# @param space_name [String, Symbol] The name or identifier of the target color space to convert to.
|
69
|
+
# @return [Abachrome::Color] Returns self with its values converted to the specified color space.
|
70
|
+
# @raise [Abachrome::ColorSpaceNotFoundError] If the specified color space is not registered.
|
71
|
+
# @see Abachrome::ColorSpace.find
|
72
|
+
# @example
|
73
|
+
# red = Abachrome::Color.new(1, 0, 0, color_space: :srgb)
|
74
|
+
# red.convert_to!(:oklch) # Converts the red color to OKLCH space in place
|
25
75
|
def convert_to!(space_name)
|
26
76
|
to_color_space!(ColorSpace.find(space_name))
|
27
77
|
end
|
28
78
|
|
79
|
+
# Convert a color to a specified color space.
|
80
|
+
#
|
81
|
+
# @param space_name [Symbol, String] The name of the color space to convert to.
|
82
|
+
# @return [Abachrome::Color] A new Color instance in the specified color space.
|
83
|
+
# @example
|
84
|
+
# red_rgb = Abachrome::Color.new(:srgb, [1, 0, 0])
|
85
|
+
# red_lch = red_rgb.in_color_space(:oklch)
|
29
86
|
def in_color_space(space_name)
|
30
87
|
convert_to(space_name)
|
31
88
|
end
|
32
89
|
|
90
|
+
# Converts the color to the specified color space and mutates the current object.
|
91
|
+
#
|
92
|
+
# @param space_name [Symbol, String] The target color space to convert to (e.g., :oklch, :rgb, :lab)
|
93
|
+
# @return [Abachrome::Color] Returns self after conversion
|
94
|
+
# @see #convert_to!
|
95
|
+
# @example
|
96
|
+
# color = Abachrome::Color.new([255, 0, 0], :rgb)
|
97
|
+
# color.in_color_space!(:oklch) # Color is now in OKLCH space
|
33
98
|
def in_color_space!(space_name)
|
34
99
|
convert_to!(space_name)
|
35
100
|
end
|
36
101
|
end
|
37
102
|
end
|
38
|
-
end
|
103
|
+
end
|
@@ -1,16 +1,49 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::ColorMixins::ToLrgb - Linear RGB color space conversion functionality
|
2
|
+
#
|
3
|
+
# This mixin provides methods for converting colors to the linear RGB (LRGB) color space,
|
4
|
+
# which uses a linear relationship between stored numeric values and actual light intensity.
|
5
|
+
# Linear RGB is essential for accurate color calculations and serves as an intermediate
|
6
|
+
# color space for many color transformations, particularly when converting between
|
7
|
+
# different color models.
|
8
|
+
#
|
9
|
+
# Key features:
|
10
|
+
# - Convert colors to linear RGB with automatic converter lookup
|
11
|
+
# - Both non-destructive (to_lrgb) and destructive (to_lrgb!) conversion methods
|
12
|
+
# - Direct access to linear RGB components (lred, lgreen, lblue)
|
13
|
+
# - Utility methods for RGB array and hex string output
|
14
|
+
# - Optimized to return the same object when no conversion is needed
|
15
|
+
# - High-precision decimal arithmetic for accurate color science calculations
|
16
|
+
#
|
17
|
+
# The linear RGB color space differs from standard sRGB by removing gamma correction,
|
18
|
+
# making it suitable for mathematical operations like blending, lighting calculations,
|
19
|
+
# and color space transformations that require linear light behavior.
|
2
20
|
|
3
21
|
require_relative "../converter"
|
4
22
|
|
5
23
|
module Abachrome
|
6
24
|
module ColorMixins
|
7
25
|
module ToLrgb
|
26
|
+
# Converts this color to the Linear RGB (LRGB) color space.
|
27
|
+
# This method transforms the current color to the linear RGB color space,
|
28
|
+
# which uses a linear relationship between the stored numeric value and
|
29
|
+
# the actual light intensity. If the color is already in the LRGB space,
|
30
|
+
# it returns the current object without conversion.
|
31
|
+
#
|
32
|
+
# @return [Abachrome::Color] A new color object in the LRGB color space,
|
33
|
+
# or the original object if already in LRGB space
|
8
34
|
def to_lrgb
|
9
35
|
return self if color_space.name == :lrgb
|
10
36
|
|
11
37
|
Converter.convert(self, :lrgb)
|
12
38
|
end
|
13
39
|
|
40
|
+
# Converts the current color to the linear RGB (LRGB) color space and updates
|
41
|
+
# the receiver's state. If the color is already in LRGB space, this is a no-op.
|
42
|
+
#
|
43
|
+
# Unlike #to_lrgb which returns a new color instance, this method modifies the
|
44
|
+
# current object by changing its color space and coordinates to the LRGB equivalent.
|
45
|
+
#
|
46
|
+
# @return [Abachrome::Color] the receiver itself, now in LRGB color space
|
14
47
|
def to_lrgb!
|
15
48
|
unless color_space.name == :lrgb
|
16
49
|
lrgb_color = to_lrgb
|
@@ -20,30 +53,65 @@ module Abachrome
|
|
20
53
|
self
|
21
54
|
end
|
22
55
|
|
56
|
+
# Returns the linear red component value of the color.
|
57
|
+
#
|
58
|
+
# This method accesses the first coordinate from the color in linear RGB space.
|
59
|
+
# Linear RGB values differ from standard RGB by using a non-gamma-corrected
|
60
|
+
# linear representation of luminance.
|
61
|
+
#
|
62
|
+
# @return [AbcDecimal] The linear red component value, typically in range [0, 1]
|
23
63
|
def lred
|
24
64
|
to_lrgb.coordinates[0]
|
25
65
|
end
|
26
66
|
|
67
|
+
# Retrieves the linear green (lgreen) coordinate from a color by converting it to
|
68
|
+
# linear RGB color space first. Linear RGB uses a different scale than standard
|
69
|
+
# sRGB, with values representing linear light energy rather than gamma-corrected
|
70
|
+
# values.
|
71
|
+
#
|
72
|
+
# @return [AbcDecimal] The linear green component value from the color's linear
|
73
|
+
# RGB representation
|
27
74
|
def lgreen
|
28
75
|
to_lrgb.coordinates[1]
|
29
76
|
end
|
30
77
|
|
78
|
+
# Returns the linear blue channel value of this color after conversion to linear RGB color space.
|
79
|
+
#
|
80
|
+
# This method converts the current color to the linear RGB color space and extracts the blue
|
81
|
+
# component (the third coordinate).
|
82
|
+
#
|
83
|
+
# @return [AbcDecimal] The linear blue component value, typically in the range [0, 1]
|
31
84
|
def lblue
|
32
85
|
to_lrgb.coordinates[2]
|
33
86
|
end
|
34
87
|
|
88
|
+
# Returns the coordinates of the color in the linear RGB color space.
|
89
|
+
#
|
90
|
+
# @return [Array<AbcDecimal>] An array of three AbcDecimal values representing
|
91
|
+
# the red, green, and blue components in linear RGB color space.
|
35
92
|
def lrgb_values
|
36
93
|
to_lrgb.coordinates
|
37
94
|
end
|
38
95
|
|
96
|
+
# Returns an array of sRGB values as integers in the 0-255 range.
|
97
|
+
# This method converts the color to RGB, scales the values to the 0-255 range,
|
98
|
+
# rounds to integers, and ensures they are clamped within the valid range.
|
99
|
+
#
|
100
|
+
# @return [Array<Integer>] An array of three RGB integer values between 0-255
|
39
101
|
def rgb_array
|
40
102
|
to_rgb.coordinates.map { |c| (c * 255).round.clamp(0, 255) }
|
41
103
|
end
|
42
104
|
|
105
|
+
# Returns a hexadecimal string representation of the color in RGB format.
|
106
|
+
#
|
107
|
+
# @return [String] A hexadecimal color code in the format '#RRGGBB' where RR, GG, and BB
|
108
|
+
# are two-digit hexadecimal values for the red, green, and blue components respectively.
|
109
|
+
# @example
|
110
|
+
# color.rgb_hex # => "#1a2b3c"
|
43
111
|
def rgb_hex
|
44
112
|
r, g, b = rgb_array
|
45
113
|
format("#%02x%02x%02x", r, g, b)
|
46
114
|
end
|
47
115
|
end
|
48
116
|
end
|
49
|
-
end
|
117
|
+
end
|
@@ -1,16 +1,49 @@
|
|
1
|
-
#
|
1
|
+
# Abachrome::ColorMixins::ToOklab - OKLAB color space conversion functionality
|
2
|
+
#
|
3
|
+
# This mixin provides methods for converting colors to the OKLAB color space, which is a
|
4
|
+
# perceptually uniform color space designed for better color manipulation and comparison.
|
5
|
+
# OKLAB provides more intuitive lightness adjustments and color blending compared to
|
6
|
+
# traditional RGB color spaces, making it ideal for color science applications.
|
7
|
+
#
|
8
|
+
# Key features:
|
9
|
+
# - Convert colors to OKLAB with automatic converter lookup
|
10
|
+
# - Both non-destructive (to_oklab) and destructive (to_oklab!) conversion methods
|
11
|
+
# - Direct access to OKLAB components (lightness, a, b)
|
12
|
+
# - Utility methods for OKLAB array and value extraction
|
13
|
+
# - Optimized to return the same object when no conversion is needed
|
14
|
+
# - High-precision decimal arithmetic for accurate color science calculations
|
15
|
+
#
|
16
|
+
# The OKLAB color space uses three components: L (lightness), a (green-red axis), and
|
17
|
+
# b (blue-yellow axis), providing a more perceptually uniform representation of colors
|
18
|
+
# that better matches human visual perception compared to traditional color spaces.
|
2
19
|
|
3
20
|
require_relative "../converter"
|
4
21
|
|
5
22
|
module Abachrome
|
6
23
|
module ColorMixins
|
7
24
|
module ToOklab
|
25
|
+
# Converts the current color to the OKLAB color space.
|
26
|
+
#
|
27
|
+
# If the color is already in OKLAB, it returns the color unchanged.
|
28
|
+
# Otherwise, it uses the Converter to transform the color to OKLAB.
|
29
|
+
#
|
30
|
+
# @return [Abachrome::Color] A new Color object in the OKLAB color space
|
8
31
|
def to_oklab
|
9
32
|
return self if color_space.name == :oklab
|
10
33
|
|
11
34
|
Converter.convert(self, :oklab)
|
12
35
|
end
|
13
36
|
|
37
|
+
# Converts the color to the OKLAB color space in place.
|
38
|
+
# This method transforms the current color into OKLAB space,
|
39
|
+
# modifying the original object by updating its color space
|
40
|
+
# and coordinates if not already in OKLAB.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# color = Abachrome::Color.from_hex("#ff5500")
|
44
|
+
# color.to_oklab! # Color now uses OKLAB color space
|
45
|
+
#
|
46
|
+
# @return [Abachrome::Color] self, with updated color space and coordinates
|
14
47
|
def to_oklab!
|
15
48
|
unless color_space.name == :oklab
|
16
49
|
oklab_color = to_oklab
|
@@ -20,29 +53,61 @@ module Abachrome
|
|
20
53
|
self
|
21
54
|
end
|
22
55
|
|
56
|
+
# Returns the lightness component (L) of the color in the OKLAB color space.
|
57
|
+
# The lightness value ranges from 0 (black) to 1 (white) and represents
|
58
|
+
# the perceived lightness of the color.
|
59
|
+
#
|
60
|
+
# @return [AbcDecimal] The lightness (L) value from the OKLAB color space
|
23
61
|
def lightness
|
24
62
|
to_oklab.coordinates[0]
|
25
63
|
end
|
26
64
|
|
65
|
+
# Returns the L (Lightness) component from the OKLAB color space.
|
66
|
+
#
|
67
|
+
# The L value represents perceptual lightness in the OKLAB color space,
|
68
|
+
# typically ranging from 0 (black) to 1 (white).
|
69
|
+
#
|
70
|
+
# @return [AbcDecimal] The L (Lightness) component from the OKLAB color space
|
27
71
|
def l
|
28
72
|
to_oklab.coordinates[0]
|
29
73
|
end
|
30
74
|
|
75
|
+
# Returns the 'a' component from the OKLAB color space (green-red axis).
|
76
|
+
#
|
77
|
+
# The 'a' component in OKLAB represents the position on the green-red axis,
|
78
|
+
# with negative values being more green and positive values being more red.
|
79
|
+
#
|
80
|
+
# @return [AbcDecimal] The 'a' component value from the OKLAB color space.
|
81
|
+
# @see #to_oklab For the full conversion to OKLAB color space
|
31
82
|
def a
|
32
83
|
to_oklab.coordinates[1]
|
33
84
|
end
|
34
85
|
|
86
|
+
# Returns the B value of the color in OKLAB color space.
|
87
|
+
#
|
88
|
+
# This method first converts the color to OKLAB color space if needed,
|
89
|
+
# then extracts the B component (blue-yellow axis), which is the third
|
90
|
+
# coordinate in the OKLAB model.
|
91
|
+
#
|
92
|
+
# @return [AbcDecimal] The B component value in OKLAB color space
|
35
93
|
def b
|
36
94
|
to_oklab.coordinates[2]
|
37
95
|
end
|
38
96
|
|
97
|
+
# Returns the OKLAB color space coordinates for this color.
|
98
|
+
#
|
99
|
+
# @return [Array] An array of OKLAB coordinates [L, a, b] representing the color in OKLAB color space
|
39
100
|
def oklab_values
|
40
101
|
to_oklab.coordinates
|
41
102
|
end
|
42
103
|
|
104
|
+
# Returns an array representation of the color's coordinates in the OKLAB color space.
|
105
|
+
#
|
106
|
+
# @return [Array<AbcDecimal>] An array containing the coordinates of the color
|
107
|
+
# in the OKLAB color space in the order [L, a, b]
|
43
108
|
def oklab_array
|
44
109
|
to_oklab.coordinates
|
45
110
|
end
|
46
111
|
end
|
47
112
|
end
|
48
|
-
end
|
113
|
+
end
|