pigment 0.2.1 → 0.3.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.
@@ -0,0 +1,195 @@
1
+ require_relative '../pigment'
2
+
3
+ module Pigment
4
+ # Represent an abstract color in any format
5
+ module Color
6
+ class << self
7
+ # @param [#to_f] red
8
+ # @param [#to_f] blue
9
+ # @param [#to_f] green
10
+ # @param [#to_f] alpha
11
+ # @return [Pigment::Color::RGB]
12
+ def rgba(red, blue, green, alpha = 1.0)
13
+ Pigment::Color::RGB.new(red, blue, green, alpha)
14
+ end
15
+
16
+ # @param [Integer] hue between 0 and 360 degrees
17
+ # @param [#to_f] saturation between 0.0 and 1.0
18
+ # @param [#to_f] lightness between 0.0 and 1.0
19
+ # @param [#to_f] alpha between 0.0 and 1.0
20
+ # @return [Pigment::Color::HSL]
21
+ def hsla(hue, saturation, lightness, alpha = 1.0)
22
+ Pigment::Color::HSL.from_hue_angle(hue, saturation, lightness, alpha)
23
+ end
24
+
25
+ alias_method :rgb, :rgba
26
+ alias_method :hsl, :hsla
27
+
28
+ # sets aliases for any color format
29
+ # @param [Class] klass
30
+ def included(klass)
31
+ klass.alias_method :gray?, :grayscale?
32
+ klass.alias_method :-@, :inverse
33
+ klass.alias_method :inv, :inverse
34
+ klass.alias_method :invert, :inverse
35
+ klass.alias_method :complementary, :inverse
36
+ klass.alias_method :complement, :inverse
37
+ klass.alias_method :to_floats, :to_a
38
+ klass.alias_method :to_f, :to_a
39
+ klass.alias_method :inspect, :to_s
40
+ end
41
+ end
42
+
43
+ # @param [Class] color_type
44
+ # @return [Pigment::Color]
45
+ def into(color_type)
46
+ color_type.convert(self)
47
+ end
48
+
49
+ # @return [Pigment::Color]
50
+ def dup
51
+ self.class.new(*to_a)
52
+ end
53
+
54
+ # @return [Pigment::Color]
55
+ def inverse
56
+ into(Pigment::Color::RGB).inverse.into(self.class)
57
+ end
58
+
59
+ # @param [Object] other
60
+ # @return [Boolean]
61
+ def inverse?(other)
62
+ other.is_a?(Pigment::Color) && self.inverse == other
63
+ end
64
+
65
+ # @return [Array<Pigment::Color>]
66
+ def triadic
67
+ into(Pigment::Color::RGB).triadic.map { |color| color.into(self.class) }
68
+ end
69
+
70
+ # @param [Object] other
71
+ # @return [Boolean]
72
+ def triadic_of?(other)
73
+ other.into(self.class)
74
+ other.triadic.include?(self)
75
+ end
76
+
77
+ # @param [Array<Object>] others
78
+ # @return [Boolean]
79
+ def triadic_include?(*others)
80
+ colors = triadic
81
+ others.all? { |color| colors.include?(color) }
82
+ end
83
+
84
+ # @return [Array<Pigment::Color>]
85
+ def split
86
+ into(Pigment::Color::HSL).split.map { |color| color.into(self.class) }
87
+ end
88
+
89
+ # @param [Object] other
90
+ # @return [Boolean]
91
+ def split_of?(other)
92
+ other.split.include?(self)
93
+ end
94
+
95
+ # @param [Array<Object>] others
96
+ # @return [Boolean]
97
+ def split_include?(*others)
98
+ colors = split
99
+ others.all? { |color| colors.include?(color) }
100
+ end
101
+
102
+ # @return [Array<Pigment::Color>]
103
+ def analogous
104
+ into(Pigment::Color::HSL).analogous.map { |color| color.into(self.class) }
105
+ end
106
+
107
+ # @param [Object] other
108
+ # @return [Boolean]
109
+ def analogous_of?(other)
110
+ other.analogous.include?(self)
111
+ end
112
+
113
+ # @param [Array<Object>] others
114
+ # @return [Boolean]
115
+ def analogous_include?(*others)
116
+ colors = analogous
117
+ others.all? { |color| colors.include?(color) }
118
+ end
119
+
120
+ # @return [Array<Pigment::Color>]
121
+ def tetradic
122
+ into(Pigment::Color::HSL).tetradic.map { |color| color.into(self.class) }
123
+ end
124
+
125
+ # @param [Object] other
126
+ # @return [Boolean]
127
+ def tetradic_of?(other)
128
+ other.tetradic.include?(self)
129
+ end
130
+
131
+ # @param [Array<Object>] others
132
+ # @return [Boolean]
133
+ def tetradic_include?(*others)
134
+ others.all? { |color| tetradic.include?(color) }
135
+ end
136
+
137
+ # @return [Array<Pigment::Color>]
138
+ def rectangular
139
+ into(Pigment::Color::HSL).rectangular.map { |color| color.into(self.class) }
140
+ end
141
+
142
+ # @param [Object] other
143
+ # @return [Boolean]
144
+ def rectangular_of?(other)
145
+ other.rectangular.include?(self)
146
+ end
147
+
148
+ # @param [Array<Object>] others
149
+ # @return [Boolean]
150
+ def rectangular_include?(*others)
151
+ colors = rectangular
152
+ others.all? { |color| colors.include?(color) }
153
+ end
154
+
155
+ # @return [Array<Pigment::Color>]
156
+ def tertiary
157
+ into(Pigment::Color::HSL).tertiary.map { |color| color.into(self.class) }
158
+ end
159
+
160
+ # @param [Object] other
161
+ # @return [Boolean]
162
+ def tertiary_of?(other)
163
+ other.tertiary.include?(self)
164
+ end
165
+
166
+ # @param [Array<Object>] others
167
+ # @return [Boolean]
168
+ def tertiary_include?(*others)
169
+ colors = tertiary
170
+ others.all? { |color| colors.include?(color) }
171
+ end
172
+
173
+ # @param [Boolean] with_alpha
174
+ # @return [String]
175
+ def to_html(with_alpha: false)
176
+ "##{to_hex(with_alpha: with_alpha)}"
177
+ end
178
+
179
+ # @param [Boolean] with_alpha
180
+ # @return [Array<Integer>]
181
+ def to_ints(with_alpha: true)
182
+ into(Pigment::Color::RGB).to_ints(with_alpha: with_alpha)
183
+ end
184
+
185
+ # @param [Boolean] with_alpha
186
+ # @return [String]
187
+ def to_hex(with_alpha: true)
188
+ into(Pigment::Color::RGB).to_hex(with_alpha: with_alpha)
189
+ end
190
+ end
191
+ end
192
+
193
+ require_relative 'color/rgb'
194
+ require_relative 'color/hsl'
195
+
@@ -0,0 +1,158 @@
1
+ require_relative '../color'
2
+
3
+ module Pigment
4
+ module Color
5
+ # Represent a color in the HSL Format
6
+ class HSL
7
+ using FloatSnap
8
+
9
+ # @return [Float]
10
+ attr_reader :hue, :saturation, :lightness, :alpha
11
+
12
+ class << self
13
+
14
+ # Converts a color into HSL format from any possible format, given they know how to convert to RGB
15
+ # @param [Pigment::Color] color
16
+ # @return [Pigment::Color::HSL]
17
+ def convert(color)
18
+ return color if color.is_a?(self)
19
+ color = color.into(Pigment::Color::RGB)
20
+ rgb = color.rgb
21
+ r, g, b = rgb
22
+
23
+ min = rgb.min
24
+ max = rgb.max
25
+ chroma = max - min
26
+ sum = max + min
27
+ l = sum / 2.0
28
+
29
+ return new(0, 0, l, color.alpha) if chroma == 0.0
30
+
31
+ s = l > 0.5 ? chroma / (2.0 - sum) : chroma / sum
32
+
33
+ h = case max
34
+ when r then ((g - b) / chroma) / 6 + (g < b && 1 || 0)
35
+ when g then ((b - r) / chroma) / 6.0 + (1.0 / 3.0)
36
+ when b then ((r - g) / chroma) / 6.0 + (2.0 / 3.0)
37
+ end
38
+
39
+ new(h, s, l, color.alpha)
40
+ end
41
+
42
+ # @param [Integer] hue between 0 and 360 degrees
43
+ # @param [#to_f] saturation between 0.0 and 1.0
44
+ # @param [#to_f] lightness between 0.0 and 1.0
45
+ # @param [#to_f] alpha between 0.0 and 1.0
46
+ # @return [Pigment::Color::HSL]
47
+ def from_hue_angle(hue, saturation, lightness, alpha = 1.0)
48
+ new(hue / 360.0, saturation, lightness, alpha)
49
+ end
50
+ end
51
+
52
+ # @param [#to_f] hue between 0.0 and 1.0 mapping to 0 to 360 degrees
53
+ # @param [#to_f] saturation between 0.0 and 1.0
54
+ # @param [#to_f] lightness between 0.0 and 1.0
55
+ # @param [#to_f] alpha between 0.0 and 1.0
56
+ # @return [Pigment::Color::HSL]
57
+ # @raise [InvalidColorFormatError]
58
+ def initialize(hue, saturation, lightness, alpha = 1.0)
59
+ @hue = hue % 1.0
60
+ @saturation = saturation.to_f.snap
61
+ @lightness = lightness.to_f.snap
62
+ @alpha = alpha.to_f.snap
63
+
64
+ color = to_f(with_alpha: true)
65
+ raise InvalidColorFormatError, color unless color.all? { |c| c.between?(0.0, 1.0) }
66
+ end
67
+
68
+ # @return [Pigment::Color::HSL] the grayscale correspondent of the color
69
+ def grayscale
70
+ self.class.new(@hue, 0, @lightness, @alpha)
71
+ end
72
+
73
+ # @return [Boolean] true if saturation is 0, false otherwise
74
+ def grayscale?
75
+ @saturation == 0
76
+ end
77
+
78
+ # @return [Array<Pigment::Color>] An array with the triadic colors of the color
79
+ def triadic
80
+ [self.class.new(@hue + 1 / 3.0, s, l), self.class.new(@hue + 2 / 3.0, s, l)]
81
+ end
82
+
83
+ # @return [Array<Pigment::Color>] An array with the split colors of the color
84
+ def split
85
+ [self.class.new(@hue - 5 / 12.0, s, l), self.class.new(@hue + 5 / 12.0, s, l)]
86
+ end
87
+
88
+ # @return [Array<Pigment::Color>] An array with the analogous colors of the color
89
+ def analogous
90
+ [self.class.new(@hue - 1 / 12.0, s, l), self.class.new(@hue + 1 / 12.0, s, l)]
91
+ end
92
+
93
+ # @return [Array<Pigment::Color>] An array with the tetradic colors of the color
94
+ def tetradic
95
+ [
96
+ self.class.new(@hue + 1 / 4.0, @saturation, @lightness),
97
+ self.class.new(@hue + 1 / 2.0, @saturation, @lightness),
98
+ self.class.new(@hue + 3 / 4.0, @saturation, @lightness)
99
+ ]
100
+ end
101
+
102
+ # @return [Array<Pigment::Color>] An array with the rectangular colors of the color
103
+ def rectangular
104
+ [
105
+ self.class.new(@hue + 1 / 6.0, @saturation, @lightness),
106
+ self.class.new(@hue + 1 / 2.0, @saturation, @lightness),
107
+ self.class.new(@hue + 2 / 3.0, @saturation, @lightness)
108
+ ]
109
+ end
110
+
111
+ # @return [Array<Pigment::Color>] An array with the tertiary colors of the color
112
+ def tertiary
113
+ [
114
+ self.class.new(@hue + 1 / 6.0, @saturation, @lightness),
115
+ self.class.new(@hue + 1 / 3.0, @saturation, @lightness),
116
+ self.class.new(@hue + 1 / 2.0, @saturation, @lightness),
117
+ self.class.new(@hue + 2 / 3.0, @saturation, @lightness),
118
+ self.class.new(@hue + 5 / 6.0, @saturation, @lightness),
119
+ ]
120
+ end
121
+
122
+ # @param [Boolean] with_alpha
123
+ # @return [Array<Float>] an array with the color components
124
+ def to_a(with_alpha: true)
125
+ with_alpha ? [@hue, @saturation, @lightness, @alpha] : [@hue, @saturation, @lightness]
126
+ end
127
+
128
+ # @return [String] the string representation of a hsl color
129
+ def to_s
130
+ "HSL Color(hue: #{hue}, saturation: #{saturation}, lightness: #{lightness}, alpha: #{alpha})"
131
+ end
132
+
133
+ # @param [Object] other
134
+ # @return [Boolean] wether the color is equal to other object
135
+ def ==(other)
136
+ other = Pigment::Color::HSL.convert(other)
137
+ other.hue.snap == @hue.snap &&
138
+ other.saturation.snap == @saturation.snap &&
139
+ other.lightness.snap == @lightness.snap &&
140
+ other.alpha.snap == @alpha.snap
141
+ end
142
+
143
+ alias_method :a, :alpha
144
+ alias_method :h, :hue
145
+ alias_method :s, :saturation
146
+ alias_method :l, :lightness
147
+
148
+ include Pigment::Color
149
+
150
+ private
151
+ # @return [Array] an array with the respective hsla components
152
+ def method_missing(method, *args)
153
+ super unless method =~ /^[ahsl]+$/ && args.empty?
154
+ method.to_s.each_char.map { |component| send(component) }
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,10 @@
1
+ module Pigment
2
+ module Color
3
+ # Error raised when an invalid color format is used
4
+ class InvalidColorFormatError < ArgumentError
5
+ def initialize(object)
6
+ super("Invalid Format #{object.inspect}")
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,283 @@
1
+ require_relative '../color'
2
+
3
+ module Pigment
4
+ module Color
5
+ # Represent a color in the RGB Format
6
+ class RGB
7
+ using FloatSnap
8
+
9
+ # @return [Float]
10
+ attr_reader :red, :green, :blue, :alpha
11
+
12
+ class << self
13
+ # Converts a color into RGB format from any possible format
14
+ # @param [Pigment::Color] color
15
+ # @return [Pigment::Color]
16
+ # @raise [InvalidColorFormatError]
17
+ def convert(color)
18
+ case color
19
+ when RGB then color
20
+ when HSL then from_hsl(*color)
21
+ else raise InvalidColorFormatError, color
22
+ end
23
+ end
24
+
25
+ # Creates a Pigment::Color::RGB from an HTML Hex code String
26
+ # @param [String, Integer, Float] hex
27
+ # @return [Pigment::Color::RGB]
28
+ # @raise [InvalidColorFormatError]
29
+ def from_hex(hex)
30
+ case hex
31
+ when String then from_hex_string(hex)
32
+ when Integer then from_hex_integer(hex)
33
+ when Float then from_hex_integer(hex.round)
34
+ else raise InvalidColorFormatError, hex
35
+ end
36
+ end
37
+
38
+ # Creates a Pigment::Color from a group of rgba Integers
39
+ # @param [Integer] red
40
+ # @param [Integer] green
41
+ # @param [Integer] blue
42
+ # @param [Integer] alpha
43
+ # @return [Pigment::Color::RGB]
44
+ # @raise [InvalidColorFormatError]
45
+ def from_rgba_integers(red, green, blue, alpha = 255)
46
+ color = [red, green, blue, alpha]
47
+ raise InvalidColorFormatError, color unless color.all? do |c|
48
+ (0..255).include? c
49
+ end
50
+ new(*color.map { |c| c / 255.0 })
51
+ end
52
+
53
+ # @param [Integer] red
54
+ # @param [Integer] green
55
+ # @param [Integer] blue
56
+ # @return [Pigment::Color::RGB]
57
+ def from_rgb_integers(red, green, blue)
58
+ from_rgba_integers(red, green, blue)
59
+ end
60
+
61
+ # @return [Pigment::Color::RGB] a random generated color
62
+ def random
63
+ new(rand(0.0..1.0), rand(0.0..1.0), rand(0.0..1.0))
64
+ end
65
+
66
+ # Suppress an array of floats by dividing by the greatest color component.
67
+ # @param [Array] color
68
+ # @return [Array]
69
+ def suppress(color)
70
+ return color.map { |c| c / color.max } unless color.max.between?(0.0, 1.0)
71
+ color
72
+ end
73
+
74
+ private
75
+ # @param [Integer] hex
76
+ # @return [Pigment::Color::RGB]
77
+ def from_hex_integer(hex)
78
+ raise InvalidColorFormatError, hex unless hex.is_a?(Numeric) && hex.between?(0, 0xFFFFFFFF)
79
+ red = (hex >> 24 & 0xFF)
80
+ green = (hex >> 16 & 0xFF)
81
+ blue = (hex >> 8 & 0xFF)
82
+ alpha = (hex & 0xFF)
83
+ from_rgba_integers(red, green, blue, alpha)
84
+ end
85
+
86
+ # @param [String] hex
87
+ # @raise [InvalidColorFormatError]
88
+ # @return [Pigment::Color::RGB]
89
+ def from_hex_string(hex)
90
+ matches = hex.match(/^#?(?<r>\h{2})(?<g>\h{2})(?<b>\h{2})(?<a>\h{2})?$/)&.named_captures
91
+ raise InvalidColorFormatError, hex unless matches
92
+ matches["a"] ||= 'FF'
93
+ new(*matches.values.map { |value| value.to_i(16) / 255.0 })
94
+ end
95
+
96
+ # Creates a Pigment::Color::RGB form the HSL color System. It's mostly used to calculate harmonic colors.
97
+ # @param [#to_f] hue between 0.0 and 1.0
98
+ # @param [#to_f] saturation between 0.0 and 1.0
99
+ # @param [#to_f] lightness between 0.0 and 1.0
100
+ # @param [#to_f] alpha between 0.0 and 1.0
101
+ # @return [Pigment::Color::RGB]
102
+ def from_hsl(hue, saturation, lightness, alpha = 1.0)
103
+ return new(lightness, lightness, lightness, alpha) if saturation == 0
104
+ v2 = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - saturation * lightness
105
+ v1 = 2 * lightness - v2
106
+ color = [hue + (1 / 3.0), hue, hue - (1 / 3.0)].map do |hv|
107
+ hv = hv < 0 ? hv + 1
108
+ : hv > 1 ? hv - 1
109
+ : hv
110
+
111
+ case
112
+ when 6 * hv < 1 then v1 + (v2 - v1) * 6 * hv
113
+ when 2 * hv < 1 then v2
114
+ when 3 * hv < 2 then v1 + (v2 - v1) * ((2 / 3.0) - hv) * 6
115
+ else v1
116
+ end
117
+ end
118
+ color << alpha
119
+ new(*color.map { |c| c.round(2) })
120
+ end
121
+ end
122
+
123
+ # Pigment uses sRGB or sRGBA as the default color system
124
+ # Pigment::Color::RGB is represented as an array of floats, which are ranged from 0.0 to 1.0
125
+ # @param [Float, Integer] red between 0.0 and 1.0
126
+ # @param [Float, Integer] green between 0.0 and 1.0
127
+ # @param [Float, Integer] blue between 0.0 and 1.0
128
+ # @param [Float, Integer] alpha between 0.0 and 1.0
129
+ # @return [Pigment::Color::RGB]
130
+ # @raise [InvalidColorFormatError]
131
+ def initialize(red, green, blue, alpha = 1.0)
132
+ @red = red.to_f.snap
133
+ @green = green.to_f.snap
134
+ @blue = blue.to_f.snap
135
+ @alpha = alpha.to_f
136
+
137
+ color = to_floats(with_alpha: true)
138
+ raise InvalidColorFormatError, color unless color.all? { |c| c.between?(0.0, 1.0) }
139
+ end
140
+
141
+ # Sums all the two colors components. If any component gets out of the 0 to 1.0 range it gets suppressed.
142
+ # @param [Pigment::Color] color
143
+ # @return [Pigment::Color::RGB]
144
+ # @raise [InvalidColorFormatError]
145
+ def +(color)
146
+ raise InvalidColorFormatError, color unless color.is_a?(Pigment::Color)
147
+ color = color.into(self.class)
148
+ color = [
149
+ @red + color.red,
150
+ @green + color.green,
151
+ @blue + color.blue
152
+ ]
153
+
154
+ self.class.new(*self.class.suppress(color), @alpha)
155
+ end
156
+
157
+ # Subtracts all the two color components. If any component gets out of the 0 to 1.0 range it gets suppressed.
158
+ # Tone component will be 0 if it gets lower than 0
159
+ # @param [Pigment::Color] color
160
+ # @return [Pigment::Color::RGB]
161
+ # @raise [InvalidColorFormatError]
162
+ def -(color)
163
+ raise InvalidColorFormatError, color unless color.is_a?(Pigment::Color)
164
+ color = color.into(self.class)
165
+ self.class.new(*self.class.suppress([
166
+ @red - color.red,
167
+ @green - color.green,
168
+ @blue - color.blue
169
+ ].map { |c| c >= 0 ? c : 0 }), @alpha)
170
+ end
171
+
172
+ # Multiplies all the color components by n. If any component gets out of the 0 to 1.0 range it gets suppressed.
173
+ # @param [Numeric] n
174
+ # @return [Pigment::Color::RGB]
175
+ def *(n)
176
+ raise ArgumentError, "Expecting Numeric. Given #{n.class}" unless n.is_a? Numeric
177
+ n = rgb.map { |c| c * n.to_f }
178
+ self.class.new(*self.class.suppress(n), @alpha)
179
+ end
180
+
181
+ # Divides all the color components by n. If any component gets out of the 0 to 1.0 range it gets suppressed.
182
+ # @param [Numeric] n
183
+ # @return [Pigment::Color::RGB]
184
+ def /(n)
185
+ raise ArgumentError, "Expecting Numeric. Given #{n.class}" unless n.is_a? Numeric
186
+ n = rgb.map { |c| c / n.to_f }
187
+ self.class.new(*self.class.suppress(n), @alpha)
188
+ end
189
+
190
+ # Test if two colors are equal
191
+ # @param [Pigment::Color] other
192
+ # @return [Boolean]
193
+ def ==(other)
194
+ return false unless other.is_a?(Pigment::Color)
195
+ other = Pigment::Color::RGB.convert(other)
196
+ other.red.snap == @red.snap &&
197
+ other.blue.snap == @blue.snap &&
198
+ other.green.snap == @green.snap &&
199
+ other.alpha.snap == @alpha.snap
200
+ end
201
+
202
+ # @return [Pigment::Color::RGB] the grayscale correspondent of the color
203
+ def grayscale
204
+ gray = (@red + @green + @blue) / 3.0
205
+ self.class.new(gray, gray, gray, @alpha)
206
+ end
207
+
208
+ # @return [Boolean] true if all components are the same, false otherwise
209
+ def grayscale?
210
+ @red == @green && @green == @blue
211
+ end
212
+
213
+ # Interpolates two colors. Amount must be an float between -1.0 and 1.0
214
+ # @param [Pigment::Color] color
215
+ # @param [Float] amount
216
+ # @return [Pigment::Color::RGB]
217
+ # @raise [InvalidColorFormatError]
218
+ def interpolate(color, amount = 0.5)
219
+ raise InvalidColorFormatError, color unless color.is_a?(Pigment::Color)
220
+ raise ArgumentError, "Amount must be an float between -1.0 and 1.0, got #{amount}" unless (-1.0..1.0).include?(amount)
221
+ color = color.into(Pigment::Color::RGB)
222
+ n = [rgb, color.rgb].transpose.map! { |c, d| c + amount * (d - c) }
223
+ self.class.new(*self.class.suppress(n))
224
+ end
225
+
226
+ # @return [RGB] the Invert color
227
+ def inverse
228
+ self.class.new(*rgb.map { |c| 1.0 - c }, @alpha)
229
+ end
230
+
231
+
232
+ # @return [Array<Pigment::Color>] An array of the triadic colors from self
233
+ def triadic
234
+ [self.class.new(@blue, @red, @green, @alpha), self.class.new(@green, @blue, @red, @alpha)]
235
+ end
236
+
237
+ # @param [Boolean] with_alpha
238
+ # @return [Array<Float>] an array of the color components. Alpha value is passed as well if with_alpha is set to true.
239
+ def to_a(with_alpha: true)
240
+ with_alpha ? [@red, @green, @blue, @alpha] : [@red, @green, @blue]
241
+ end
242
+
243
+ # @param [Boolean] with_alpha
244
+ # @return [Array<Integer>] an array of the color components. Alpha value is passed as well if with_alpha is set to true.
245
+ def to_ints(with_alpha: true)
246
+ to_a(with_alpha: with_alpha).map { |v| (v * 255).to_i }
247
+ end
248
+
249
+ # @param [Boolean] with_alpha
250
+ # @return [String] an hexadecimal representation of the color components. Alpha value is passed as well if
251
+ # with_alpha is set to true.
252
+ def to_hex(with_alpha: true)
253
+ to_ints(with_alpha: with_alpha).map { |v| '%02x' % v }.join
254
+ end
255
+
256
+ # @return [Array<Float>] an array with the red, green and blue color components
257
+ def rgb
258
+ to_a(with_alpha: false)
259
+ end
260
+
261
+ # @return [String] the string representation of a hsl color
262
+ def to_s
263
+ "RGB Color(red: #{red}, green: #{green}, blue: #{blue}, alpha: #{alpha})"
264
+ end
265
+
266
+ alias_method :mix, :interpolate
267
+ alias_method :r, :red
268
+ alias_method :g, :green
269
+ alias_method :b, :blue
270
+ alias_method :a, :alpha
271
+ alias_method :rgba, :to_a
272
+
273
+ include Pigment::Color
274
+
275
+ private
276
+ # @return [Array<Float>] an array with the respective rgba components
277
+ def method_missing(method, *args)
278
+ return super unless method =~ /^[abgr]+$/ && args.empty?
279
+ method.size.times.map{ |i| send(method[i]) }
280
+ end
281
+ end
282
+ end
283
+ end