pigment 0.2.3 → 0.3.0

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 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'