pigment 0.1.10 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dda5e6ade89b5949326fcb411e9aa8d99065fa511d3baeebb08e1cfb6199e84e
4
+ data.tar.gz: '058d8b2c5e47edfe74d716688ab99e33b99b51c46773dd0600c43c4755010b2e'
5
+ SHA512:
6
+ metadata.gz: 409765f525e55b3b63fd2ce3fe1e54af1fb070600c4f049a7992d984bd20b0b7f08bbdedb08f5702d6a9f53b50f035c4e25cff4013d741175f5615f889b1febd
7
+ data.tar.gz: ab38122e3bbd72c5af6f78a451ae885b52673ec3583a05d346af1bd9c81bd8d844d0dea757fb8e5a5eb7a111452815a192cfebd079304707128a35b45ced28d6
@@ -0,0 +1,6 @@
1
+ # 0.3.0
2
+ - New classes per Color Format
3
+ - Pigment::Color::RGB
4
+ - Pigment::Color::HSL
5
+ - Base module for Color Formats Pigment::Color
6
+ - Palette class to handle a collection of colors
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright © 2020 Pedro Miranda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -6,4 +6,185 @@ To install:
6
6
  gem install pigment
7
7
  ```
8
8
 
9
- <a href='http://www.pledgie.com/campaigns/18945'><img alt='Click here to lend your support to: pigment (ruby gem) and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/18945.png?skin_name=chrome' border='0' /></a>
9
+ ## Usage
10
+ ### RGB Color Format
11
+ The RGB color format is represented with four components between 0.0 and 1.0, representing 0 to 255
12
+ - `@red`
13
+ - `@green`
14
+ - `@blue`
15
+ - `@alpha`
16
+
17
+ ```ruby
18
+ require 'pigment/color/rgb'
19
+
20
+ red = Pigment::Color::RGB.new(1.0, 0.0, 0.0)
21
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.0)
22
+
23
+ red.to_a
24
+ # [1.0, 0.0, 0.0, 1.0]
25
+
26
+ semitransparent_red = Pigment::Color::RGB.new(1.0, 0.0, 0.0, 0.5)
27
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.5)
28
+
29
+ red + semitransparent_red
30
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
31
+
32
+ semitransparent_red + red
33
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.5)
34
+
35
+ red - semitransparent_red
36
+ # RGB Color(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
37
+
38
+ half_red = red / 2
39
+ # RGB Color(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0)
40
+
41
+ half_red * 2 == red
42
+ # true
43
+
44
+ gray50 = Pigment::Color::RGB.new(1.0, 0.5, 0.0).grayscale
45
+ # RGB Color(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)
46
+
47
+ gray50.grayscale?
48
+ # true
49
+
50
+ cyan = red.inverse
51
+ # RGB Color(red: 0.0, green: 1.0, blue: 1.0, alpha: 1.0)
52
+
53
+ green, blue = red.triadic
54
+ # [RGB Color(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0), RGB Color(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)]
55
+
56
+ red.to_hex
57
+ # '0xff0000ff'
58
+
59
+ red.to_hex(with_alpha: false)
60
+ # '0xff0000'
61
+
62
+ Pigment::Color::RGB.convert(Pigment::Color::HSL.new(0.0, 1, 0.5))
63
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
64
+ ```
65
+
66
+ ### HSL Color Format
67
+
68
+ The HSL color format is represented with
69
+
70
+ - `@hue` - a value from 0.0 to 1.0, representing 0 to 360 degrees
71
+ - `@saturation` - a value from 0.0 to 1.0
72
+ - `@lightness` - a value from 0.0 to 1.0
73
+ - `@alpha` - a value from 0.0 to 1.0
74
+
75
+ This format is useful to calculate related colors:
76
+
77
+ - triadic
78
+ - split
79
+ - analogous
80
+ - tetradic
81
+ - rectangular
82
+ - tertiary
83
+
84
+ ```ruby
85
+ require 'pigment/color/hsl'
86
+
87
+ hsl_red = Pigment::Color::HSL.convert(red)
88
+ # HSL Color(hue: 0.0, saturation: 1.0, lightness: 0.5, alpha: 1.0)
89
+
90
+ hsl_red == Pigment::Color::HSL(0.0, 1, 0.5)
91
+ # HSL Color(hue: 0.0, saturation: 1.0, lightness: 0.5, alpha: 1.0)
92
+
93
+ hsl_red.triadic
94
+ hsl_red.split
95
+ hsl_red.analogous
96
+ hsl_red.tetradic
97
+ hsl_red.rectangular
98
+ hsl_red.tertiary
99
+
100
+ ```
101
+
102
+ ### Color Module
103
+
104
+ The color module works as the base for any possible color format, implementing common methods
105
+
106
+ ```ruby
107
+ red.to_html
108
+ # '#ff0000'
109
+
110
+ red.into(Pigment::HSL)
111
+ # HSL Color(hue: 0.0, saturation: 1.0, lightness: 0.5, alpha: 1.0)
112
+
113
+ red.inverse?(cyan)
114
+ # true
115
+
116
+ red.triadic_of?(blue)
117
+ # true
118
+
119
+ red.triadic_include?(green, blue)
120
+ # true
121
+
122
+ red.split_of?
123
+ red.split_include?
124
+ red.analogous_of?
125
+ red.analogous_include?
126
+ red.tetradic_of?
127
+ red.tetradic_include?
128
+ red.rectangular_of?
129
+ red.rectangular_include?
130
+ red.tertiary_of?
131
+ red.tertiary_include?
132
+ # of -> checks if self is included in argument result
133
+ # include -> checks if arguments are included in self result
134
+ ```
135
+
136
+ ### Color Palette
137
+
138
+ ```ruby
139
+ require 'pigment/palette'
140
+
141
+ pallete = Pigment::Palette.new(
142
+ red: red,
143
+ blue: blue,
144
+ )
145
+
146
+ pallete[:red]
147
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
148
+
149
+ pallete[:green] = green
150
+ # RGB Color(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0)
151
+
152
+ # Pigment::Palette is enumerable
153
+
154
+ palette.map.to_a
155
+ # [RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0), RGB Color(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0), RGB Color(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0)]
156
+ ```
157
+
158
+ ### Default Color Palette
159
+
160
+ ```ruby
161
+ require 'pigment/default_rgb_palette'
162
+
163
+ Pigment::Palette::RGB::DEFAULT[:Red]
164
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
165
+
166
+
167
+ Pigment::Palette::RGB::Green
168
+ # RGB Color(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0)
169
+
170
+ Pigment::Palette::RGB.Blue
171
+ # RGB Color(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
172
+ ```
173
+
174
+ ## Changes
175
+ See [Changelog](CHANGELOG.md)
176
+
177
+
178
+ ## Future Work
179
+ - [ ] new color formats:
180
+ - [ ] Y'CbCr
181
+ - [ ] RYB
182
+ - [ ] CMYK
183
+ - [ ] redesign of Base Color module to support Additive color formats
184
+ - [ ] Palette Loader to load palette files
185
+
186
+ ## License
187
+ See [License](LICENSE.md)
188
+
189
+ ## Related interests
190
+ - [color-names](https://github.com/meodai/color-names): javascript collection of 25586 color names
@@ -1,309 +1,3 @@
1
- module Pigment
2
- VERSION = '0.1.10'
3
-
4
- class Color
5
-
6
- @named_colors = {}
7
- attr_reader :color, :hsl
8
-
9
- # Pigment uses sRGB or sRGBA as the default color system
10
- # color can be a hexadecimal code preceded by a '#' like '#FF4CB2' or a array of floats (1.0, 0.3, 0.7)
11
- # or an array of integers between 0 and 255 (153, 255, 31)
12
- # @param [String, Array] color
13
- def initialize(*color)
14
- @color = case
15
- when color[0] =~ /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})?$/
16
- [$1, $2, $3, $4 || 'ff'].map { |v| v.to_i(16) / 255.0 }
17
- when color.is_a?(Array) && (color.all? { |c| (0.0..1.0).include? c }) && color.length == 3
18
- [color, 1.0].flatten!
19
- when color.is_a?(Array) && (color.all? { |c| (0..255).include? c && c.is_a?(Integer) } ) && color.length == 3
20
- [color.map { |c| c / 255.0 }, 1.0].flatten!
21
- when color.is_a?(Array) && (color.all? { |c| (0.0..1.0).include? c }) && color.length == 4
22
- color
23
- when color.is_a?(Array) && (color.all? { |c| (0..255).include? c && c.is_a?(Integer) } ) && color.length == 4
24
- color.map { |c| c / 255.0 }
25
- else
26
- raise ArgumentError, "Expected String or Array with length 3 or 4. Given #{color.class} with length = #{color.length}"
27
- end
28
- end
29
-
30
- # Selectors.
31
- %w'r g b a'.each_with_index do |m, i|
32
- define_method("#{m}", ->() { color[i] })
33
- end
34
-
35
- %w'h s l'.each_with_index do |m, i|
36
- define_method("#{m}", ->() { hsl[i] })
37
- end
38
-
39
- # Set alpha value. Only accepts float values
40
- # @param [Float] alpha
41
- def a=(alpha)
42
- @color[3] = alpha if alpha.is_a?(Float) && (0.0..1.0).include?(alpha)
43
- end
44
-
45
- # Returns an array with the rgb components
46
- # @return [Array]
47
- def rgb
48
- @color[0, 3]
49
- end
50
-
51
- def hsl
52
- to_hsl unless @hsl
53
- @hsl
54
- end
55
-
56
- # Return specified color by its name from the named_colors hash.
57
- # @param [Symbol] name
58
- # @return [Color]
59
- def self.[](name)
60
- @named_colors[name]
61
- end
62
-
63
- # Add name to a color , add it to the named_colors hash and defines a constant.
64
- # @param [Array of Strings] names
65
- # @param [Color] color
66
- def self.[]=(*names, color)
67
- color = new(color) unless color.is_a? Color
68
- names.each do |name|
69
- @named_colors[name.downcase] = color
70
- const_set("#{name}".to_sym, color)
71
- end
72
- end
73
-
74
- # Return all the named_colors as an array.
75
- def self.named_colors
76
- @named_colors.keys
77
- end
78
-
79
- # Return all the named_colors as a sorted array.
80
- def self.named_colors_sorted
81
- named_colors.sort
82
- end
83
-
84
-
85
- # Suppress an array of floats by dividing by the greatest color component.
86
- # @param [Array] color
87
- # @return [Array]
88
- def self.suppress(color)
89
- color.map! { |c| c / color.max } unless (0.0..1.0).include?(color.max)
90
- color
91
- end
92
-
93
- # Creates a Color form the HSL color System. It's mostly used to calculate harmonic colors.
94
- # @param [Float] h
95
- # @param [Float] s
96
- # @param [Float] l
97
- # @return [Color]
98
- def self.from_hsl(h, s, l)
99
- return new(l, l, l) if s == 0
100
- v2 = l < 0.5 ? l * (1 + s) : (l + s) - (s * l)
101
- v1 = 2 * l - v2
102
- color = [h + (1 / 3.0), h, h - (1 / 3.0)].map do |hv|
103
- case
104
- when hv < 0 then hv += 1
105
- when hv > 1 then hv -= 1
106
- when 6 * hv < 1 then v1 +(v2 - v1) * 6 * hv
107
- when 2 * hv < 1 then v2
108
- when 3 * hv < 2 then v1 + (v2 - v1) * ((2 / 3.0)- hv) * 6
109
- else v1
110
- end
111
- end
112
- new(*color)
113
- end
114
-
115
- # Same as inverse.
116
- def -@
117
- inv
118
- end
119
-
120
- # Sums all the two colors components. If any component gets out of the 0 to 1.0 range its suppressed.
121
- # @param [Numeric] color
122
- # @return [Color]
123
- def +(color)
124
- case color
125
- when Color
126
- self.class.new(*self.class.suppress([color.rgb, rgb].transpose.map! { |c, d| c + d }))
127
- else
128
- raise ArgumentError, "Expecting Color. Given #{color.class}"
129
- end
130
- end
131
-
132
- # Subtracts all the two color components. If any component gets out of the 0 to 1.0 range its suppressed.
133
- # If tone component gets lower than 0 it acts like its dealing with the inverse component -> 1 - component
134
- # @param [Numeric] color
135
- # @return [Color]
136
- def -(color)
137
- case color
138
- when Color
139
- self.class.new(*self.class.suppress([rgb, color.rgb].transpose.map! do |c, d|
140
- e = c - d
141
- e >= 0 ? e : e = 1 + e
142
- e
143
- end))
144
- else
145
- raise ArgumentError, "Expecting color. Given #{color.class}"
146
- end
147
- end
148
-
149
- # Multiplies all the color components by n. If any component gets out of the 0 to 1.0 range its suppressed.
150
- # @param [Numeric] n
151
- # @return [Color]
152
- def *(n)
153
- case n
154
- when Numeric
155
- n = rgb.map { |c| c * n.to_f }
156
- self.class.new(*self.class.suppress(n))
157
- else
158
- raise ArgumentError, "Expecting Numeric. Given #{n.class}"
159
- end
160
- end
161
-
162
- # Divides all the color components by n. If any component gets out of the 0 to 1.0 range its suppressed.
163
- # @param [Numeric] n
164
- # @return [Color]
165
- def /(n)
166
- case n
167
- when Numeric
168
- n = rgb.map { |c| c * n.to_f }
169
- self.class.new(*self.class.suppress(n))
170
- else
171
- raise ArgumentError, "Expecting Numeric. Given #{n.class}"
172
- end
173
- end
174
-
175
- # Test if two colors are equal
176
- # @param [Color] color
177
- # @return [Boolean]
178
- def ==(color)
179
- color.is_a?(Color) && color.rgb == rgb
180
- end
181
-
182
- # Converts a color to its grayscale correspondent
183
- # @return [Color]
184
- def grayscale
185
- r = g = b = (self.r + self.g + self.b)/3
186
- self.class.new(r, g, b)
187
- end
188
-
189
- # Calculates the harmonic colors. Type can be :triadic, :split, :analogous, :complement or :complementary
190
- # @param [Symbol] type
191
- # @return [Color, Array of Colors]
192
- def harmonize(type = :triadic)
193
- color.to_hsl unless @hsl
194
- case type
195
- when :triadic
196
- [self.class.from_hsl(h - 5 / 12.0, s, l), self.class.from_hsl(h + 1 / 3.0, s, l)]
197
- when :split
198
- [self.class.from_hsl(h - 5 / 12.0, s, l), self.class.from_hsl(h + 5 / 12.0, s, l)]
199
- when :analogous
200
- [self.class.from_hsl(h - 1 / 12.0, s, l), self.class.from_hsl(h + 1 / 12.0, s, l)]
201
- when :complement, :complementary
202
- inv
203
- else
204
- raise ArgumentError, "Expected :triadic, :split, :analogous, :complement or :complementary. Given #{type}"
205
- end
206
- end
207
-
208
- # Interpolates two colors. Amount must be an float between -1.0 and 1.0
209
- # @param [Color] color
210
- # @param [Float] amount
211
- def interpolate(color, amount = 0.5)
212
- if color.is_a? Color && (-1.0..1.0).include?(amount)
213
- n = [rgb, color.rgb].transpose.map! { |c, d| c + amount * (d - c) }
214
- self.class.new(*self.class.suppress(n))
215
- else
216
- raise ArgumentError
217
- end
218
- end
219
-
220
- # Returns the Invert color
221
- # @return [Color]
222
- def inverse
223
- self.class.new(*rgb.map { |c| 1.0 - c })
224
- end
225
-
226
- # Returns a new Color without the given channels
227
- # @param [Array of Symbols] channels
228
- # @return [Color]
229
- def remove_channels(*channels)
230
- r = 0 if channels.include? :r
231
- g = 0 if channels.include? :g
232
- b = 0 if channels.include? :b
233
- self.class.new(r, g, b)
234
- end
235
-
236
- # Creates an instance variable to keep the HSL values of a RGB color.
237
- # @return [Array]
238
- def to_hsl
239
- min = rgb.min
240
- max = rgb.max
241
- delta = (max - min)
242
- l = (max + min) / 2.0
243
-
244
- s = if delta == 0.0 # close to 0.0, so it's a grey
245
- h = 0
246
- 0
247
- elsif l < 0.5
248
- delta / (max + min)
249
- else
250
- delta / (2.0 - max - min)
251
- end
252
-
253
- h = if r == max
254
- h = ((g - b) / delta) / 6.0
255
- h += 1.0 if g < b
256
- h
257
- elsif g == max
258
- ((b - r) / delta) / 6.0 + (1.0 / 3.0)
259
- elsif b == max
260
- ((r - g) / delta) / 6.0 + (2.0 / 3.0)
261
- end
262
-
263
- h += 1 if h < 0
264
- h -= 1 if h > 1
265
- @hsl = [h, s, l]
266
- self
267
- end
268
-
269
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
270
- # @param [Boolean] with_alpha
271
- # @return [Array]
272
- def to_floats(with_alpha = false)
273
- with_alpha ? @color.dup : rgb
274
- end
275
-
276
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
277
- # @param [Boolean] with_alpha
278
- # @return [Array]
279
- def to_ints(with_alpha = false)
280
- to_floats(with_alpha).map { |v| Integer(v * 255) }
281
- end
282
-
283
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
284
- # @param [Boolean] with_alpha
285
- # @return [Array]
286
- def to_hex(with_alpha = false)
287
- to_ints(with_alpha).map { |v| '%02x' % v }.join
288
- end
289
-
290
- def to_s
291
- "Color(r=#{r}, g=#{g}, b=#{b}, a=#{a}#{", [h=#{h}, s=#{s}, l=#{l}]" if @hsl})"
292
- end
293
-
294
- alias_method :alpha=, :a=
295
- alias_method :inv, :inverse
296
- alias_method :invert, :inverse
297
- alias_method :complementary, :inverse
298
- alias_method :mix, :interpolate
299
- alias_method :red, :r
300
- alias_method :green, :g
301
- alias_method :blue, :b
302
- alias_method :alpha, :a
303
- alias_method :to_a, :to_floats
304
- alias_method :to_ary, :to_floats
305
- alias_method :to_f, :to_floats
306
- end
307
- end
308
-
309
- require_relative 'colors.rb'
1
+ require_relative 'pigment/version'
2
+ require_relative 'pigment/float_snap'
3
+ require_relative 'pigment/color/invalid_color_format_error'