pigment 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f65760dd782badba8e2142b5b44f801956ac611c
4
- data.tar.gz: 7558e44c1a8bc79bee4d4236bc86a6dedc31d0d8
2
+ SHA256:
3
+ metadata.gz: dda5e6ade89b5949326fcb411e9aa8d99065fa511d3baeebb08e1cfb6199e84e
4
+ data.tar.gz: '058d8b2c5e47edfe74d716688ab99e33b99b51c46773dd0600c43c4755010b2e'
5
5
  SHA512:
6
- metadata.gz: 257a7f79240c8875f5990861cb8d5c195ac32a26c05c2b78e49c4a532efe086cddcb206e2e8bc1fd86020c227dded6e0e6d8517950f0f81950c383e1ea84fc7e
7
- data.tar.gz: 3bdc92c1b0835aae32863cd37db8255cbcb3a2d462249645f87b542f48717adf225d668f3f8662738351764c90ecb280360a4fb0fce2c2d88b729c64ff97097f
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,29 +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`
10
16
 
11
- # License
17
+ ```ruby
18
+ require 'pigment/color/rgb'
12
19
 
13
- (The MIT License)
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)
14
22
 
15
- Copyright &copy; 2012 Pedro Miranda
23
+ red.to_a
24
+ # [1.0, 0.0, 0.0, 1.0]
16
25
 
17
- Permission is hereby granted, free of charge, to any person obtaining
18
- a copy of this software and associated documentation files (the
19
- 'Software'), to deal in the Software without restriction, including
20
- without limitation the rights to use, copy, modify, merge, publish,
21
- distribute, sublicense, and/or sell copies of the Software, and to
22
- permit persons to whom the Software is furnished to do so, subject to
23
- the following conditions:
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)
24
28
 
25
- The above copyright notice and this permission notice shall be
26
- included in all copies or substantial portions of the Software.
29
+ red + semitransparent_red
30
+ # RGB Color(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
27
31
 
28
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
29
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
32
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
33
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
34
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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,306 +1,3 @@
1
- module Pigment
2
- VERSION = '0.2.3'.freeze
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
- # Getters and Setters.
31
- %w'r g b a'.each_with_index do |m, i|
32
- define_method("#{m}", ->() { @color[i] })
33
- define_method("#{m}=", ->(value) { @color[i] = value if value.is_a?(Float) && (0.0..1.0).include?(value) })
34
- end
35
-
36
- %w'h s l'.each_with_index do |m, i|
37
- define_method("#{m}", ->() { hsl[i] })
38
- end
39
-
40
- def method_missing(method, *args)
41
- # Returns an array with the respective rgba components
42
- # @return [Array]
43
- super unless method =~ /(a|b|g|r)+/ && args.empty?
44
- method.size.times.map{ |i| send(method[i]) }
45
- end
46
-
47
- # Return specified color by its name from the named_colors hash.
48
- # @param [Symbol] name
49
- # @return [Array]
50
- def self.[](*colors)
51
- colors.size > 1 ? colors.map { |color| @named_colors[color] } : @named_colors[colors[0]]
52
- end
53
-
54
- # Add name to a color , add it to the named_colors hash and defines a constant.
55
- # @param [Array of Strings] names
56
- # @param [Color] color
57
- def self.[]=(*names, color)
58
- color = new(color) unless color.is_a? Color
59
- names.each do |name|
60
- @named_colors[name.downcase] = color
61
- const_set("#{name}".to_sym, color)
62
- end
63
- end
64
-
65
- # Return all the named_colors as an array.
66
- def self.named_colors
67
- @named_colors.keys
68
- end
69
-
70
- # Return all the named_colors as a sorted array.
71
- def self.named_colors_sorted
72
- named_colors.sort
73
- end
74
-
75
- # Suppress an array of floats by dividing by the greatest color component.
76
- # @param [Array] color
77
- # @return [Array]
78
- def self.suppress(color)
79
- color.map! { |c| c / color.max } unless (0.0..1.0).include?(color.max)
80
- color
81
- end
82
-
83
- # Creates a Color form the HSL color System. It's mostly used to calculate harmonic colors.
84
- # @param [Float] h
85
- # @param [Float] s
86
- # @param [Float] l
87
- # @return [Color]
88
- def self.from_hsl(h, s, l)
89
- return new(l, l, l) if s == 0
90
- v2 = l < 0.5 ? l * (1 + s) : (l + s) - (s * l)
91
- v1 = 2 * l - v2
92
- color = [h + (1 / 3.0), h, h - (1 / 3.0)].map do |hv|
93
- case
94
- when hv < 0 then hv += 1
95
- when hv > 1 then hv -= 1
96
- when 6 * hv < 1 then v1 +(v2 - v1) * 6 * hv
97
- when 2 * hv < 1 then v2
98
- when 3 * hv < 2 then v1 + (v2 - v1) * ((2 / 3.0)- hv) * 6
99
- else v1
100
- end
101
- end
102
- new(*color)
103
- end
104
-
105
- # Same as inverse.
106
- def -@
107
- inv
108
- end
109
-
110
- # Sums all the two colors components. If any component gets out of the 0 to 1.0 range its suppressed.
111
- # @param [Numeric] color
112
- # @return [Color]
113
- def +(color)
114
- case color
115
- when Color
116
- self.class.new(*self.class.suppress([color.rgb, rgb].transpose.map! { |c, d| c + d }))
117
- else
118
- raise ArgumentError, "Expecting Color. Given #{color.class}"
119
- end
120
- end
121
-
122
- # Subtracts all the two color components. If any component gets out of the 0 to 1.0 range its suppressed.
123
- # If tone component gets lower than 0 it acts like its dealing with the inverse component -> 1 - component
124
- # @param [Numeric] color
125
- # @return [Color]
126
- def -(color)
127
- case color
128
- when Color
129
- self.class.new(*self.class.suppress([rgb, color.rgb].transpose.map! do |c, d|
130
- e = c - d
131
- e >= 0 ? e : e = 1 + e
132
- e
133
- end))
134
- else
135
- raise ArgumentError, "Expecting color. Given #{color.class}"
136
- end
137
- end
138
-
139
- # Multiplies all the color components by n. If any component gets out of the 0 to 1.0 range its suppressed.
140
- # @param [Numeric] n
141
- # @return [Color]
142
- def *(n)
143
- case n
144
- when Numeric
145
- n = rgb.map { |c| c * n.to_f }
146
- self.class.new(*self.class.suppress(n))
147
- else
148
- raise ArgumentError, "Expecting Numeric. Given #{n.class}"
149
- end
150
- end
151
-
152
- # Divides all the color components by n. If any component gets out of the 0 to 1.0 range its suppressed.
153
- # @param [Numeric] n
154
- # @return [Color]
155
- def /(n)
156
- case n
157
- when Numeric
158
- n = rgb.map { |c| c * n.to_f }
159
- self.class.new(*self.class.suppress(n))
160
- else
161
- raise ArgumentError, "Expecting Numeric. Given #{n.class}"
162
- end
163
- end
164
-
165
- # Test if two colors are equal
166
- # @param [Color] color
167
- # @return [Boolean]
168
- def ==(color)
169
- color.is_a?(Color) && color.rgba == rgba
170
- end
171
-
172
- # @return [Color]
173
- def dup
174
- self.class.new(*@color)
175
- end
176
-
177
- # Converts a color to its grayscale correspondent
178
- # @return [Color]
179
- def grayscale
180
- r = g = b = (self.r + self.g + self.b)/3
181
- self.class.new(r, g, b)
182
- end
183
-
184
- # Calculates the harmonic colors. Type can be :triadic, :split, :analogous, :complement or :complementary
185
- # @param [Symbol] type
186
- # @return [Color, Array of Colors]
187
- def harmonize(type = :triadic)
188
- color.to_hsl unless @hsl
189
- case type
190
- when :triadic
191
- [self.class.from_hsl(h - 5 / 12.0, s, l), self.class.from_hsl(h + 1 / 3.0, s, l)]
192
- when :split
193
- [self.class.from_hsl(h - 5 / 12.0, s, l), self.class.from_hsl(h + 5 / 12.0, s, l)]
194
- when :analogous
195
- [self.class.from_hsl(h - 1 / 12.0, s, l), self.class.from_hsl(h + 1 / 12.0, s, l)]
196
- when :complement, :complementary
197
- inv
198
- else
199
- raise ArgumentError, "Expected :triadic, :split, :analogous, :complement or :complementary. Given #{type}"
200
- end
201
- end
202
-
203
- # Interpolates two colors. Amount must be an float between -1.0 and 1.0
204
- # @param [Color] color
205
- # @param [Float] amount
206
- def interpolate(color, amount = 0.5)
207
- if color.is_a?(Color) && (-1.0..1.0).include?(amount)
208
- n = [rgb, color.rgb].transpose.map! { |c, d| c + amount * (d - c) }
209
- self.class.new(*self.class.suppress(n))
210
- else
211
- raise ArgumentError
212
- end
213
- end
214
-
215
- # Returns the Invert color
216
- # @return [Color]
217
- def inverse
218
- self.class.new(*rgb.map { |c| 1.0 - c })
219
- end
220
-
221
- # Returns a new Color without the given channels
222
- # @param [Array of Symbols] channels
223
- # @return [Color]
224
- def remove_channels(*channels)
225
- color = self.class.new(r, g, b, a)
226
- %w'r g b a'.each do |attr|
227
- color.send("#{attr}=", 0) if channels.include? attr.to_sym
228
- end
229
- color
230
- end
231
-
232
- # Creates an instance variable to keep the HSL values of a RGB color.
233
- # @return [Array]
234
- def to_hsl
235
- min = rgb.min
236
- max = rgb.max
237
- delta = (max - min)
238
- l = (max + min) / 2.0
239
-
240
- s = if delta == 0.0 # close to 0.0, so it's a grey
241
- h = 0
242
- 0
243
- elsif l < 0.5
244
- delta / (max + min)
245
- else
246
- delta / (2.0 - max - min)
247
- end
248
-
249
- h = if r == max
250
- h = ((g - b) / delta) / 6.0
251
- h += 1.0 if g < b
252
- h
253
- elsif g == max
254
- ((b - r) / delta) / 6.0 + (1.0 / 3.0)
255
- elsif b == max
256
- ((r - g) / delta) / 6.0 + (2.0 / 3.0)
257
- end
258
-
259
- h += 1 if h < 0
260
- h -= 1 if h > 1
261
- @hsl = [h, s, l]
262
- self
263
- end
264
-
265
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
266
- # @param [Boolean] with_alpha
267
- # @return [Array]
268
- def to_floats(with_alpha = true)
269
- with_alpha ? @color.dup : rgb
270
- end
271
-
272
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
273
- # @param [Boolean] with_alpha
274
- # @return [Array]
275
- def to_ints(with_alpha = true)
276
- to_floats(with_alpha).map { |v| Integer(v * 255) }
277
- end
278
-
279
- # Returns an array of the color components. Alpha value is passed as well if with_alpha is set to true.
280
- # @param [Boolean] with_alpha
281
- # @return [Array]
282
- def to_hex(with_alpha = true)
283
- to_ints(with_alpha).map { |v| '%02x' % v }.join
284
- end
285
-
286
- def to_s
287
- "Color(r=#{r}, g=#{g}, b=#{b}, a=#{a}#{", [h=#{h}, s=#{s}, l=#{l}]" if @hsl})"
288
- end
289
-
290
- alias_method :alpha=, :a=
291
- alias_method :inv, :inverse
292
- alias_method :invert, :inverse
293
- alias_method :complementary, :inverse
294
- alias_method :mix, :interpolate
295
- alias_method :red, :r
296
- alias_method :green, :g
297
- alias_method :blue, :b
298
- alias_method :alpha, :a
299
- alias_method :to_a, :to_floats
300
- alias_method :to_ary, :to_floats
301
- alias_method :to_f, :to_floats
302
- alias_method :to_hsl, :hsl
303
- end
304
- end
305
-
306
- require_relative 'colors.rb'
1
+ require_relative 'pigment/version'
2
+ require_relative 'pigment/float_snap'
3
+ require_relative 'pigment/color/invalid_color_format_error'